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

Commit 242d219

Browse files
tglsfdcpull[bot]
authored andcommitted
Fix logic buglets in pg_dump's flagInhAttrs().
As it stands, flagInhAttrs() can make changes in table properties that change decisions made at other tables during other iterations of its loop. This is a pretty bad idea, since we visit the tables in OID order which is not necessarily related to inheritance relationships. So far as I can tell, the consequences are just cosmetic: we might dump DEFAULT or GENERATED expressions that we don't really need to because they match properties of the parent. Nonetheless, it's buggy, and somebody might someday add functionality here that fails less benignly when the traversal order varies. One issue is that when we decide we needn't dump a particular GENERATED expression, we physically unlink the struct for it, so that it will now look like the table has no such expression, causing the wrong choice to be made at any child visited later. We can improve that by instead clearing the dobj.dump flag, and taking care to check that flag when it comes time to dump the expression or not. The other problem is that if we decide we need to fake up a DEFAULT NULL clause to override a default that would otherwise get inherited, we modify the data structure in the reverse fashion, creating an attrdefs entry where there hadn't been one. It's harder to avoid doing that, but since the backend won't report a plain "DEFAULT NULL" property we can modify the code to recognize ones we just added. Add some commentary to perhaps forestall future mistakes of the same ilk. Since the effects of this seem only cosmetic, no back-patch. Discussion: https://postgr.es/m/1506298.1676323579@sss.pgh.pa.us
1 parent 2220768 commit 242d219

File tree

2 files changed

+29
-10
lines changed

2 files changed

+29
-10
lines changed

src/bin/pg_dump/common.c

+23-6
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,13 @@ flagInhAttrs(DumpOptions *dopt, TableInfo *tblinfo, int numTables)
471471
j,
472472
k;
473473

474+
/*
475+
* We scan the tables in OID order, since that's how tblinfo[] is sorted.
476+
* Hence we will typically visit parents before their children --- but
477+
* that is *not* guaranteed. Thus this loop must be careful that it does
478+
* not alter table properties in a way that could change decisions made at
479+
* child tables during other iterations.
480+
*/
474481
for (i = 0; i < numTables; i++)
475482
{
476483
TableInfo *tbinfo = &(tblinfo[i]);
@@ -519,15 +526,18 @@ flagInhAttrs(DumpOptions *dopt, TableInfo *tblinfo, int numTables)
519526
parent->numatts);
520527
if (inhAttrInd >= 0)
521528
{
529+
AttrDefInfo *parentDef = parent->attrdefs[inhAttrInd];
530+
522531
foundNotNull |= parent->notnull[inhAttrInd];
523-
foundDefault |= (parent->attrdefs[inhAttrInd] != NULL &&
532+
foundDefault |= (parentDef != NULL &&
533+
strcmp(parentDef->adef_expr, "NULL") != 0 &&
524534
!parent->attgenerated[inhAttrInd]);
525535
if (parent->attgenerated[inhAttrInd])
526536
{
527537
/* these pointer nullness checks are just paranoia */
528-
if (parent->attrdefs[inhAttrInd] != NULL &&
538+
if (parentDef != NULL &&
529539
tbinfo->attrdefs[j] != NULL &&
530-
strcmp(parent->attrdefs[inhAttrInd]->adef_expr,
540+
strcmp(parentDef->adef_expr,
531541
tbinfo->attrdefs[j]->adef_expr) == 0)
532542
foundSameGenerated = true;
533543
else
@@ -539,7 +549,14 @@ flagInhAttrs(DumpOptions *dopt, TableInfo *tblinfo, int numTables)
539549
/* Remember if we found inherited NOT NULL */
540550
tbinfo->inhNotNull[j] = foundNotNull;
541551

542-
/* Manufacture a DEFAULT NULL clause if necessary */
552+
/*
553+
* Manufacture a DEFAULT NULL clause if necessary. This breaks
554+
* the advice given above to avoid changing state that might get
555+
* inspected in other loop iterations. We prevent trouble by
556+
* having the foundDefault test above check whether adef_expr is
557+
* "NULL", so that it will reach the same conclusion before or
558+
* after this is done.
559+
*/
543560
if (foundDefault && tbinfo->attrdefs[j] == NULL)
544561
{
545562
AttrDefInfo *attrDef;
@@ -575,10 +592,10 @@ flagInhAttrs(DumpOptions *dopt, TableInfo *tblinfo, int numTables)
575592
tbinfo->attrdefs[j] = attrDef;
576593
}
577594

578-
/* Remove generation expression from child if possible */
595+
/* No need to dump generation expression if it's inheritable */
579596
if (foundSameGenerated && !foundDiffGenerated &&
580597
!tbinfo->ispartition && !dopt->binary_upgrade)
581-
tbinfo->attrdefs[j] = NULL;
598+
tbinfo->attrdefs[j]->dobj.dump = DUMP_COMPONENT_NONE;
582599
}
583600
}
584601
}

src/bin/pg_dump/pg_dump.c

+6-4
Original file line numberDiff line numberDiff line change
@@ -8525,9 +8525,9 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
85258525
* Column generation expressions cannot be dumped separately,
85268526
* because there is no syntax for it. By setting separate to
85278527
* false here we prevent the "default" from being processed as
8528-
* its own dumpable object, and flagInhAttrs() will remove it
8529-
* from the table if possible (that is, if it can be inherited
8530-
* from a parent).
8528+
* its own dumpable object. Later, flagInhAttrs() will mark
8529+
* it as not to be dumped at all, if possible (that is, if it
8530+
* can be inherited from a parent).
85318531
*/
85328532
attrdefs[j].separate = false;
85338533
}
@@ -15345,9 +15345,11 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
1534515345
bool print_notnull;
1534615346

1534715347
/*
15348-
* Default value --- suppress if to be printed separately.
15348+
* Default value --- suppress if to be printed separately
15349+
* or not at all.
1534915350
*/
1535015351
print_default = (tbinfo->attrdefs[j] != NULL &&
15352+
tbinfo->attrdefs[j]->dobj.dump &&
1535115353
!tbinfo->attrdefs[j]->separate);
1535215354

1535315355
/*

0 commit comments

Comments
 (0)