Skip to content

Commit 57f8178

Browse files
jeff-davishari90
authored andcommitted
Matview statistics depend on matview data.
yb conflict resolutions: - src/bin/pg_dump/pg_backup_archiver.c >@@ -102,7 +102,8 @@ static void pending_list_append(TocEntry *l, TocEntry *te); <@@ -124,7 +124,8 @@ static void ready_list_insert(ParallelReadyList *ready_list, TocEntry *te); >-static void move_to_ready_heap(TocEntry *pending_list, >+static void move_to_ready_heap(ArchiveHandle *AH, <-static void move_to_ready_list(TocEntry *pending_list, <+static void move_to_ready_list(ArchiveHandle *AH, Cause: Missing 9bfd44b: pg_restore's ready_list was converted to a priority queue Resolution: Combine incoming addition of ArchiveHandle with pg15's ready_list. >@@ -4331,7 +4352,7 @@ restore_toc_entries_parallel(ArchiveHandle *AH, ParallelState *pstate, <@@ -4146,7 +4167,7 @@ restore_toc_entries_parallel(ArchiveHandle *AH, ParallelState *pstate, >- move_to_ready_heap(pending_list, ready_heap, AH->restorePass); >+ move_to_ready_heap(AH, pending_list, ready_heap, AH->restorePass); <- move_to_ready_list(pending_list, &ready_list, AH->restorePass); <+ move_to_ready_list(AH, pending_list, &ready_list, AH->restorePass); Cause: Missing 9bfd44b: pg_restore's ready_list was converted to a priority queue Resolution: Combine incoming addition of ArchiveHandle with pg15's ready_list. >@@ -4380,7 +4401,7 @@ restore_toc_entries_parallel(ArchiveHandle *AH, ParallelState *pstate, <@@ -4195,7 +4216,7 @@ restore_toc_entries_parallel(ArchiveHandle *AH, ParallelState *pstate, >- move_to_ready_heap(pending_list, ready_heap, AH->restorePass); >+ move_to_ready_heap(AH, pending_list, ready_heap, AH->restorePass); <- move_to_ready_list(pending_list, &ready_list, AH->restorePass); <+ move_to_ready_list(AH, pending_list, &ready_list, AH->restorePass); Cause: Missing 9bfd44b: pg_restore's ready_list was converted to a priority queue Resolution: Combine incoming addition of ArchiveHandle with pg15's ready_list. >@@ -4551,7 +4572,8 @@ TocEntrySizeCompareBinaryheap(void *p1, void *p2, void *arg) <@@ -4429,7 +4450,8 @@ TocEntrySizeCompare(const void *p1, const void *p2) >-move_to_ready_heap(TocEntry *pending_list, >+move_to_ready_heap(ArchiveHandle *AH, <-move_to_ready_list(TocEntry *pending_list, <+move_to_ready_list(ArchiveHandle *AH, Cause: Missing 9bfd44b: pg_restore's ready_list was converted to a priority queue Resolution: Combine incoming addition of ArchiveHandle with pg15's ready_list. REFRESH MATERIALIZED VIEW replaces the storage, which resets statistics, so statistics must be restored afterward. If both statistics and data are being dumped for a materialized view, add a dependency from the former to the latter. Defer the statistics to SECTION_POST_DATA, and use RESTORE_PASS_POST_ACL. Reported-by: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com> Reviewed-by: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com> Discussion: https://postgr.es/m/CAExHW5s47kmubpbbRJzSM-Zfe0Tj2O3GBagB7YAyE8rQ-V24Uw@mail.gmail.com (cherry picked from commit a0a4601)
1 parent b84ef44 commit 57f8178

File tree

4 files changed

+91
-60
lines changed

4 files changed

+91
-60
lines changed

src/bin/pg_dump/pg_backup_archiver.c

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ static void processEncodingEntry(ArchiveHandle *AH, TocEntry *te);
9191
static void processStdStringsEntry(ArchiveHandle *AH, TocEntry *te);
9292
static void processSearchPathEntry(ArchiveHandle *AH, TocEntry *te);
9393
static int _tocEntryRequired(TocEntry *te, teSection curSection, ArchiveHandle *AH);
94-
static RestorePass _tocEntryRestorePass(TocEntry *te);
94+
static RestorePass _tocEntryRestorePass(ArchiveHandle *AH, TocEntry *te);
9595
static bool _tocEntryIsACL(TocEntry *te);
9696
static void _disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te);
9797
static void _enableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te);
@@ -124,7 +124,8 @@ static void ready_list_insert(ParallelReadyList *ready_list, TocEntry *te);
124124
static void ready_list_remove(ParallelReadyList *ready_list, int i);
125125
static void ready_list_sort(ParallelReadyList *ready_list);
126126
static int TocEntrySizeCompare(const void *p1, const void *p2);
127-
static void move_to_ready_list(TocEntry *pending_list,
127+
static void move_to_ready_list(ArchiveHandle *AH,
128+
TocEntry *pending_list,
128129
ParallelReadyList *ready_list,
129130
RestorePass pass);
130131
static TocEntry *pop_next_work_item(ParallelReadyList *ready_list,
@@ -701,7 +702,7 @@ RestoreArchive(Archive *AHX)
701702
if ((te->reqs & (REQ_SCHEMA | REQ_DATA | REQ_STATS)) == 0)
702703
continue; /* ignore if not to be dumped at all */
703704

704-
switch (_tocEntryRestorePass(te))
705+
switch (_tocEntryRestorePass(AH, te))
705706
{
706707
case RESTORE_PASS_MAIN:
707708
(void) restore_toc_entry(AH, te, false);
@@ -720,7 +721,7 @@ RestoreArchive(Archive *AHX)
720721
for (te = AH->toc->next; te != AH->toc; te = te->next)
721722
{
722723
if ((te->reqs & (REQ_SCHEMA | REQ_DATA | REQ_STATS)) != 0 &&
723-
_tocEntryRestorePass(te) == RESTORE_PASS_ACL)
724+
_tocEntryRestorePass(AH, te) == RESTORE_PASS_ACL)
724725
(void) restore_toc_entry(AH, te, false);
725726
}
726727
}
@@ -730,7 +731,7 @@ RestoreArchive(Archive *AHX)
730731
for (te = AH->toc->next; te != AH->toc; te = te->next)
731732
{
732733
if ((te->reqs & (REQ_SCHEMA | REQ_DATA | REQ_STATS)) != 0 &&
733-
_tocEntryRestorePass(te) == RESTORE_PASS_POST_ACL)
734+
_tocEntryRestorePass(AH, te) == RESTORE_PASS_POST_ACL)
734735
(void) restore_toc_entry(AH, te, false);
735736
}
736737
}
@@ -3130,7 +3131,7 @@ _tocEntryRequired(TocEntry *te, teSection curSection, ArchiveHandle *AH)
31303131
* See notes with the RestorePass typedef in pg_backup_archiver.h.
31313132
*/
31323133
static RestorePass
3133-
_tocEntryRestorePass(TocEntry *te)
3134+
_tocEntryRestorePass(ArchiveHandle *AH, TocEntry *te)
31343135
{
31353136
/* "ACL LANGUAGE" was a crock emitted only in PG 7.4 */
31363137
if (strcmp(te->desc, "ACL") == 0 ||
@@ -3151,6 +3152,26 @@ _tocEntryRestorePass(TocEntry *te)
31513152
strncmp(te->tag, "EVENT TRIGGER ", 14) == 0)
31523153
return RESTORE_PASS_POST_ACL;
31533154

3155+
/*
3156+
* If statistics data is dependent on materialized view data, it must be
3157+
* deferred to RESTORE_PASS_POST_ACL.
3158+
*/
3159+
if (strcmp(te->desc, "STATISTICS DATA") == 0)
3160+
{
3161+
for (int i = 0; i < te->nDeps; i++)
3162+
{
3163+
DumpId depid = te->dependencies[i];
3164+
3165+
if (depid <= AH->maxDumpId && AH->tocsByDumpId[depid] != NULL)
3166+
{
3167+
TocEntry *otherte = AH->tocsByDumpId[depid];
3168+
3169+
if (strcmp(otherte->desc, "MATERIALIZED VIEW DATA") == 0)
3170+
return RESTORE_PASS_POST_ACL;
3171+
}
3172+
}
3173+
}
3174+
31543175
/* All else can be handled in the main pass. */
31553176
return RESTORE_PASS_MAIN;
31563177
}
@@ -4069,7 +4090,7 @@ restore_toc_entries_prefork(ArchiveHandle *AH, TocEntry *pending_list)
40694090
* not set skipped_some in this case, since by assumption no main-pass
40704091
* items could depend on these.
40714092
*/
4072-
if (_tocEntryRestorePass(next_work_item) != RESTORE_PASS_MAIN)
4093+
if (_tocEntryRestorePass(AH, next_work_item) != RESTORE_PASS_MAIN)
40734094
do_now = false;
40744095

40754096
if (do_now)
@@ -4145,7 +4166,7 @@ restore_toc_entries_parallel(ArchiveHandle *AH, ParallelState *pstate,
41454166
* process in the current restore pass.
41464167
*/
41474168
AH->restorePass = RESTORE_PASS_MAIN;
4148-
move_to_ready_list(pending_list, &ready_list, AH->restorePass);
4169+
move_to_ready_list(AH, pending_list, &ready_list, AH->restorePass);
41494170

41504171
/*
41514172
* main parent loop
@@ -4194,7 +4215,7 @@ restore_toc_entries_parallel(ArchiveHandle *AH, ParallelState *pstate,
41944215
/* Advance to next restore pass */
41954216
AH->restorePass++;
41964217
/* That probably allows some stuff to be made ready */
4197-
move_to_ready_list(pending_list, &ready_list, AH->restorePass);
4218+
move_to_ready_list(AH, pending_list, &ready_list, AH->restorePass);
41984219
/* Loop around to see if anything's now ready */
41994220
continue;
42004221
}
@@ -4428,7 +4449,8 @@ TocEntrySizeCompare(const void *p1, const void *p2)
44284449
* which applies the same logic one-at-a-time.)
44294450
*/
44304451
static void
4431-
move_to_ready_list(TocEntry *pending_list,
4452+
move_to_ready_list(ArchiveHandle *AH,
4453+
TocEntry *pending_list,
44324454
ParallelReadyList *ready_list,
44334455
RestorePass pass)
44344456
{
@@ -4441,7 +4463,7 @@ move_to_ready_list(TocEntry *pending_list,
44414463
next_te = te->pending_next;
44424464

44434465
if (te->depCount == 0 &&
4444-
_tocEntryRestorePass(te) == pass)
4466+
_tocEntryRestorePass(AH, te) == pass)
44454467
{
44464468
/* Remove it from pending_list ... */
44474469
pending_list_remove(te);
@@ -4835,7 +4857,7 @@ reduce_dependencies(ArchiveHandle *AH, TocEntry *te,
48354857
* memberships changed.
48364858
*/
48374859
if (otherte->depCount == 0 &&
4838-
_tocEntryRestorePass(otherte) == AH->restorePass &&
4860+
_tocEntryRestorePass(AH, otherte) == AH->restorePass &&
48394861
otherte->pending_prev != NULL &&
48404862
ready_list != NULL)
48414863
{

src/bin/pg_dump/pg_dump.c

Lines changed: 54 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -2798,6 +2798,19 @@ makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
27982798

27992799
tbinfo->dataObj = tdinfo;
28002800

2801+
/*
2802+
* Materialized view statistics must be restored after the data, because
2803+
* REFRESH MATERIALIZED VIEW replaces the storage and resets the stats.
2804+
*
2805+
* The dependency is added here because the statistics objects are created
2806+
* first.
2807+
*/
2808+
if (tbinfo->relkind == RELKIND_MATVIEW && tbinfo->stats != NULL)
2809+
{
2810+
tbinfo->stats->section = SECTION_POST_DATA;
2811+
addObjectDependency(&tbinfo->stats->dobj, tdinfo->dobj.dumpId);
2812+
}
2813+
28012814
/* Make sure that we'll collect per-column info for this table. */
28022815
tbinfo->interesting = true;
28032816
}
@@ -6366,7 +6379,32 @@ getRelationStatistics(Archive *fout, DumpableObject *rel, int32 relpages,
63666379
info->relkind = relkind;
63676380
info->indAttNames = indAttNames;
63686381
info->nindAttNames = nindAttNames;
6369-
info->postponed_def = false;
6382+
6383+
/*
6384+
* Ordinarily, stats go in SECTION_DATA for tables and
6385+
* SECTION_POST_DATA for indexes.
6386+
*
6387+
* However, the section may be updated later for materialized view
6388+
* stats. REFRESH MATERIALIZED VIEW replaces the storage and resets
6389+
* the stats, so the stats must be restored after the data. Also, the
6390+
* materialized view definition may be postponed to SECTION_POST_DATA
6391+
* (see repairMatViewBoundaryMultiLoop()).
6392+
*/
6393+
switch (info->relkind)
6394+
{
6395+
case RELKIND_RELATION:
6396+
case RELKIND_PARTITIONED_TABLE:
6397+
case RELKIND_MATVIEW:
6398+
info->section = SECTION_DATA;
6399+
break;
6400+
case RELKIND_INDEX:
6401+
case RELKIND_PARTITIONED_INDEX:
6402+
info->section = SECTION_POST_DATA;
6403+
break;
6404+
default:
6405+
pg_fatal("cannot dump statistics for relation kind '%c'",
6406+
info->relkind);
6407+
}
63706408

63716409
return info;
63726410
}
@@ -6763,9 +6801,17 @@ getTables(Archive *fout, int *numTables)
67636801

67646802
/* Add statistics */
67656803
if (tblinfo[i].interesting)
6766-
getRelationStatistics(fout, &tblinfo[i].dobj, tblinfo[i].relpages,
6767-
PQgetvalue(res, i, i_reltuples),
6768-
relallvisible, tblinfo[i].relkind, NULL, 0);
6804+
{
6805+
RelStatsInfo *stats;
6806+
6807+
stats = getRelationStatistics(fout, &tblinfo[i].dobj,
6808+
tblinfo[i].relpages,
6809+
PQgetvalue(res, i, i_reltuples),
6810+
relallvisible,
6811+
tblinfo[i].relkind, NULL, 0);
6812+
if (tblinfo[i].relkind == RELKIND_MATVIEW)
6813+
tblinfo[i].stats = stats;
6814+
}
67696815

67706816
/*
67716817
* Read-lock target tables to make sure they aren't DROPPED or altered
@@ -9932,34 +9978,6 @@ appendNamedArgument(PQExpBuffer out, Archive *fout, const char *argname,
99329978
appendPQExpBuffer(out, "::%s", argtype);
99339979
}
99349980

9935-
/*
9936-
* Decide which section to use based on the relkind of the parent object.
9937-
*
9938-
* NB: materialized views may be postponed from SECTION_PRE_DATA to
9939-
* SECTION_POST_DATA to resolve some kinds of dependency problems. If so, the
9940-
* matview stats will also be postponed to SECTION_POST_DATA. See
9941-
* repairMatViewBoundaryMultiLoop().
9942-
*/
9943-
static teSection
9944-
statisticsDumpSection(const RelStatsInfo *rsinfo)
9945-
{
9946-
switch (rsinfo->relkind)
9947-
{
9948-
case RELKIND_RELATION:
9949-
case RELKIND_PARTITIONED_TABLE:
9950-
case RELKIND_MATVIEW:
9951-
return SECTION_DATA;
9952-
case RELKIND_INDEX:
9953-
case RELKIND_PARTITIONED_INDEX:
9954-
return SECTION_POST_DATA;
9955-
default:
9956-
pg_fatal("cannot dump statistics for relation kind '%c'",
9957-
rsinfo->relkind);
9958-
}
9959-
9960-
return 0; /* keep compiler quiet */
9961-
}
9962-
99639981
/*
99649982
* dumpRelationStats --
99659983
*
@@ -9972,8 +9990,6 @@ dumpRelationStats(Archive *fout, const RelStatsInfo *rsinfo)
99729990
PGresult *res;
99739991
PQExpBuffer query;
99749992
PQExpBuffer out;
9975-
DumpId *deps = NULL;
9976-
int ndeps = 0;
99779993
int i_attname;
99789994
int i_inherited;
99799995
int i_null_frac;
@@ -9994,13 +10010,6 @@ dumpRelationStats(Archive *fout, const RelStatsInfo *rsinfo)
999410010
if (!fout->dopt->dumpStatistics)
999510011
return;
999610012

9997-
/* dependent on the relation definition, if doing schema */
9998-
if (fout->dopt->dumpSchema)
9999-
{
10000-
deps = dobj->dependencies;
10001-
ndeps = dobj->nDeps;
10002-
}
10003-
1000410013
query = createPQExpBuffer();
1000510014
if (!fout->is_prepared[PREPQUERY_GETATTRIBUTESTATS])
1000610015
{
@@ -10178,11 +10187,10 @@ dumpRelationStats(Archive *fout, const RelStatsInfo *rsinfo)
1017810187
ARCHIVE_OPTS(.tag = dobj->name,
1017910188
.namespace = dobj->namespace->dobj.name,
1018010189
.description = "STATISTICS DATA",
10181-
.section = rsinfo->postponed_def ?
10182-
SECTION_POST_DATA : statisticsDumpSection(rsinfo),
10190+
.section = rsinfo->section,
1018310191
.createStmt = out->data,
10184-
.deps = deps,
10185-
.nDeps = ndeps));
10192+
.deps = dobj->dependencies,
10193+
.nDeps = dobj->nDeps));
1018610194

1018710195
destroyPQExpBuffer(out);
1018810196
destroyPQExpBuffer(query);
@@ -18652,7 +18660,7 @@ addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
1865218660
break;
1865318661
case DO_REL_STATS:
1865418662
/* stats section varies by parent object type, DATA or POST */
18655-
if (statisticsDumpSection((RelStatsInfo *) dobj) == SECTION_DATA)
18663+
if (((RelStatsInfo *) dobj)->section == SECTION_DATA)
1865618664
{
1865718665
addObjectDependency(dobj, preDataBound->dumpId);
1865818666
addObjectDependency(postDataBound, dobj->dumpId);

src/bin/pg_dump/pg_dump.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,7 @@ typedef struct _tableInfo
360360
bool *inhNotNull; /* true if NOT NULL is inherited */
361361
struct _attrDefInfo **attrdefs; /* DEFAULT expressions */
362362
struct _constraintInfo *checkexprs; /* CHECK constraints */
363+
struct _relStatsInfo *stats; /* only set for matviews */
363364
bool needs_override; /* has GENERATED ALWAYS AS IDENTITY */
364365
char *amname; /* relation access method */
365366

@@ -442,7 +443,7 @@ typedef struct _relStatsInfo
442443
*/
443444
char **indAttNames; /* attnames of the index, in order */
444445
int32 nindAttNames; /* number of attnames stored (can be 0) */
445-
bool postponed_def; /* stats must be postponed into post-data */
446+
teSection section; /* stats may appear in data or post-data */
446447
} RelStatsInfo;
447448

448449
typedef struct _statsExtInfo

src/bin/pg_dump/pg_dump_sort.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -877,7 +877,7 @@ repairMatViewBoundaryMultiLoop(DumpableObject *boundaryobj,
877877
RelStatsInfo *nextinfo = (RelStatsInfo *) nextobj;
878878

879879
if (nextinfo->relkind == RELKIND_MATVIEW)
880-
nextinfo->postponed_def = true;
880+
nextinfo->section = SECTION_POST_DATA;
881881
}
882882
}
883883

0 commit comments

Comments
 (0)