16
16
17
17
static void check_new_cluster_is_empty (void );
18
18
static void check_databases_are_compatible (void );
19
+ static void check_for_changed_signatures (void );
19
20
static void check_locale_and_encoding (DbInfo * olddb , DbInfo * newdb );
20
21
static bool equivalent_locale (int category , const char * loca , const char * locb );
21
22
static void check_is_install_user (ClusterInfo * cluster );
@@ -142,6 +143,8 @@ check_and_dump_old_cluster(bool live_check)
142
143
if (GET_MAJOR_VERSION (old_cluster .major_version ) <= 804 )
143
144
new_9_0_populate_pg_largeobject_metadata (& old_cluster , true);
144
145
146
+ get_non_default_acl_infos (& old_cluster );
147
+
145
148
/*
146
149
* While not a check option, we do this now because this is the only time
147
150
* the old server is running.
@@ -161,6 +164,7 @@ check_new_cluster(void)
161
164
162
165
check_new_cluster_is_empty ();
163
166
check_databases_are_compatible ();
167
+ check_for_changed_signatures ();
164
168
165
169
check_loadable_libraries ();
166
170
@@ -443,6 +447,223 @@ check_databases_are_compatible(void)
443
447
}
444
448
}
445
449
450
+ /*
451
+ * Find the location of the last dot, return NULL if not found.
452
+ */
453
+ static char *
454
+ last_dot_location (const char * identity )
455
+ {
456
+ const char * p ,
457
+ * ret = NULL ;
458
+
459
+ for (p = identity ; * p ; p ++ )
460
+ if (* p == '.' )
461
+ ret = p ;
462
+ return unconstify (char * , ret );
463
+ }
464
+
465
+ /*
466
+ * check_for_changed_signatures()
467
+ *
468
+ * Check that the old cluster doesn't have non-default ACL's for system objects
469
+ * (relations, attributes, functions and procedures) which have different
470
+ * signatures in the new cluster. Otherwise generate revoke_objects.sql.
471
+ */
472
+ static void
473
+ check_for_changed_signatures (void )
474
+ {
475
+ PGconn * conn ;
476
+ char subquery [QUERY_ALLOC ];
477
+ PGresult * res ;
478
+ int ntups ;
479
+ int i_obj_ident ;
480
+ int dbnum ;
481
+ bool need_check = false;
482
+ FILE * script = NULL ;
483
+ bool found_changed = false;
484
+ char output_path [MAXPGPATH ];
485
+
486
+ prep_status ("Checking for system objects with non-default ACL" );
487
+
488
+ for (dbnum = 0 ; dbnum < old_cluster .dbarr .ndbs ; dbnum ++ )
489
+ if (old_cluster .dbarr .dbs [dbnum ].non_def_acl_arr .nacls > 0 )
490
+ {
491
+ need_check = true;
492
+ break ;
493
+ }
494
+ /*
495
+ * The old cluster doesn't have system objects with non-default ACL so
496
+ * quickly exit.
497
+ */
498
+ if (!need_check )
499
+ {
500
+ check_ok ();
501
+ return ;
502
+ }
503
+
504
+ snprintf (output_path , sizeof (output_path ), "revoke_objects.sql" );
505
+
506
+ snprintf (subquery , sizeof (subquery ),
507
+ /* Get system relations which created in pg_catalog */
508
+ "SELECT 'pg_class'::regclass classid, oid objid, 0 objsubid "
509
+ "FROM pg_catalog.pg_class "
510
+ "WHERE relnamespace = 'pg_catalog'::regnamespace "
511
+ "UNION ALL "
512
+ /* Get system relations attributes which created in pg_catalog */
513
+ "SELECT 'pg_class'::regclass, att.attrelid, att.attnum "
514
+ "FROM pg_catalog.pg_class rel "
515
+ "INNER JOIN pg_catalog.pg_attribute att ON rel.oid = att.attrelid "
516
+ "WHERE rel.relnamespace = 'pg_catalog'::regnamespace "
517
+ "UNION ALL "
518
+ /* Get system functions and procedure which created in pg_catalog */
519
+ "SELECT 'pg_proc'::regclass, oid, 0 "
520
+ "FROM pg_catalog.pg_proc "
521
+ "WHERE pronamespace = 'pg_catalog'::regnamespace " );
522
+
523
+ conn = connectToServer (& new_cluster , "template1" );
524
+ res = executeQueryOrDie (conn ,
525
+ "SELECT ident.type, ident.identity "
526
+ "FROM (%s) obj, "
527
+ "LATERAL pg_catalog.pg_identify_object("
528
+ " obj.classid, obj.objid, obj.objsubid) ident "
529
+ /*
530
+ * Don't rely on database collation, since we use strcmp
531
+ * comparison to find non-default ACLs.
532
+ */
533
+ "ORDER BY ident.identity COLLATE \"C\";" , subquery );
534
+ ntups = PQntuples (res );
535
+
536
+ i_obj_ident = PQfnumber (res , "identity" );
537
+
538
+ for (dbnum = 0 ; dbnum < old_cluster .dbarr .ndbs ; dbnum ++ )
539
+ {
540
+ DbInfo * dbinfo = & old_cluster .dbarr .dbs [dbnum ];
541
+ bool db_used = false;
542
+ int aclnum = 0 ,
543
+ objnum = 0 ;
544
+
545
+ /*
546
+ * For every database check system objects with non-default ACL.
547
+ *
548
+ * AclInfo array is sorted by obj_ident. This allows us to compare
549
+ * AclInfo entries with the query result above efficiently.
550
+ */
551
+ for (aclnum = 0 ; aclnum < dbinfo -> non_def_acl_arr .nacls ; aclnum ++ )
552
+ {
553
+ AclInfo * aclinfo = & dbinfo -> non_def_acl_arr .aclinfos [aclnum ];
554
+ bool report = false;
555
+
556
+ while (objnum < ntups )
557
+ {
558
+ int ret ;
559
+
560
+ ret = strcmp (aclinfo -> obj_ident ,
561
+ PQgetvalue (res , objnum , i_obj_ident ));
562
+
563
+ /*
564
+ * The new cluster doesn't have an object with same identity,
565
+ * exit the loop, report below and check next object.
566
+ */
567
+ if (ret < 0 )
568
+ {
569
+ report = true;
570
+ break ;
571
+ }
572
+ /*
573
+ * The new cluster has an object with same identity, just exit
574
+ * the loop.
575
+ */
576
+ else if (ret == 0 )
577
+ {
578
+ objnum ++ ;
579
+ break ;
580
+ }
581
+ else
582
+ objnum ++ ;
583
+ }
584
+
585
+ if (report )
586
+ {
587
+ found_changed = true;
588
+ if (script == NULL && (script = fopen_priv (output_path , "w" )) == NULL )
589
+ pg_fatal ("could not open file \"%s\": %s\n" ,
590
+ output_path , strerror (errno ));
591
+ if (!db_used )
592
+ {
593
+ PQExpBufferData conn_buf ;
594
+
595
+ initPQExpBuffer (& conn_buf );
596
+ appendPsqlMetaConnect (& conn_buf , dbinfo -> db_name );
597
+ fputs (conn_buf .data , script );
598
+ termPQExpBuffer (& conn_buf );
599
+
600
+ db_used = true;
601
+ }
602
+
603
+ /* Handle columns separately */
604
+ if (strstr (aclinfo -> obj_type , "column" ) != NULL )
605
+ {
606
+ char * pdot = last_dot_location (aclinfo -> obj_ident );
607
+ PQExpBufferData ident_buf ;
608
+
609
+ if (pdot == NULL || * (pdot + 1 ) == '\0' )
610
+ pg_fatal ("invalid column identity \"%s\"" ,
611
+ aclinfo -> obj_ident );
612
+
613
+ initPQExpBuffer (& ident_buf );
614
+ appendBinaryPQExpBuffer (& ident_buf , aclinfo -> obj_ident ,
615
+ pdot - aclinfo -> obj_ident );
616
+
617
+ fprintf (script , "REVOKE ALL (%s) ON %s FROM %s;\n" ,
618
+ /* pg_identify_object() quotes identity if necessary */
619
+ pdot + 1 , ident_buf .data ,
620
+ /* role_names is already quoted */
621
+ aclinfo -> role_names );
622
+ termPQExpBuffer (& ident_buf );
623
+ }
624
+ /*
625
+ * For relations except sequences we don't need to specify
626
+ * the object type.
627
+ */
628
+ else if (aclinfo -> is_relation &&
629
+ strcmp (aclinfo -> obj_type , "sequence" ) != 0 )
630
+ fprintf (script , "REVOKE ALL ON %s FROM %s;\n" ,
631
+ /* pg_identify_object() quotes identity if necessary */
632
+ aclinfo -> obj_ident ,
633
+ /* role_names is already quoted */
634
+ aclinfo -> role_names );
635
+ /* Other object types */
636
+ else
637
+ fprintf (script , "REVOKE ALL ON %s %s FROM %s;\n" ,
638
+ aclinfo -> obj_type ,
639
+ /* pg_identify_object() quotes identity if necessary */
640
+ aclinfo -> obj_ident ,
641
+ /* role_names is already quoted */
642
+ aclinfo -> role_names );
643
+ }
644
+ }
645
+ }
646
+
647
+ PQclear (res );
648
+ PQfinish (conn );
649
+
650
+ if (script )
651
+ fclose (script );
652
+
653
+ if (found_changed )
654
+ {
655
+ pg_log (PG_REPORT , "fatal\n" );
656
+ pg_fatal ("Your installation contains non-default privileges for system objects\n"
657
+ "for which the API has changed. To perform the upgrade, reset these\n"
658
+ "privileges to default. The file\n"
659
+ " %s\n"
660
+ "when executed by psql will revoke non-default privileges for those objects.\n\n" ,
661
+ output_path );
662
+ }
663
+ else
664
+ check_ok ();
665
+ }
666
+
446
667
447
668
/*
448
669
* create_script_for_cluster_analyze()
0 commit comments