aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_utilcmd.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser/parse_utilcmd.c')
-rw-r--r--src/backend/parser/parse_utilcmd.c143
1 files changed, 143 insertions, 0 deletions
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 6029eb13d7f..8c7bd686397 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -39,6 +39,7 @@
#include "catalog/pg_constraint_fn.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
+#include "catalog/pg_statistic_ext.h"
#include "catalog/pg_type.h"
#include "commands/comment.h"
#include "commands/defrem.h"
@@ -85,6 +86,7 @@ typedef struct
List *fkconstraints; /* FOREIGN KEY constraints */
List *ixconstraints; /* index-creating constraints */
List *inh_indexes; /* cloned indexes from INCLUDING INDEXES */
+ 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
@@ -118,11 +120,14 @@ static void transformTableLikeClause(CreateStmtContext *cxt,
TableLikeClause *table_like_clause);
static void transformOfType(CreateStmtContext *cxt,
TypeName *ofTypename);
+static CreateStatsStmt *generateClonedExtStatsStmt(RangeVar *heapRel,
+ Oid heapRelid, Oid source_statsid);
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);
@@ -234,6 +239,7 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString)
cxt.fkconstraints = NIL;
cxt.ixconstraints = NIL;
cxt.inh_indexes = NIL;
+ cxt.extstats = NIL;
cxt.blist = NIL;
cxt.alist = NIL;
cxt.pkey = NULL;
@@ -335,6 +341,11 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString)
transformCheckConstraints(&cxt, !is_foreign_table ? true : false);
/*
+ * Postprocess extended statistics.
+ */
+ transformExtendedStatistics(&cxt);
+
+ /*
* Output results.
*/
stmt->tableElts = cxt.columns;
@@ -1190,6 +1201,43 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
}
/*
+ * Likewise, copy extended statistics if requested
+ */
+ 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 the child is committed.
@@ -1567,6 +1615,85 @@ generateClonedIndexStmt(RangeVar *heapRel, Oid heapRelid, 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.
+ */
+static CreateStatsStmt *
+generateClonedExtStatsStmt(RangeVar *heapRel, Oid heapRelid,
+ Oid source_statsid)
+{
+ HeapTuple ht_stats;
+ Form_pg_statistic_ext statsrec;
+ CreateStatsStmt *stats;
+ List *stat_types = NIL;
+ List *def_names = NIL;
+ bool isnull;
+ Datum datum;
+ ArrayType *arr;
+ char *enabled;
+ int i;
+
+ Assert(OidIsValid(heapRelid));
+ Assert(heapRel != NULL);
+
+ /*
+ * Fetch pg_statistic_ext tuple of source statistics object.
+ */
+ ht_stats = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(source_statsid));
+ if (!HeapTupleIsValid(ht_stats))
+ elog(ERROR, "cache lookup failed for statistics object %u", source_statsid);
+ statsrec = (Form_pg_statistic_ext) GETSTRUCT(ht_stats);
+
+ /* Determine which statistics types exist */
+ datum = SysCacheGetAttr(STATEXTOID, ht_stats,
+ Anum_pg_statistic_ext_stxkind, &isnull);
+ Assert(!isnull);
+ arr = DatumGetArrayTypeP(datum);
+ if (ARR_NDIM(arr) != 1 ||
+ ARR_HASNULL(arr) ||
+ ARR_ELEMTYPE(arr) != CHAROID)
+ elog(ERROR, "stxkind is not a 1-D char array");
+ enabled = (char *) ARR_DATA_PTR(arr);
+ for (i = 0; i < ARR_DIMS(arr)[0]; i++)
+ {
+ if (enabled[i] == STATS_EXT_NDISTINCT)
+ stat_types = lappend(stat_types, makeString("ndistinct"));
+ else if (enabled[i] == STATS_EXT_DEPENDENCIES)
+ stat_types = lappend(stat_types, makeString("dependencies"));
+ else
+ elog(ERROR, "unrecognized statistics kind %c", enabled[i]);
+ }
+
+ /* Determine which columns the statistics are on */
+ for (i = 0; i < statsrec->stxkeys.dim1; i++)
+ {
+ ColumnRef *cref = makeNode(ColumnRef);
+ AttrNumber attnum = statsrec->stxkeys.values[i];
+
+ cref->fields = list_make1(makeString(get_attname(heapRelid,
+ attnum, false)));
+ cref->location = -1;
+
+ def_names = lappend(def_names, cref);
+ }
+
+ /* finally, build the output node */
+ stats = makeNode(CreateStatsStmt);
+ stats->defnames = NULL;
+ stats->stat_types = stat_types;
+ stats->exprs = def_names;
+ stats->relations = list_make1(heapRel);
+ stats->stxcomment = NULL;
+ stats->if_not_exists = false;
+
+ /* Clean up */
+ ReleaseSysCache(ht_stats);
+
+ return stats;
+}
+
+/*
* get_collation - fetch qualified name of a collation
*
* If collation is InvalidOid or is the default for the given actual_datatype,
@@ -2120,6 +2247,18 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
}
/*
+ * transformExtendedStatistics
+ * Handle extended statistic objects
+ *
+ * Right now, there's nothing to do here, so we just copy the list.
+ */
+static void
+transformExtendedStatistics(CreateStmtContext *cxt)
+{
+ cxt->alist = list_concat(cxt->alist, cxt->extstats);
+}
+
+/*
* transformCheckConstraints
* handle CHECK constraints
*
@@ -2695,6 +2834,7 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
cxt.fkconstraints = NIL;
cxt.ixconstraints = NIL;
cxt.inh_indexes = NIL;
+ cxt.extstats = NIL;
cxt.blist = NIL;
cxt.alist = NIL;
cxt.pkey = NULL;
@@ -2957,6 +3097,9 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
newcmds = lappend(newcmds, newcmd);
}
+ /* Append extended statistic objects */
+ transformExtendedStatistics(&cxt);
+
/* Close rel */
relation_close(rel, NoLock);