diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2024-05-22 17:54:17 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2024-05-22 17:54:17 -0400 |
commit | 5278668d7a460d0fac3578d494c039dbc1fc5e89 (patch) | |
tree | ed6f8c90dcfa8b1e9a84667abd5bdefbdea7b4a4 /src/backend/parser/parse_utilcmd.c | |
parent | c37267162e889fe783786b9e28d1b65b82365a00 (diff) | |
download | postgresql-5278668d7a460d0fac3578d494c039dbc1fc5e89.tar.gz postgresql-5278668d7a460d0fac3578d494c039dbc1fc5e89.zip |
Fix handling of extended expression statistics in CREATE TABLE LIKE.
transformTableLikeClause believed that it could process extended
statistics immediately because "the representation of CreateStatsStmt
doesn't depend on column numbers". That was true when extended stats
were first introduced, but it was falsified by the addition of
extended stats on expressions: the parsed expression tree is fed
forward by the LIKE option, and that will contain Vars. So if the
new table doesn't have attnums identical to the old one's (typically
because there are some dropped columns in the old one), that doesn't
work. The CREATE goes through, but it emits invalid statistics
objects that will cause problems later.
Fortunately, we already have logic that can adapt expression trees
to the possibly-new column numbering. To use it, we have to delay
processing of CREATE_TABLE_LIKE_STATISTICS into expandTableLikeClause,
just as for other LIKE options that involve expressions.
Per bug #18468 from Alexander Lakhin. Back-patch to v14 where
extended statistics on expressions were added.
Discussion: https://postgr.es/m/18468-f5add190e3fa5902@postgresql.org
Diffstat (limited to 'src/backend/parser/parse_utilcmd.c')
-rw-r--r-- | src/backend/parser/parse_utilcmd.c | 136 |
1 files changed, 63 insertions, 73 deletions
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index 639cfa443e2..d5c2b2ff0b0 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -87,7 +87,6 @@ typedef struct List *fkconstraints; /* FOREIGN KEY constraints */ List *ixconstraints; /* index-creating constraints */ List *likeclauses; /* LIKE clauses that need post-processing */ - List *extstats; /* cloned extended statistics */ List *blist; /* "before list" of things to do before * creating the table */ List *alist; /* "after list" of things to do after creating @@ -120,13 +119,14 @@ static void transformTableLikeClause(CreateStmtContext *cxt, static void transformOfType(CreateStmtContext *cxt, TypeName *ofTypename); static CreateStatsStmt *generateClonedExtStatsStmt(RangeVar *heapRel, - Oid heapRelid, Oid source_statsid); + Oid heapRelid, + Oid source_statsid, + const AttrMap *attmap); static List *get_collation(Oid collation, Oid actual_datatype); static List *get_opclass(Oid opclass, Oid actual_datatype); static void transformIndexConstraints(CreateStmtContext *cxt); static IndexStmt *transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt); -static void transformExtendedStatistics(CreateStmtContext *cxt); static void transformFKConstraints(CreateStmtContext *cxt, bool skipValidation, bool isAddConstraint); @@ -246,7 +246,6 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString) cxt.fkconstraints = NIL; cxt.ixconstraints = NIL; cxt.likeclauses = NIL; - cxt.extstats = NIL; cxt.blist = NIL; cxt.alist = NIL; cxt.pkey = NULL; @@ -340,11 +339,6 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString) transformCheckConstraints(&cxt, !cxt.isforeign); /* - * Postprocess extended statistics. - */ - transformExtendedStatistics(&cxt); - - /* * Output results. */ stmt->tableElts = cxt.columns; @@ -1111,62 +1105,26 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla } /* - * We cannot yet deal with defaults, CHECK constraints, or indexes, since - * we don't yet know what column numbers the copied columns will have in - * the finished table. If any of those options are specified, add the - * LIKE clause to cxt->likeclauses so that expandTableLikeClause will be - * called after we do know that. Also, remember the relation OID so that - * expandTableLikeClause is certain to open the same table. + * We cannot yet deal with defaults, CHECK constraints, indexes, or + * statistics, since we don't yet know what column numbers the copied + * columns will have in the finished table. If any of those options are + * specified, add the LIKE clause to cxt->likeclauses so that + * expandTableLikeClause will be called after we do know that. Also, + * remember the relation OID so that expandTableLikeClause is certain to + * open the same table. */ if (table_like_clause->options & (CREATE_TABLE_LIKE_DEFAULTS | CREATE_TABLE_LIKE_GENERATED | CREATE_TABLE_LIKE_CONSTRAINTS | - CREATE_TABLE_LIKE_INDEXES)) + CREATE_TABLE_LIKE_INDEXES | + CREATE_TABLE_LIKE_STATISTICS)) { table_like_clause->relationOid = RelationGetRelid(relation); cxt->likeclauses = lappend(cxt->likeclauses, table_like_clause); } /* - * We may copy extended statistics if requested, since the representation - * of CreateStatsStmt doesn't depend on column numbers. - */ - if (table_like_clause->options & CREATE_TABLE_LIKE_STATISTICS) - { - List *parent_extstats; - ListCell *l; - - parent_extstats = RelationGetStatExtList(relation); - - foreach(l, parent_extstats) - { - Oid parent_stat_oid = lfirst_oid(l); - CreateStatsStmt *stats_stmt; - - stats_stmt = generateClonedExtStatsStmt(cxt->relation, - RelationGetRelid(relation), - parent_stat_oid); - - /* Copy comment on statistics object, if requested */ - if (table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS) - { - comment = GetComment(parent_stat_oid, StatisticExtRelationId, 0); - - /* - * We make use of CreateStatsStmt's stxcomment option, so as - * not to need to know now what name the statistics will have. - */ - stats_stmt->stxcomment = comment; - } - - cxt->extstats = lappend(cxt->extstats, stats_stmt); - } - - list_free(parent_extstats); - } - - /* * Close the parent rel, but keep our AccessShareLock on it until xact * commit. That will prevent someone else from deleting or ALTERing the * parent before we can run expandTableLikeClause. @@ -1423,6 +1381,44 @@ expandTableLikeClause(RangeVar *heapRel, TableLikeClause *table_like_clause) } } + /* + * Process extended statistics if required. + */ + if (table_like_clause->options & CREATE_TABLE_LIKE_STATISTICS) + { + List *parent_extstats; + ListCell *l; + + parent_extstats = RelationGetStatExtList(relation); + + foreach(l, parent_extstats) + { + Oid parent_stat_oid = lfirst_oid(l); + CreateStatsStmt *stats_stmt; + + stats_stmt = generateClonedExtStatsStmt(heapRel, + RelationGetRelid(childrel), + parent_stat_oid, + attmap); + + /* Copy comment on statistics object, if requested */ + if (table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS) + { + comment = GetComment(parent_stat_oid, StatisticExtRelationId, 0); + + /* + * We make use of CreateStatsStmt's stxcomment option, so as + * not to need to know now what name the statistics will have. + */ + stats_stmt->stxcomment = comment; + } + + result = lappend(result, stats_stmt); + } + + list_free(parent_extstats); + } + /* Done with child rel */ table_close(childrel, NoLock); @@ -1837,10 +1833,12 @@ generateClonedIndexStmt(RangeVar *heapRel, Relation source_idx, * Generate a CreateStatsStmt node using information from an already existing * extended statistic "source_statsid", for the rel identified by heapRel and * heapRelid. + * + * Attribute numbers in expression Vars are adjusted according to attmap. */ static CreateStatsStmt * generateClonedExtStatsStmt(RangeVar *heapRel, Oid heapRelid, - Oid source_statsid) + Oid source_statsid, const AttrMap *attmap) { HeapTuple ht_stats; Form_pg_statistic_ext statsrec; @@ -1923,10 +1921,19 @@ generateClonedExtStatsStmt(RangeVar *heapRel, Oid heapRelid, foreach(lc, exprs) { + Node *expr = (Node *) lfirst(lc); StatsElem *selem = makeNode(StatsElem); + bool found_whole_row; + + /* Adjust Vars to match new table's column numbering */ + expr = map_variable_attnos(expr, + 1, 0, + attmap, + InvalidOid, + &found_whole_row); selem->name = NULL; - selem->expr = (Node *) lfirst(lc); + selem->expr = expr; def_names = lappend(def_names, selem); } @@ -2653,19 +2660,6 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt) } /* - * transformExtendedStatistics - * Handle extended statistic objects - * - * Right now, there's nothing to do here, so we just append the list to - * the existing "after" list. - */ -static void -transformExtendedStatistics(CreateStmtContext *cxt) -{ - cxt->alist = list_concat(cxt->alist, cxt->extstats); -} - -/* * transformCheckConstraints * handle CHECK constraints * @@ -3457,7 +3451,6 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt, cxt.fkconstraints = NIL; cxt.ixconstraints = NIL; cxt.likeclauses = NIL; - cxt.extstats = NIL; cxt.blist = NIL; cxt.alist = NIL; cxt.pkey = NULL; @@ -3763,9 +3756,6 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt, newcmds = lappend(newcmds, newcmd); } - /* Append extended statistics objects */ - transformExtendedStatistics(&cxt); - /* Close rel */ relation_close(rel, NoLock); |