Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit df5d9bb

Browse files
committed
Allow pg_dump to dump non-extension members of an extension-owned schema.
Previously, if a schema was created by an extension, a normal pg_dump run (not --binary-upgrade) would summarily skip every object in that schema. In a case where an extension creates a schema and then users create other objects within that schema, this does the wrong thing: we want pg_dump to skip the schema but still create the non-extension-owned objects. There's no easy way to fix this pre-9.6, because in earlier versions the "dump" status for a schema is just a bool and there's no way to distinguish "dump me" from "dump my members". However, as of 9.6 we do have enough state to represent that, so this is a simple correction of the logic in selectDumpableNamespace. In passing, make some cosmetic fixes in nearby code. Martín Marqués, reviewed by Michael Paquier Discussion: <99581032-71de-6466-c325-069861f1947d@2ndquadrant.com>
1 parent e97e9c5 commit df5d9bb

File tree

3 files changed

+247
-11
lines changed

3 files changed

+247
-11
lines changed

src/bin/pg_dump/pg_dump.c

+18-10
Original file line numberDiff line numberDiff line change
@@ -1302,7 +1302,7 @@ checkExtensionMembership(DumpableObject *dobj, Archive *fout)
13021302

13031303
/*
13041304
* In 9.6 and above, mark the member object to have any non-initial ACL,
1305-
* policies, and security lables dumped.
1305+
* policies, and security labels dumped.
13061306
*
13071307
* Note that any initial ACLs (see pg_init_privs) will be removed when we
13081308
* extract the information about the object. We don't provide support for
@@ -1324,8 +1324,8 @@ checkExtensionMembership(DumpableObject *dobj, Archive *fout)
13241324
dobj->dump = DUMP_COMPONENT_NONE;
13251325
else
13261326
dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL |
1327-
DUMP_COMPONENT_SECLABEL | DUMP_COMPONENT_POLICY);
1328-
1327+
DUMP_COMPONENT_SECLABEL |
1328+
DUMP_COMPONENT_POLICY);
13291329
}
13301330

13311331
return true;
@@ -1338,15 +1338,11 @@ checkExtensionMembership(DumpableObject *dobj, Archive *fout)
13381338
static void
13391339
selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
13401340
{
1341-
if (checkExtensionMembership(&nsinfo->dobj, fout))
1342-
return; /* extension membership overrides all else */
1343-
13441341
/*
13451342
* If specific tables are being dumped, do not dump any complete
13461343
* namespaces. If specific namespaces are being dumped, dump just those
13471344
* namespaces. Otherwise, dump all non-system namespaces.
13481345
*/
1349-
13501346
if (table_include_oids.head != NULL)
13511347
nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
13521348
else if (schema_include_oids.head != NULL)
@@ -1355,18 +1351,21 @@ selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
13551351
nsinfo->dobj.catId.oid) ?
13561352
DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
13571353
else if (fout->remoteVersion >= 90600 &&
1358-
strncmp(nsinfo->dobj.name, "pg_catalog",
1359-
strlen("pg_catalog")) == 0)
1360-
1354+
strcmp(nsinfo->dobj.name, "pg_catalog") == 0)
1355+
{
13611356
/*
13621357
* In 9.6 and above, we dump out any ACLs defined in pg_catalog, if
13631358
* they are interesting (and not the original ACLs which were set at
13641359
* initdb time, see pg_init_privs).
13651360
*/
13661361
nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
1362+
}
13671363
else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
13681364
strcmp(nsinfo->dobj.name, "information_schema") == 0)
1365+
{
1366+
/* Other system schemas don't get dumped */
13691367
nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1368+
}
13701369
else
13711370
nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
13721371

@@ -1377,6 +1376,15 @@ selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
13771376
simple_oid_list_member(&schema_exclude_oids,
13781377
nsinfo->dobj.catId.oid))
13791378
nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1379+
1380+
/*
1381+
* If the schema belongs to an extension, allow extension membership to
1382+
* override the dump decision for the schema itself. However, this does
1383+
* not change dump_contains, so this won't change what we do with objects
1384+
* within the schema. (If they belong to the extension, they'll get
1385+
* suppressed by it, otherwise not.)
1386+
*/
1387+
(void) checkExtensionMembership(&nsinfo->dobj, fout);
13801388
}
13811389

13821390
/*

src/test/modules/test_pg_dump/t/001_base.pl

+205-1
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,211 @@
429429
unlike => {
430430
no_privs => 1,
431431
pg_dumpall_globals => 1,
432-
section_post_data => 1, }, },);
432+
section_post_data => 1, }, },
433+
# Objects included in extension part of a schema created by this extension */
434+
'CREATE TABLE regress_pg_dump_schema.test_table' => {
435+
regexp => qr/^
436+
\QCREATE TABLE test_table (\E
437+
\n\s+\Qcol1 integer,\E
438+
\n\s+\Qcol2 integer\E
439+
\n\);$/xm,
440+
like => { binary_upgrade => 1, },
441+
unlike => {
442+
clean => 1,
443+
clean_if_exists => 1,
444+
createdb => 1,
445+
defaults => 1,
446+
no_privs => 1,
447+
no_owner => 1,
448+
pg_dumpall_globals => 1,
449+
schema_only => 1,
450+
section_pre_data => 1,
451+
section_post_data => 1, }, },
452+
'GRANT SELECT ON regress_pg_dump_schema.test_table' => {
453+
regexp => qr/^
454+
\QSELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\E\n
455+
\QGRANT SELECT ON TABLE test_table TO regress_dump_test_role;\E\n
456+
\QSELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\E
457+
$/xms,
458+
like => { binary_upgrade => 1, },
459+
unlike => {
460+
clean => 1,
461+
clean_if_exists => 1,
462+
createdb => 1,
463+
defaults => 1,
464+
no_owner => 1,
465+
no_privs => 1,
466+
pg_dumpall_globals => 1,
467+
schema_only => 1,
468+
section_pre_data => 1,
469+
section_post_data => 1, }, },
470+
'CREATE SEQUENCE regress_pg_dump_schema.test_seq' => {
471+
regexp => qr/^
472+
\QCREATE SEQUENCE test_seq\E
473+
\n\s+\QSTART WITH 1\E
474+
\n\s+\QINCREMENT BY 1\E
475+
\n\s+\QNO MINVALUE\E
476+
\n\s+\QNO MAXVALUE\E
477+
\n\s+\QCACHE 1;\E
478+
$/xm,
479+
like => { binary_upgrade => 1, },
480+
unlike => {
481+
clean => 1,
482+
clean_if_exists => 1,
483+
createdb => 1,
484+
defaults => 1,
485+
no_privs => 1,
486+
no_owner => 1,
487+
pg_dumpall_globals => 1,
488+
schema_only => 1,
489+
section_pre_data => 1,
490+
section_post_data => 1, }, },
491+
'GRANT USAGE ON regress_pg_dump_schema.test_seq' => {
492+
regexp => qr/^
493+
\QSELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\E\n
494+
\QGRANT USAGE ON SEQUENCE test_seq TO regress_dump_test_role;\E\n
495+
\QSELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\E
496+
$/xms,
497+
like => { binary_upgrade => 1, },
498+
unlike => {
499+
clean => 1,
500+
clean_if_exists => 1,
501+
createdb => 1,
502+
defaults => 1,
503+
no_owner => 1,
504+
no_privs => 1,
505+
pg_dumpall_globals => 1,
506+
schema_only => 1,
507+
section_pre_data => 1,
508+
section_post_data => 1, }, },
509+
'CREATE TYPE regress_pg_dump_schema.test_type' => {
510+
regexp => qr/^
511+
\QCREATE TYPE test_type AS (\E
512+
\n\s+\Qcol1 integer\E
513+
\n\);$/xm,
514+
like => { binary_upgrade => 1, },
515+
unlike => {
516+
clean => 1,
517+
clean_if_exists => 1,
518+
createdb => 1,
519+
defaults => 1,
520+
no_privs => 1,
521+
no_owner => 1,
522+
pg_dumpall_globals => 1,
523+
schema_only => 1,
524+
section_pre_data => 1,
525+
section_post_data => 1, }, },
526+
'GRANT USAGE ON regress_pg_dump_schema.test_type' => {
527+
regexp => qr/^
528+
\QSELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\E\n
529+
\QGRANT ALL ON TYPE test_type TO regress_dump_test_role;\E\n
530+
\QSELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\E
531+
$/xms,
532+
like => { binary_upgrade => 1, },
533+
unlike => {
534+
clean => 1,
535+
clean_if_exists => 1,
536+
createdb => 1,
537+
defaults => 1,
538+
no_owner => 1,
539+
no_privs => 1,
540+
pg_dumpall_globals => 1,
541+
schema_only => 1,
542+
section_pre_data => 1,
543+
section_post_data => 1, }, },
544+
'CREATE FUNCTION regress_pg_dump_schema.test_func' => {
545+
regexp => qr/^
546+
\QCREATE FUNCTION test_func() RETURNS integer\E
547+
\n\s+\QLANGUAGE sql\E
548+
$/xm,
549+
like => { binary_upgrade => 1, },
550+
unlike => {
551+
clean => 1,
552+
clean_if_exists => 1,
553+
createdb => 1,
554+
defaults => 1,
555+
no_privs => 1,
556+
no_owner => 1,
557+
pg_dumpall_globals => 1,
558+
schema_only => 1,
559+
section_pre_data => 1,
560+
section_post_data => 1, }, },
561+
'GRANT ALL ON regress_pg_dump_schema.test_func' => {
562+
regexp => qr/^
563+
\QSELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\E\n
564+
\QGRANT ALL ON FUNCTION test_func() TO regress_dump_test_role;\E\n
565+
\QSELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\E
566+
$/xms,
567+
like => { binary_upgrade => 1, },
568+
unlike => {
569+
clean => 1,
570+
clean_if_exists => 1,
571+
createdb => 1,
572+
defaults => 1,
573+
no_owner => 1,
574+
no_privs => 1,
575+
pg_dumpall_globals => 1,
576+
schema_only => 1,
577+
section_pre_data => 1,
578+
section_post_data => 1, }, },
579+
'CREATE AGGREGATE regress_pg_dump_schema.test_agg' => {
580+
regexp => qr/^
581+
\QCREATE AGGREGATE test_agg(smallint) (\E
582+
\n\s+\QSFUNC = int2_sum,\E
583+
\n\s+\QSTYPE = bigint\E
584+
\n\);$/xm,
585+
like => { binary_upgrade => 1, },
586+
unlike => {
587+
clean => 1,
588+
clean_if_exists => 1,
589+
createdb => 1,
590+
defaults => 1,
591+
no_privs => 1,
592+
no_owner => 1,
593+
pg_dumpall_globals => 1,
594+
schema_only => 1,
595+
section_pre_data => 1,
596+
section_post_data => 1, }, },
597+
'GRANT ALL ON regress_pg_dump_schema.test_agg' => {
598+
regexp => qr/^
599+
\QSELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\E\n
600+
\QGRANT ALL ON FUNCTION test_agg(smallint) TO regress_dump_test_role;\E\n
601+
\QSELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\E
602+
$/xms,
603+
like => { binary_upgrade => 1, },
604+
unlike => {
605+
clean => 1,
606+
clean_if_exists => 1,
607+
createdb => 1,
608+
defaults => 1,
609+
no_owner => 1,
610+
no_privs => 1,
611+
pg_dumpall_globals => 1,
612+
schema_only => 1,
613+
section_pre_data => 1,
614+
section_post_data => 1, }, },
615+
# Objects not included in extension, part of schema created by extension
616+
'CREATE TABLE regress_pg_dump_schema.external_tab' => {
617+
create_order => 4,
618+
create_sql => 'CREATE TABLE regress_pg_dump_schema.external_tab
619+
(col1 int);',
620+
regexp => qr/^
621+
\QCREATE TABLE external_tab (\E
622+
\n\s+\Qcol1 integer\E
623+
\n\);$/xm,
624+
like => {
625+
binary_upgrade => 1,
626+
clean => 1,
627+
clean_if_exists => 1,
628+
createdb => 1,
629+
defaults => 1,
630+
no_owner => 1,
631+
no_privs => 1,
632+
schema_only => 1,
633+
section_pre_data => 1, },
634+
unlike => {
635+
pg_dumpall_globals => 1,
636+
section_post_data => 1, }, }, );
433637
434638
#########################################
435639
# Create a PG instance to test actually dumping from

src/test/modules/test_pg_dump/test_pg_dump--1.0.sql

+24
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ CREATE TABLE regress_pg_dump_table (
1010

1111
CREATE SEQUENCE regress_pg_dump_seq;
1212

13+
CREATE SCHEMA regress_pg_dump_schema;
14+
1315
GRANT USAGE ON regress_pg_dump_seq TO regress_dump_test_role;
1416

1517
GRANT SELECT ON regress_pg_dump_table TO regress_dump_test_role;
@@ -19,3 +21,25 @@ GRANT SELECT(col2) ON regress_pg_dump_table TO regress_dump_test_role;
1921
REVOKE SELECT(col2) ON regress_pg_dump_table FROM regress_dump_test_role;
2022

2123
CREATE ACCESS METHOD regress_test_am TYPE INDEX HANDLER bthandler;
24+
25+
-- Create a set of objects that are part of the schema created by
26+
-- this extension.
27+
CREATE TABLE regress_pg_dump_schema.test_table (
28+
col1 int,
29+
col2 int
30+
);
31+
GRANT SELECT ON regress_pg_dump_schema.test_table TO regress_dump_test_role;
32+
33+
CREATE SEQUENCE regress_pg_dump_schema.test_seq;
34+
GRANT USAGE ON regress_pg_dump_schema.test_seq TO regress_dump_test_role;
35+
36+
CREATE TYPE regress_pg_dump_schema.test_type AS (col1 int);
37+
GRANT USAGE ON TYPE regress_pg_dump_schema.test_type TO regress_dump_test_role;
38+
39+
CREATE FUNCTION regress_pg_dump_schema.test_func () RETURNS int
40+
AS 'SELECT 1;' LANGUAGE SQL;
41+
GRANT EXECUTE ON FUNCTION regress_pg_dump_schema.test_func() TO regress_dump_test_role;
42+
43+
CREATE AGGREGATE regress_pg_dump_schema.test_agg(int2)
44+
(SFUNC = int2_sum, STYPE = int8);
45+
GRANT EXECUTE ON FUNCTION regress_pg_dump_schema.test_agg(int2) TO regress_dump_test_role;

0 commit comments

Comments
 (0)