extstats_pg_dump_and_comment_support.patch
application/octet-stream
Filename: extstats_pg_dump_and_comment_support.patch
Type: application/octet-stream
Part: 0
Message:
Re: multivariate statistics (v25)
Patch
Format: unified
| File | + | − |
|---|---|---|
| doc/src/sgml/func.sgml | 25 | 14 |
| doc/src/sgml/ref/comment.sgml | 4 | 2 |
| src/backend/parser/gram.y | 2 | 1 |
| src/backend/utils/adt/ruleutils.c | 81 | 0 |
| src/bin/pg_dump/common.c | 4 | 0 |
| src/bin/pg_dump/pg_dump.c | 154 | 0 |
| src/bin/pg_dump/pg_dump.h | 9 | 0 |
| src/bin/pg_dump/pg_dump_sort.c | 11 | 10 |
| src/include/catalog/pg_proc.h | 2 | 0 |
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 40af053..1e42f05 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -16418,6 +16418,10 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
</indexterm>
<indexterm>
+ <primary>pg_get_statisticsextdef</primary>
+ </indexterm>
+
+ <indexterm>
<primary>pg_get_triggerdef</primary>
</indexterm>
@@ -16587,6 +16591,11 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
uses</entry>
</row>
<row>
+ <entry><literal><function>pg_get_statisticsextdef(<parameter>statext_oid</parameter>)</function></literal></entry>
+ <entry><type>text</type></entry>
+ <entry>get <command>CREATE STATISTICS</> command for extended statistics objects</entry>
+ </row>
+ <row>
<entry><function>pg_get_triggerdef</function>(<parameter>trigger_oid</parameter>)</entry>
<entry><type>text</type></entry>
<entry>get <command>CREATE [ CONSTRAINT ] TRIGGER</> command for trigger</entry>
@@ -16730,20 +16739,22 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
<para>
<function>pg_get_constraintdef</function>,
- <function>pg_get_indexdef</function>, <function>pg_get_ruledef</function>,
- and <function>pg_get_triggerdef</function>, respectively reconstruct the
- creating command for a constraint, index, rule, or trigger. (Note that this
- is a decompiled reconstruction, not the original text of the command.)
- <function>pg_get_expr</function> decompiles the internal form of an
- individual expression, such as the default value for a column. It can be
- useful when examining the contents of system catalogs. If the expression
- might contain Vars, specify the OID of the relation they refer to as the
- second parameter; if no Vars are expected, zero is sufficient.
- <function>pg_get_viewdef</function> reconstructs the <command>SELECT</>
- query that defines a view. Most of these functions come in two variants,
- one of which can optionally <quote>pretty-print</> the result. The
- pretty-printed format is more readable, but the default format is more
- likely to be interpreted the same way by future versions of
+ <function>pg_get_indexdef</function>,
+ <function>pg_get_statisticsextdef</function>,
+ <function>pg_get_ruledef</function>, and
+ <function>pg_get_triggerdef</function>, respectively reconstruct the
+ creating command for a constraint, index, extended statistics object, rule,
+ or trigger. (Note that this is a decompiled reconstruction, not the
+ original text of the command.) <function>pg_get_expr</function> decompiles
+ the internal form of an individual expression, such as the default value
+ for a column. It can be useful when examining the contents of system
+ catalogs. If the expression might contain Vars, specify the OID of the
+ relation they refer to as the second parameter; if no Vars are expected,
+ zero is sufficient. <function>pg_get_viewdef</function> reconstructs the
+ <command>SELECT</> query that defines a view. Most of these functions come
+ in two variants, one of which can optionally <quote>pretty-print</> the
+ result. The pretty-printed format is more readable, but the default format
+ is more likely to be interpreted the same way by future versions of
<productname>PostgreSQL</>; avoid using pretty-printed output for dump
purposes. Passing <literal>false</> for the pretty-print parameter yields
the same result as the variant that does not have the parameter at all.
diff --git a/doc/src/sgml/ref/comment.sgml b/doc/src/sgml/ref/comment.sgml
index c1cf587..d94bc85 100644
--- a/doc/src/sgml/ref/comment.sgml
+++ b/doc/src/sgml/ref/comment.sgml
@@ -51,6 +51,7 @@ COMMENT ON
SCHEMA <replaceable class="PARAMETER">object_name</replaceable> |
SEQUENCE <replaceable class="PARAMETER">object_name</replaceable> |
SERVER <replaceable class="PARAMETER">object_name</replaceable> |
+ STATISTICS <replaceable class="PARAMETER">object_name</replaceable> |
TABLE <replaceable class="PARAMETER">object_name</replaceable> |
TABLESPACE <replaceable class="PARAMETER">object_name</replaceable> |
TEXT SEARCH CONFIGURATION <replaceable class="PARAMETER">object_name</replaceable> |
@@ -125,8 +126,8 @@ COMMENT ON
The name of the object to be commented. Names of tables,
aggregates, collations, conversions, domains, foreign tables, functions,
indexes, operators, operator classes, operator families, sequences,
- text search objects, types, and views can be schema-qualified.
- When commenting on a column,
+ statistics, text search objects, types, and views can be
+ schema-qualified. When commenting on a column,
<replaceable class="parameter">relation_name</replaceable> must refer
to a table, view, composite type, or foreign table.
</para>
@@ -327,6 +328,7 @@ COMMENT ON RULE my_rule ON my_table IS 'Logs updates of employee records';
COMMENT ON SCHEMA my_schema IS 'Departmental data';
COMMENT ON SEQUENCE my_sequence IS 'Used to generate primary keys';
COMMENT ON SERVER myserver IS 'my foreign server';
+COMMENT ON STATISTICS my_statistics IS 'Improves planner row estimations';
COMMENT ON TABLE my_schema.my_table IS 'Employee Information';
COMMENT ON TABLESPACE my_tablespace IS 'Tablespace for indexes';
COMMENT ON TEXT SEARCH CONFIGURATION my_config IS 'Special word filtering';
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index a755646..2ca8e75 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -6197,7 +6197,7 @@ opt_restart_seqs:
* EXTENSION | EVENT TRIGGER | FOREIGN DATA WRAPPER |
* FOREIGN TABLE | INDEX | [PROCEDURAL] LANGUAGE |
* MATERIALIZED VIEW | POLICY | ROLE | SCHEMA | SEQUENCE |
- * SERVER | TABLE | TABLESPACE |
+ * SERVER | STATISTICS | TABLE | TABLESPACE |
* TEXT SEARCH CONFIGURATION | TEXT SEARCH DICTIONARY |
* TEXT SEARCH PARSER | TEXT SEARCH TEMPLATE | TYPE |
* VIEW] <objname> |
@@ -6384,6 +6384,7 @@ comment_type:
| SCHEMA { $$ = OBJECT_SCHEMA; }
| INDEX { $$ = OBJECT_INDEX; }
| SEQUENCE { $$ = OBJECT_SEQUENCE; }
+ | STATISTICS { $$ = OBJECT_STATISTICS; }
| TABLE { $$ = OBJECT_TABLE; }
| VIEW { $$ = OBJECT_VIEW; }
| MATERIALIZED VIEW { $$ = OBJECT_MATVIEW; }
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index b27b77d..680aef9 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -35,6 +35,7 @@
#include "catalog/pg_operator.h"
#include "catalog/pg_partitioned_table.h"
#include "catalog/pg_proc.h"
+#include "catalog/pg_statistic_ext.h"
#include "catalog/pg_trigger.h"
#include "catalog/pg_type.h"
#include "commands/defrem.h"
@@ -317,6 +318,7 @@ static char *pg_get_indexdef_worker(Oid indexrelid, int colno,
const Oid *excludeOps,
bool attrsOnly, bool showTblSpc,
int prettyFlags, bool missing_ok);
+static char *pg_get_statisticsext_worker(Oid statextid, bool missing_ok);
static char *pg_get_partkeydef_worker(Oid relid, int prettyFlags);
static char *pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
int prettyFlags, bool missing_ok);
@@ -1419,6 +1421,85 @@ pg_get_indexdef_worker(Oid indexrelid, int colno,
}
/*
+ * pg_get_statisticsextdef
+ * Get the definition of an extended statistics object
+ */
+Datum
+pg_get_statisticsextdef(PG_FUNCTION_ARGS)
+{
+ Oid statextid = PG_GETARG_OID(0);
+ char *res;
+
+ res = pg_get_statisticsext_worker(statextid, true);
+
+ if (res == NULL)
+ PG_RETURN_NULL();
+
+ PG_RETURN_TEXT_P(string_to_text(res));
+}
+
+/*
+ * Internal workhorse to decompile an extended statistics object.
+ */
+static char *
+pg_get_statisticsext_worker(Oid statextid, bool missing_ok)
+{
+ Form_pg_statistic_ext statextrec;
+ Form_pg_class pgclassrec;
+ HeapTuple statexttup;
+ HeapTuple pgclasstup;
+ StringInfoData buf;
+ int colno;
+
+ statexttup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(statextid));
+
+ if (!HeapTupleIsValid(statexttup))
+ {
+ if (missing_ok)
+ return NULL;
+ elog(ERROR, "cache lookup failed for extended statistics %u", statextid);
+ }
+
+ statextrec = (Form_pg_statistic_ext) GETSTRUCT(statexttup);
+
+ pgclasstup = SearchSysCache1(RELOID, ObjectIdGetDatum(statextrec->starelid));
+
+ if (!HeapTupleIsValid(statexttup))
+ {
+ ReleaseSysCache(statexttup);
+ elog(ERROR, "cache lookup failed for relation %u", statextrec->starelid);
+ }
+
+ pgclassrec = (Form_pg_class) GETSTRUCT(pgclasstup);
+
+ initStringInfo(&buf);
+
+ appendStringInfo(&buf, "CREATE STATISTICS %s ON (",
+ quote_identifier(NameStr(statextrec->staname)));
+
+ for (colno = 0; colno < statextrec->stakeys.dim1; colno++)
+ {
+ AttrNumber attnum = statextrec->stakeys.values[colno];
+ char *attname;
+
+ if (colno > 0)
+ appendStringInfoString(&buf, ", ");
+
+ attname = get_relid_attribute_name(statextrec->starelid, attnum);
+
+ appendStringInfoString(&buf, attname);
+ }
+
+ appendStringInfo(&buf, ") FROM %s",
+ quote_identifier(NameStr(pgclassrec->relname)));
+
+ ReleaseSysCache(statexttup);
+ ReleaseSysCache(pgclasstup);
+
+ return buf.data;
+}
+
+/*
* pg_get_partkeydef
*
* Returns the partition key specification, ie, the following:
diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c
index 89530a9..e2bc357 100644
--- a/src/bin/pg_dump/common.c
+++ b/src/bin/pg_dump/common.c
@@ -273,6 +273,10 @@ getSchemaData(Archive *fout, int *numTablesPtr)
getIndexes(fout, tblinfo, numTables);
if (g_verbose)
+ write_msg(NULL, "reading extended statistics\n");
+ getExtendedStatistics(fout, tblinfo, numTables);
+
+ if (g_verbose)
write_msg(NULL, "reading constraints\n");
getConstraints(fout, tblinfo, numTables);
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 7273ec8..0ab2cc6 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -190,6 +190,7 @@ static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
static void dumpSequence(Archive *fout, TableInfo *tbinfo);
static void dumpSequenceData(Archive *fout, TableDataInfo *tdinfo);
static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
+static void dumpStatisticsExt(Archive *fout, StatsExtInfo *statsextinfo);
static void dumpConstraint(Archive *fout, ConstraintInfo *coninfo);
static void dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo);
static void dumpTSParser(Archive *fout, TSParserInfo *prsinfo);
@@ -6507,6 +6508,100 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
}
/*
+ * getExtendedStatistics
+ * get information about extended statistics on a dumpable table
+ * or materialized view.
+ *
+ * Note: extended statistics data is not returned directly to the caller, but
+ * it does get entered into the DumpableObject tables.
+ */
+void
+getExtendedStatistics(Archive *fout, TableInfo tblinfo[], int numTables)
+{
+ int i,
+ j;
+ PQExpBuffer query;
+ PGresult *res;
+ StatsExtInfo *statsextinfo;
+ int ntups;
+ int i_tableoid;
+ int i_oid;
+ int i_staname;
+ int i_stadef;
+
+ /* Extended statistics were new in v10 */
+ if (fout->remoteVersion < 100000)
+ return;
+
+ query = createPQExpBuffer();
+
+ for (i = 0; i < numTables; i++)
+ {
+ TableInfo *tbinfo = &tblinfo[i];
+
+ /* Only plain tables and materialized views can have extended statistics. */
+ /* XXX ensure this is true. It was broken in v25 0002 */
+ if (tbinfo->relkind != RELKIND_RELATION &&
+ tbinfo->relkind != RELKIND_MATVIEW)
+ continue;
+
+ /*
+ * Ignore extended statistics of tables whose definitions are not to
+ * be dumped.
+ */
+ if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
+ continue;
+
+ if (g_verbose)
+ write_msg(NULL, "reading extended statistics for table \"%s.%s\"\n",
+ tbinfo->dobj.namespace->dobj.name,
+ tbinfo->dobj.name);
+
+ /* Make sure we are in proper schema so stadef is right */
+ selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
+
+ resetPQExpBuffer(query);
+
+ appendPQExpBuffer(query,
+ "SELECT "
+ "tableoid, "
+ "oid, "
+ "staname, "
+ "pg_catalog.pg_get_statisticsextdef(oid) AS stadef "
+ "FROM pg_statistic_ext "
+ "WHERE starelid = '%u' "
+ "ORDER BY staname", tbinfo->dobj.catId.oid);
+
+ res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
+
+ ntups = PQntuples(res);
+
+ i_tableoid = PQfnumber(res, "tableoid");
+ i_oid = PQfnumber(res, "oid");
+ i_staname = PQfnumber(res, "staname");
+ i_stadef = PQfnumber(res, "stadef");
+
+ statsextinfo = (StatsExtInfo *) pg_malloc(ntups * sizeof(StatsExtInfo));
+
+ for (j = 0; j < ntups; j++)
+ {
+ statsextinfo[j].dobj.objType = DO_STATSEXT;
+ statsextinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
+ statsextinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
+ AssignDumpId(&statsextinfo[j].dobj);
+ statsextinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_staname));
+ statsextinfo[j].dobj.namespace = tbinfo->dobj.namespace;
+ statsextinfo[j].statsexttable = tbinfo;
+ statsextinfo[j].statsextdef = pg_strdup(PQgetvalue(res, j, i_stadef));
+ }
+
+ PQclear(res);
+ }
+
+ destroyPQExpBuffer(query);
+}
+
+/*
* getConstraints
*
* Get info about constraints on dumpable tables.
@@ -9157,6 +9252,9 @@ dumpDumpableObject(Archive *fout, DumpableObject *dobj)
case DO_INDEX:
dumpIndex(fout, (IndxInfo *) dobj);
break;
+ case DO_STATSEXT:
+ dumpStatisticsExt(fout, (StatsExtInfo *) dobj);
+ break;
case DO_REFRESH_MATVIEW:
refreshMatViewData(fout, (TableDataInfo *) dobj);
break;
@@ -15596,6 +15694,61 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo)
}
/*
+ * dumpStatisticsExt
+ * write out to fout an extended statistics object
+ */
+static void
+dumpStatisticsExt(Archive *fout, StatsExtInfo *statsextinfo)
+{
+ DumpOptions *dopt = fout->dopt;
+ TableInfo *tbinfo = statsextinfo->statsexttable;
+ PQExpBuffer q;
+ PQExpBuffer delq;
+ PQExpBuffer labelq;
+
+ if (dopt->dataOnly)
+ return;
+
+ q = createPQExpBuffer();
+ delq = createPQExpBuffer();
+ labelq = createPQExpBuffer();
+
+ appendPQExpBuffer(labelq, "STATISTICS %s",
+ fmtId(statsextinfo->dobj.name));
+
+ appendPQExpBuffer(q, "%s;\n", statsextinfo->statsextdef);
+
+ appendPQExpBuffer(delq, "DROP STATISTICS %s.",
+ fmtId(tbinfo->dobj.namespace->dobj.name));
+ appendPQExpBuffer(delq, "%s;\n",
+ fmtId(statsextinfo->dobj.name));
+
+ if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+ ArchiveEntry(fout, statsextinfo->dobj.catId,
+ statsextinfo->dobj.dumpId,
+ statsextinfo->dobj.name,
+ tbinfo->dobj.namespace->dobj.name,
+ NULL,
+ tbinfo->rolname, false,
+ "STATISTICS", SECTION_POST_DATA,
+ q->data, delq->data, NULL,
+ NULL, 0,
+ NULL, NULL);
+
+ /* Dump Statistics Comments */
+ if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+ dumpComment(fout, labelq->data,
+ tbinfo->dobj.namespace->dobj.name,
+ tbinfo->rolname,
+ statsextinfo->dobj.catId, 0,
+ statsextinfo->dobj.dumpId);
+
+ destroyPQExpBuffer(q);
+ destroyPQExpBuffer(delq);
+ destroyPQExpBuffer(labelq);
+}
+
+/*
* dumpConstraint
* write out to fout a user-defined constraint
*/
@@ -17133,6 +17286,7 @@ addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
addObjectDependency(postDataBound, dobj->dumpId);
break;
case DO_INDEX:
+ case DO_STATSEXT:
case DO_REFRESH_MATVIEW:
case DO_TRIGGER:
case DO_EVENT_TRIGGER:
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index a466527..cb22f63 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -56,6 +56,7 @@ typedef enum
DO_TABLE,
DO_ATTRDEF,
DO_INDEX,
+ DO_STATSEXT,
DO_RULE,
DO_TRIGGER,
DO_CONSTRAINT,
@@ -362,6 +363,13 @@ typedef struct _indxInfo
int relpages; /* relpages of the underlying table */
} IndxInfo;
+typedef struct _statsExtInfo
+{
+ DumpableObject dobj;
+ TableInfo *statsexttable; /* link to table the stats ext is for */
+ char *statsextdef;
+} StatsExtInfo;
+
typedef struct _ruleInfo
{
DumpableObject dobj;
@@ -682,6 +690,7 @@ extern void getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables);
extern InhInfo *getInherits(Archive *fout, int *numInherits);
extern PartInfo *getPartitions(Archive *fout, int *numPartitions);
extern void getIndexes(Archive *fout, TableInfo tblinfo[], int numTables);
+extern void getExtendedStatistics(Archive *fout, TableInfo tblinfo[], int numTables);
extern void getConstraints(Archive *fout, TableInfo tblinfo[], int numTables);
extern RuleInfo *getRules(Archive *fout, int *numRules);
extern void getTriggers(Archive *fout, TableInfo tblinfo[], int numTables);
diff --git a/src/bin/pg_dump/pg_dump_sort.c b/src/bin/pg_dump/pg_dump_sort.c
index ea64339..9ca58cc 100644
--- a/src/bin/pg_dump/pg_dump_sort.c
+++ b/src/bin/pg_dump/pg_dump_sort.c
@@ -48,10 +48,11 @@ static const int dbObjectTypePriority[] =
18, /* DO_TABLE */
20, /* DO_ATTRDEF */
28, /* DO_INDEX */
- 29, /* DO_RULE */
- 30, /* DO_TRIGGER */
+ 29, /* DO_STATSEXT */
+ 30, /* DO_RULE */
+ 31, /* DO_TRIGGER */
27, /* DO_CONSTRAINT */
- 31, /* DO_FK_CONSTRAINT */
+ 32, /* DO_FK_CONSTRAINT */
2, /* DO_PROCLANG */
10, /* DO_CAST */
23, /* DO_TABLE_DATA */
@@ -63,18 +64,18 @@ static const int dbObjectTypePriority[] =
15, /* DO_TSCONFIG */
16, /* DO_FDW */
17, /* DO_FOREIGN_SERVER */
- 32, /* DO_DEFAULT_ACL */
+ 33, /* DO_DEFAULT_ACL */
3, /* DO_TRANSFORM */
21, /* DO_BLOB */
25, /* DO_BLOB_DATA */
22, /* DO_PRE_DATA_BOUNDARY */
26, /* DO_POST_DATA_BOUNDARY */
- 33, /* DO_EVENT_TRIGGER */
- 34, /* DO_REFRESH_MATVIEW */
- 35, /* DO_POLICY */
- 36, /* DO_PUBLICATION */
- 37, /* DO_PUBLICATION_REL */
- 38 /* DO_SUBSCRIPTION */
+ 34, /* DO_EVENT_TRIGGER */
+ 35, /* DO_REFRESH_MATVIEW */
+ 36, /* DO_POLICY */
+ 37, /* DO_PUBLICATION */
+ 38, /* DO_PUBLICATION_REL */
+ 39 /* DO_SUBSCRIPTION */
};
static DumpId preDataBoundId;
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 9bdeef0..340f1e5 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -1981,6 +1981,8 @@ DESCR("select statement of a view");
DATA(insert OID = 1642 ( pg_get_userbyid PGNSP PGUID 12 1 0 0 0 f f f f t f s s 1 0 19 "26" _null_ _null_ _null_ _null_ _null_ pg_get_userbyid _null_ _null_ _null_ ));
DESCR("role name by OID (with fallback)");
DATA(insert OID = 1643 ( pg_get_indexdef PGNSP PGUID 12 1 0 0 0 f f f f t f s s 1 0 25 "26" _null_ _null_ _null_ _null_ _null_ pg_get_indexdef _null_ _null_ _null_ ));
+DESCR("extended statistics description");
+DATA(insert OID = 3353 ( pg_get_statisticsextdef PGNSP PGUID 12 1 0 0 0 f f f f t f s s 1 0 25 "26" _null_ _null_ _null_ _null_ _null_ pg_get_statisticsextdef _null_ _null_ _null_ ));
DESCR("index description");
DATA(insert OID = 3352 ( pg_get_partkeydef PGNSP PGUID 12 1 0 0 0 f f f f t f s s 1 0 25 "26" _null_ _null_ _null_ _null_ _null_ pg_get_partkeydef _null_ _null_ _null_ ));
DESCR("partition key description");