diff --git a/doc/src/sgml/ref/create_table.sgml b/doc/src/sgml/ref/create_table.sgml
index 338dddd7cc..9e8e9d8f1c 100644
--- a/doc/src/sgml/ref/create_table.sgml
+++ b/doc/src/sgml/ref/create_table.sgml
@@ -82,7 +82,7 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
and like_option is:
-{ INCLUDING | EXCLUDING } { DEFAULTS | CONSTRAINTS | IDENTITY | INDEXES | STORAGE | COMMENTS | ALL }
+{ INCLUDING | EXCLUDING } { COMMENTS | CONSTRAINTS | DEFAULTS | IDENTITY | INDEXES | STATISTICS | STORAGE | ALL }
and partition_bound_spec is:
@@ -591,6 +591,10 @@ WITH ( MODULUS numeric_literal, REM
No distinction is made between column constraints and table
constraints.
+
+ Extended statistics are copied to the new table if
+ INCLUDING STATISTICS is specified.
+
Indexes, PRIMARY KEY, UNIQUE,
and EXCLUDE constraints on the original table will be
@@ -616,7 +620,7 @@ WITH ( MODULUS numeric_literal, REM
INCLUDING ALL is an abbreviated form of
- INCLUDING DEFAULTS INCLUDING IDENTITY INCLUDING CONSTRAINTS INCLUDING INDEXES INCLUDING STORAGE INCLUDING COMMENTS.
+ INCLUDING COMMENTS INCLUDING CONSTRAINTS INCLUDING DEFAULTS INCLUDING IDENTITY INCLUDING INDEXES INCLUDING STATISTICS INCLUDING STORAGE.
Note that unlike INHERITS, columns and
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 3e48a58dcb..504806b25b 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -1805,7 +1805,8 @@ GetDefaultOpClass(Oid type_id, Oid am_id)
/*
* makeObjectName()
*
- * Create a name for an implicitly created index, sequence, constraint, etc.
+ * Create a name for an implicitly created index, sequence, constraint,
+ * extended statistics, etc.
*
* The parameters are typically: the original table name, the original field
* name, and a "type" string (such as "seq" or "pkey"). The field name
@@ -1981,6 +1982,8 @@ ChooseIndexName(const char *tabname, Oid namespaceId,
*
* We know that less than NAMEDATALEN characters will actually be used,
* so we can truncate the result once we've generated that many.
+ *
+ * XXX See also ChooseExtendedStatisticNameAddition.
*/
static char *
ChooseIndexNameAddition(List *colnames)
diff --git a/src/backend/commands/statscmds.c b/src/backend/commands/statscmds.c
index e90a14273b..f46ef01134 100644
--- a/src/backend/commands/statscmds.c
+++ b/src/backend/commands/statscmds.c
@@ -20,6 +20,7 @@
#include "catalog/namespace.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_statistic_ext.h"
+#include "commands/comment.h"
#include "commands/defrem.h"
#include "miscadmin.h"
#include "statistics/statistics.h"
@@ -31,6 +32,11 @@
#include "utils/typcache.h"
+static char *ChooseExtendedStatisticName(const char *name1, const char *name2,
+ const char *label, Oid namespaceid);
+static char *ChooseExtendedStatisticNameAddition(List *exprs);
+
+
/* qsort comparator for the attnums in CreateStatistics */
static int
compare_int16(const void *a, const void *b)
@@ -51,7 +57,6 @@ CreateStatistics(CreateStatsStmt *stmt)
int16 attnums[STATS_MAX_DIMENSIONS];
int numcols = 0;
char *namestr;
- NameData stxname;
Oid statoid;
Oid namespaceId;
Oid stxowner = GetUserId();
@@ -75,31 +80,6 @@ CreateStatistics(CreateStatsStmt *stmt)
Assert(IsA(stmt, CreateStatsStmt));
- /* resolve the pieces of the name (namespace etc.) */
- namespaceId = QualifiedNameGetCreationNamespace(stmt->defnames, &namestr);
- namestrcpy(&stxname, namestr);
-
- /*
- * Deal with the possibility that the statistics object already exists.
- */
- if (SearchSysCacheExists2(STATEXTNAMENSP,
- NameGetDatum(&stxname),
- ObjectIdGetDatum(namespaceId)))
- {
- if (stmt->if_not_exists)
- {
- ereport(NOTICE,
- (errcode(ERRCODE_DUPLICATE_OBJECT),
- errmsg("statistics object \"%s\" already exists, skipping",
- namestr)));
- return InvalidObjectAddress;
- }
-
- ereport(ERROR,
- (errcode(ERRCODE_DUPLICATE_OBJECT),
- errmsg("statistics object \"%s\" already exists", namestr)));
- }
-
/*
* Examine the FROM clause. Currently, we only allow it to be a single
* simple table, but later we'll probably allow multiple tables and JOIN
@@ -148,6 +128,45 @@ CreateStatistics(CreateStatsStmt *stmt)
Assert(rel);
relid = RelationGetRelid(rel);
+ /*
+ * If the node has a name, split it up and determine creation namespace.
+ * If not (a possibility not considered by the grammar, but one which can
+ * occur via the "CREATE TABLE ... (LIKE)" command), then we put the
+ * object in the same namespace as the relation, and cons up a name for it.
+ */
+ if (stmt->defnames)
+ namespaceId = QualifiedNameGetCreationNamespace(stmt->defnames, &namestr);
+ else
+ {
+ namespaceId = RelationGetNamespace(rel);
+ namestr = ChooseExtendedStatisticName(RelationGetRelationName(rel),
+ ChooseExtendedStatisticNameAddition(stmt->exprs),
+ "stat",
+ namespaceId);
+ }
+
+ /*
+ * Deal with the possibility that the statistics object already exists.
+ */
+ if (SearchSysCacheExists2(STATEXTNAMENSP,
+ CStringGetDatum(namestr),
+ ObjectIdGetDatum(namespaceId)))
+ {
+ if (stmt->if_not_exists)
+ {
+ ereport(NOTICE,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg("statistics object \"%s\" already exists, skipping",
+ namestr)));
+ relation_close(rel, NoLock);
+ return InvalidObjectAddress;
+ }
+
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg("statistics object \"%s\" already exists", namestr)));
+ }
+
/*
* Currently, we only allow simple column references in the expression
* list. That will change someday, and again the grammar already supports
@@ -288,7 +307,7 @@ CreateStatistics(CreateStatsStmt *stmt)
memset(values, 0, sizeof(values));
memset(nulls, false, sizeof(nulls));
values[Anum_pg_statistic_ext_stxrelid - 1] = ObjectIdGetDatum(relid);
- values[Anum_pg_statistic_ext_stxname - 1] = NameGetDatum(&stxname);
+ values[Anum_pg_statistic_ext_stxname - 1] = CStringGetDatum(namestr);
values[Anum_pg_statistic_ext_stxnamespace - 1] = ObjectIdGetDatum(namespaceId);
values[Anum_pg_statistic_ext_stxowner - 1] = ObjectIdGetDatum(stxowner);
values[Anum_pg_statistic_ext_stxkeys - 1] = PointerGetDatum(stxkeys);
@@ -340,6 +359,11 @@ CreateStatistics(CreateStatsStmt *stmt)
* STATISTICS, which is more work than it seems worth.
*/
+ /* Add any requested comment */
+ if (stmt->stxcomment != NULL)
+ CreateComments(statoid, StatisticExtRelationId, 0,
+ stmt->stxcomment);
+
/* Return stats object's address */
return myself;
}
@@ -405,3 +429,94 @@ UpdateStatisticsForTypeChange(Oid statsOid, Oid relationOid, int attnum,
* Future types of extended stats will likely require us to work harder.
*/
}
+
+/*
+ * Select a nonconflicting name for a new statistics.
+ *
+ * name1, name2, and label are used the same way as for makeObjectName(),
+ * except that the label can't be NULL; digits will be appended to the label
+ * if needed to create a name that is unique within the specified namespace.
+ *
+ * Returns a palloc'd string.
+ *
+ * Note: it is theoretically possible to get a collision anyway, if someone
+ * else chooses the same name concurrently. This is fairly unlikely to be
+ * a problem in practice, especially if one is holding a share update
+ * exclusive lock on the relation identified by name1. However, if choosing
+ * multiple names within a single command, you'd better create the new object
+ * and do CommandCounterIncrement before choosing the next one!
+ */
+static char *
+ChooseExtendedStatisticName(const char *name1, const char *name2,
+ const char *label, Oid namespaceid)
+{
+ int pass = 0;
+ char *stxname = NULL;
+ char modlabel[NAMEDATALEN];
+
+ /* try the unmodified label first */
+ StrNCpy(modlabel, label, sizeof(modlabel));
+
+ for (;;)
+ {
+ Oid existingstats;
+
+ stxname = makeObjectName(name1, name2, modlabel);
+
+ existingstats = GetSysCacheOid2(STATEXTNAMENSP,
+ PointerGetDatum(stxname),
+ ObjectIdGetDatum(namespaceid));
+ if (!OidIsValid(existingstats))
+ break;
+
+ /* found a conflict, so try a new name component */
+ pfree(stxname);
+ snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
+ }
+
+ return stxname;
+}
+
+/*
+ * Generate "name2" for a new statistics given the list of column names for it
+ * This will be passed to ChooseExtendedStatisticName along with the parent
+ * table name and a suitable label.
+ *
+ * We know that less than NAMEDATALEN characters will actually be used,
+ * so we can truncate the result once we've generated that many.
+ *
+ * XXX see also ChooseIndexNameAddition.
+ */
+static char *
+ChooseExtendedStatisticNameAddition(List *exprs)
+{
+ char buf[NAMEDATALEN * 2];
+ int buflen = 0;
+ ListCell *lc;
+
+ buf[0] = '\0';
+ foreach(lc, exprs)
+ {
+ ColumnRef *cref = (ColumnRef *) lfirst(lc);
+ const char *name;
+
+ /* It should be one of these, but just skip if it happens not to be */
+ if (!IsA(cref, ColumnRef))
+ continue;
+
+ name = strVal((Value *) linitial(cref->fields));
+
+ if (buflen > 0)
+ buf[buflen++] = '_'; /* insert _ between names */
+
+ /*
+ * At this point we have buflen <= NAMEDATALEN. name should be less
+ * than NAMEDATALEN already, but use strlcpy for paranoia.
+ */
+ strlcpy(buf + buflen, name, NAMEDATALEN);
+ buflen += strlen(buf + buflen);
+ if (buflen >= NAMEDATALEN)
+ break;
+ }
+ return pstrdup(buf);
+}
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 266a3ef8ef..f84da801c6 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -3424,6 +3424,7 @@ _copyCreateStatsStmt(const CreateStatsStmt *from)
COPY_NODE_FIELD(stat_types);
COPY_NODE_FIELD(exprs);
COPY_NODE_FIELD(relations);
+ COPY_STRING_FIELD(stxcomment);
COPY_SCALAR_FIELD(if_not_exists);
return newnode;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index bbffc87842..ee8d925db1 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1363,6 +1363,7 @@ _equalCreateStatsStmt(const CreateStatsStmt *a, const CreateStatsStmt *b)
COMPARE_NODE_FIELD(stat_types);
COMPARE_NODE_FIELD(exprs);
COMPARE_NODE_FIELD(relations);
+ COMPARE_STRING_FIELD(stxcomment);
COMPARE_SCALAR_FIELD(if_not_exists);
return true;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 011d2a3fa9..1785ea3918 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -2687,6 +2687,7 @@ _outCreateStatsStmt(StringInfo str, const CreateStatsStmt *node)
WRITE_NODE_FIELD(stat_types);
WRITE_NODE_FIELD(exprs);
WRITE_NODE_FIELD(relations);
+ WRITE_STRING_FIELD(stxcomment);
WRITE_BOOL_FIELD(if_not_exists);
}
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index d99f2be2c9..8a2e52acb4 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -3636,12 +3636,13 @@ TableLikeOptionList:
;
TableLikeOption:
- DEFAULTS { $$ = CREATE_TABLE_LIKE_DEFAULTS; }
+ COMMENTS { $$ = CREATE_TABLE_LIKE_COMMENTS; }
| CONSTRAINTS { $$ = CREATE_TABLE_LIKE_CONSTRAINTS; }
+ | DEFAULTS { $$ = CREATE_TABLE_LIKE_DEFAULTS; }
| IDENTITY_P { $$ = CREATE_TABLE_LIKE_IDENTITY; }
| INDEXES { $$ = CREATE_TABLE_LIKE_INDEXES; }
+ | STATISTICS { $$ = CREATE_TABLE_LIKE_STATISTICS; }
| STORAGE { $$ = CREATE_TABLE_LIKE_STORAGE; }
- | COMMENTS { $$ = CREATE_TABLE_LIKE_COMMENTS; }
| ALL { $$ = CREATE_TABLE_LIKE_ALL; }
;
@@ -3980,6 +3981,7 @@ CreateStatsStmt:
n->stat_types = $4;
n->exprs = $6;
n->relations = $8;
+ n->stxcomment = NULL;
n->if_not_exists = false;
$$ = (Node *)n;
}
@@ -3991,6 +3993,7 @@ CreateStatsStmt:
n->stat_types = $7;
n->exprs = $9;
n->relations = $11;
+ n->stxcomment = NULL;
n->if_not_exists = true;
$$ = (Node *)n;
}
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 6029eb13d7..8c7bd68639 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;
@@ -334,6 +340,11 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString)
*/
transformCheckConstraints(&cxt, !is_foreign_table ? true : false);
+ /*
+ * Postprocess extended statistics.
+ */
+ transformExtendedStatistics(&cxt);
+
/*
* Output results.
*/
@@ -1189,6 +1200,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
@@ -1566,6 +1614,85 @@ generateClonedIndexStmt(RangeVar *heapRel, Oid heapRelid, Relation source_idx,
return index;
}
+/*
+ * 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
*
@@ -2119,6 +2246,18 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
return index;
}
+/*
+ * 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);
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index ac292bc6e7..f668cbad34 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -674,12 +674,13 @@ typedef struct TableLikeClause
typedef enum TableLikeOption
{
- CREATE_TABLE_LIKE_DEFAULTS = 1 << 0,
+ CREATE_TABLE_LIKE_COMMENTS = 1 << 0,
CREATE_TABLE_LIKE_CONSTRAINTS = 1 << 1,
- CREATE_TABLE_LIKE_IDENTITY = 1 << 2,
- CREATE_TABLE_LIKE_INDEXES = 1 << 3,
- CREATE_TABLE_LIKE_STORAGE = 1 << 4,
- CREATE_TABLE_LIKE_COMMENTS = 1 << 5,
+ CREATE_TABLE_LIKE_DEFAULTS = 1 << 2,
+ CREATE_TABLE_LIKE_IDENTITY = 1 << 3,
+ CREATE_TABLE_LIKE_INDEXES = 1 << 4,
+ CREATE_TABLE_LIKE_STATISTICS = 1 << 5,
+ CREATE_TABLE_LIKE_STORAGE = 1 << 6,
CREATE_TABLE_LIKE_ALL = PG_INT32_MAX
} TableLikeOption;
@@ -2741,6 +2742,7 @@ typedef struct CreateStatsStmt
List *stat_types; /* stat types (list of Value strings) */
List *exprs; /* expressions to build statistics on */
List *relations; /* rels to build stats on (list of RangeVar) */
+ char *stxcomment; /* comment to apply to stats, or NULL */
bool if_not_exists; /* do nothing if stats name already exists */
} CreateStatsStmt;
diff --git a/src/test/regress/expected/create_table_like.out b/src/test/regress/expected/create_table_like.out
index 3f405c94ce..52ff18c8ca 100644
--- a/src/test/regress/expected/create_table_like.out
+++ b/src/test/regress/expected/create_table_like.out
@@ -137,6 +137,8 @@ DROP TABLE inhz;
CREATE TABLE ctlt1 (a text CHECK (length(a) > 2) PRIMARY KEY, b text);
CREATE INDEX ctlt1_b_key ON ctlt1 (b);
CREATE INDEX ctlt1_fnidx ON ctlt1 ((a || b));
+CREATE STATISTICS ctlt1_a_b_stat ON a,b FROM ctlt1;
+COMMENT ON STATISTICS ctlt1_a_b_stat IS 'ab stats';
COMMENT ON COLUMN ctlt1.a IS 'A';
COMMENT ON COLUMN ctlt1.b IS 'B';
COMMENT ON CONSTRAINT ctlt1_a_check ON ctlt1 IS 't1_a_check';
@@ -240,6 +242,8 @@ Indexes:
"ctlt_all_expr_idx" btree ((a || b))
Check constraints:
"ctlt1_a_check" CHECK (length(a) > 2)
+Statistics objects:
+ "public"."ctlt_all_a_b_stat" (ndistinct, dependencies) ON a, b FROM ctlt_all
SELECT c.relname, objsubid, description FROM pg_description, pg_index i, pg_class c WHERE classoid = 'pg_class'::regclass AND objoid = i.indexrelid AND c.oid = i.indexrelid AND i.indrelid = 'ctlt_all'::regclass ORDER BY c.relname, objsubid;
relname | objsubid | description
@@ -248,6 +252,12 @@ SELECT c.relname, objsubid, description FROM pg_description, pg_index i, pg_clas
ctlt_all_pkey | 0 | index pkey
(2 rows)
+SELECT s.stxname, objsubid, description FROM pg_description, pg_statistic_ext s WHERE classoid = 'pg_statistic_ext'::regclass AND objoid = s.oid AND s.stxrelid = 'ctlt_all'::regclass ORDER BY s.stxname, objsubid;
+ stxname | objsubid | description
+-------------------+----------+-------------
+ ctlt_all_a_b_stat | 0 | ab stats
+(1 row)
+
CREATE TABLE inh_error1 () INHERITS (ctlt1, ctlt4);
NOTICE: merging multiple inherited definitions of column "a"
ERROR: inherited column "a" has a storage parameter conflict
diff --git a/src/test/regress/sql/create_table_like.sql b/src/test/regress/sql/create_table_like.sql
index 557040bbe7..32d861621b 100644
--- a/src/test/regress/sql/create_table_like.sql
+++ b/src/test/regress/sql/create_table_like.sql
@@ -71,6 +71,8 @@ DROP TABLE inhz;
CREATE TABLE ctlt1 (a text CHECK (length(a) > 2) PRIMARY KEY, b text);
CREATE INDEX ctlt1_b_key ON ctlt1 (b);
CREATE INDEX ctlt1_fnidx ON ctlt1 ((a || b));
+CREATE STATISTICS ctlt1_a_b_stat ON a,b FROM ctlt1;
+COMMENT ON STATISTICS ctlt1_a_b_stat IS 'ab stats';
COMMENT ON COLUMN ctlt1.a IS 'A';
COMMENT ON COLUMN ctlt1.b IS 'B';
COMMENT ON CONSTRAINT ctlt1_a_check ON ctlt1 IS 't1_a_check';
@@ -108,6 +110,7 @@ SELECT description FROM pg_description, pg_constraint c WHERE classoid = 'pg_con
CREATE TABLE ctlt_all (LIKE ctlt1 INCLUDING ALL);
\d+ ctlt_all
SELECT c.relname, objsubid, description FROM pg_description, pg_index i, pg_class c WHERE classoid = 'pg_class'::regclass AND objoid = i.indexrelid AND c.oid = i.indexrelid AND i.indrelid = 'ctlt_all'::regclass ORDER BY c.relname, objsubid;
+SELECT s.stxname, objsubid, description FROM pg_description, pg_statistic_ext s WHERE classoid = 'pg_statistic_ext'::regclass AND objoid = s.oid AND s.stxrelid = 'ctlt_all'::regclass ORDER BY s.stxname, objsubid;
CREATE TABLE inh_error1 () INHERITS (ctlt1, ctlt4);
CREATE TABLE inh_error2 (LIKE ctlt4 INCLUDING STORAGE) INHERITS (ctlt1);