From 9cd4b4e0e280d0fd8cb120ac105d6e65a491cd7e Mon Sep 17 00:00:00 2001 From: Corey Huinker Date: Tue, 4 Mar 2025 22:16:52 -0500 Subject: [PATCH v7 1/2] Split relation into schemaname and relname. In order to further reduce potential error-failures in restores and upgrades, replace the numerous casts of fully qualified relation names into their schema+relname text components. Further remove the ::name casts on attname and change the expected datatype to text. Add an ACL_USAGE check on the namespace oid after it is looked up. --- src/include/catalog/pg_proc.dat | 8 +- src/include/statistics/stat_utils.h | 2 + src/backend/statistics/attribute_stats.c | 87 ++++-- src/backend/statistics/relation_stats.c | 65 +++-- src/backend/statistics/stat_utils.c | 37 +++ src/bin/pg_dump/pg_dump.c | 25 +- src/bin/pg_dump/t/002_pg_dump.pl | 6 +- src/test/regress/expected/stats_import.out | 307 +++++++++++++-------- src/test/regress/sql/stats_import.sql | 276 +++++++++++------- doc/src/sgml/func.sgml | 41 +-- 10 files changed, 566 insertions(+), 288 deletions(-) diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index cede992b6e2..fdd4b8d7dba 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -12443,8 +12443,8 @@ descr => 'clear statistics on relation', proname => 'pg_clear_relation_stats', provolatile => 'v', proisstrict => 'f', proparallel => 'u', prorettype => 'void', - proargtypes => 'regclass', - proargnames => '{relation}', + proargtypes => 'text text', + proargnames => '{schemaname,relname}', prosrc => 'pg_clear_relation_stats' }, { oid => '8461', descr => 'restore statistics on attribute', @@ -12459,8 +12459,8 @@ descr => 'clear statistics on attribute', proname => 'pg_clear_attribute_stats', provolatile => 'v', proisstrict => 'f', proparallel => 'u', prorettype => 'void', - proargtypes => 'regclass name bool', - proargnames => '{relation,attname,inherited}', + proargtypes => 'text text text bool', + proargnames => '{schemaname,relname,attname,inherited}', prosrc => 'pg_clear_attribute_stats' }, # GiST stratnum implementations diff --git a/src/include/statistics/stat_utils.h b/src/include/statistics/stat_utils.h index 0eb4decfcac..cad042c8e4a 100644 --- a/src/include/statistics/stat_utils.h +++ b/src/include/statistics/stat_utils.h @@ -32,6 +32,8 @@ extern bool stats_check_arg_pair(FunctionCallInfo fcinfo, extern void stats_lock_check_privileges(Oid reloid); +extern Oid stats_schema_check_privileges(const char *nspname); + extern bool stats_fill_fcinfo_from_arg_pairs(FunctionCallInfo pairs_fcinfo, FunctionCallInfo positional_fcinfo, struct StatsArgInfo *arginfo); diff --git a/src/backend/statistics/attribute_stats.c b/src/backend/statistics/attribute_stats.c index 6bcbee0edba..f87db2d6102 100644 --- a/src/backend/statistics/attribute_stats.c +++ b/src/backend/statistics/attribute_stats.c @@ -36,7 +36,8 @@ enum attribute_stats_argnum { - ATTRELATION_ARG = 0, + ATTRELSCHEMA_ARG = 0, + ATTRELNAME_ARG, ATTNAME_ARG, ATTNUM_ARG, INHERITED_ARG, @@ -58,8 +59,9 @@ enum attribute_stats_argnum static struct StatsArgInfo attarginfo[] = { - [ATTRELATION_ARG] = {"relation", REGCLASSOID}, - [ATTNAME_ARG] = {"attname", NAMEOID}, + [ATTRELSCHEMA_ARG] = {"schemaname", TEXTOID}, + [ATTRELNAME_ARG] = {"relname", TEXTOID}, + [ATTNAME_ARG] = {"attname", TEXTOID}, [ATTNUM_ARG] = {"attnum", INT2OID}, [INHERITED_ARG] = {"inherited", BOOLOID}, [NULL_FRAC_ARG] = {"null_frac", FLOAT4OID}, @@ -80,7 +82,8 @@ static struct StatsArgInfo attarginfo[] = enum clear_attribute_stats_argnum { - C_ATTRELATION_ARG = 0, + C_ATTRELSCHEMA_ARG = 0, + C_ATTRELNAME_ARG, C_ATTNAME_ARG, C_INHERITED_ARG, C_NUM_ATTRIBUTE_STATS_ARGS @@ -88,8 +91,9 @@ enum clear_attribute_stats_argnum static struct StatsArgInfo cleararginfo[] = { - [C_ATTRELATION_ARG] = {"relation", REGCLASSOID}, - [C_ATTNAME_ARG] = {"attname", NAMEOID}, + [C_ATTRELSCHEMA_ARG] = {"relation", TEXTOID}, + [C_ATTRELNAME_ARG] = {"relation", TEXTOID}, + [C_ATTNAME_ARG] = {"attname", TEXTOID}, [C_INHERITED_ARG] = {"inherited", BOOLOID}, [C_NUM_ATTRIBUTE_STATS_ARGS] = {0} }; @@ -133,6 +137,9 @@ static void init_empty_stats_tuple(Oid reloid, int16 attnum, bool inherited, static bool attribute_statistics_update(FunctionCallInfo fcinfo) { + char *nspname; + Oid nspoid; + char *relname; Oid reloid; char *attname; AttrNumber attnum; @@ -170,8 +177,23 @@ attribute_statistics_update(FunctionCallInfo fcinfo) bool result = true; - stats_check_required_arg(fcinfo, attarginfo, ATTRELATION_ARG); - reloid = PG_GETARG_OID(ATTRELATION_ARG); + stats_check_required_arg(fcinfo, attarginfo, ATTRELSCHEMA_ARG); + stats_check_required_arg(fcinfo, attarginfo, ATTRELNAME_ARG); + + nspname = TextDatumGetCString(PG_GETARG_DATUM(ATTRELSCHEMA_ARG)); + nspoid = stats_schema_check_privileges(nspname); + if (nspoid == InvalidOid) + return false; + + relname = TextDatumGetCString(PG_GETARG_DATUM(ATTRELNAME_ARG)); + reloid = get_relname_relid(relname, nspoid); + if (reloid == InvalidOid) + { + ereport(WARNING, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("Relation \"%s\".\"%s\" not found.", nspname, relname))); + return false; + } if (RecoveryInProgress()) ereport(ERROR, @@ -185,21 +207,18 @@ attribute_statistics_update(FunctionCallInfo fcinfo) /* user can specify either attname or attnum, but not both */ if (!PG_ARGISNULL(ATTNAME_ARG)) { - Name attnamename; - if (!PG_ARGISNULL(ATTNUM_ARG)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("cannot specify both attname and attnum"))); - attnamename = PG_GETARG_NAME(ATTNAME_ARG); - attname = NameStr(*attnamename); + attname = TextDatumGetCString(PG_GETARG_DATUM(ATTNAME_ARG)); attnum = get_attnum(reloid, attname); /* note that this test covers attisdropped cases too: */ if (attnum == InvalidAttrNumber) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), - errmsg("column \"%s\" of relation \"%s\" does not exist", - attname, get_rel_name(reloid)))); + errmsg("column \"%s\" of relation \"%s\".\"%s\" does not exist", + attname, nspname, relname))); } else if (!PG_ARGISNULL(ATTNUM_ARG)) { @@ -210,8 +229,8 @@ attribute_statistics_update(FunctionCallInfo fcinfo) !SearchSysCacheExistsAttName(reloid, attname)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), - errmsg("column %d of relation \"%s\" does not exist", - attnum, get_rel_name(reloid)))); + errmsg("column %d of relation \"%s\".\"%s\" does not exist", + attnum, nspname, relname))); } else { @@ -900,13 +919,33 @@ init_empty_stats_tuple(Oid reloid, int16 attnum, bool inherited, Datum pg_clear_attribute_stats(PG_FUNCTION_ARGS) { + char *nspname; + Oid nspoid; + char *relname; Oid reloid; - Name attname; + char *attname; AttrNumber attnum; bool inherited; - stats_check_required_arg(fcinfo, cleararginfo, C_ATTRELATION_ARG); - reloid = PG_GETARG_OID(C_ATTRELATION_ARG); + stats_check_required_arg(fcinfo, cleararginfo, C_ATTRELSCHEMA_ARG); + stats_check_required_arg(fcinfo, cleararginfo, C_ATTRELNAME_ARG); + stats_check_required_arg(fcinfo, cleararginfo, C_ATTNAME_ARG); + stats_check_required_arg(fcinfo, cleararginfo, C_INHERITED_ARG); + + nspname = TextDatumGetCString(PG_GETARG_DATUM(C_ATTRELSCHEMA_ARG)); + nspoid = stats_schema_check_privileges(nspname); + if (!OidIsValid(nspoid)) + return false; + + relname = TextDatumGetCString(PG_GETARG_DATUM(C_ATTRELNAME_ARG)); + reloid = get_relname_relid(relname, nspoid); + if (!OidIsValid(reloid)) + { + ereport(WARNING, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("Relation \"%s\".\"%s\" not found.", nspname, relname))); + return false; + } if (RecoveryInProgress()) ereport(ERROR, @@ -916,23 +955,21 @@ pg_clear_attribute_stats(PG_FUNCTION_ARGS) stats_lock_check_privileges(reloid); - stats_check_required_arg(fcinfo, cleararginfo, C_ATTNAME_ARG); - attname = PG_GETARG_NAME(C_ATTNAME_ARG); - attnum = get_attnum(reloid, NameStr(*attname)); + attname = TextDatumGetCString(PG_GETARG_DATUM(C_ATTNAME_ARG)); + attnum = get_attnum(reloid, attname); if (attnum < 0) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot clear statistics on system column \"%s\"", - NameStr(*attname)))); + attname))); if (attnum == InvalidAttrNumber) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("column \"%s\" of relation \"%s\" does not exist", - NameStr(*attname), get_rel_name(reloid)))); + attname, get_rel_name(reloid)))); - stats_check_required_arg(fcinfo, cleararginfo, C_INHERITED_ARG); inherited = PG_GETARG_BOOL(C_INHERITED_ARG); delete_pg_statistic(reloid, attnum, inherited); diff --git a/src/backend/statistics/relation_stats.c b/src/backend/statistics/relation_stats.c index 52dfa477187..fdc69bc93e2 100644 --- a/src/backend/statistics/relation_stats.c +++ b/src/backend/statistics/relation_stats.c @@ -19,9 +19,12 @@ #include "access/heapam.h" #include "catalog/indexing.h" +#include "catalog/namespace.h" #include "statistics/stat_utils.h" +#include "utils/builtins.h" #include "utils/fmgroids.h" #include "utils/fmgrprotos.h" +#include "utils/lsyscache.h" #include "utils/syscache.h" @@ -32,7 +35,8 @@ enum relation_stats_argnum { - RELATION_ARG = 0, + RELSCHEMA_ARG = 0, + RELNAME_ARG, RELPAGES_ARG, RELTUPLES_ARG, RELALLVISIBLE_ARG, @@ -42,7 +46,8 @@ enum relation_stats_argnum static struct StatsArgInfo relarginfo[] = { - [RELATION_ARG] = {"relation", REGCLASSOID}, + [RELSCHEMA_ARG] = {"schemaname", TEXTOID}, + [RELNAME_ARG] = {"relname", TEXTOID}, [RELPAGES_ARG] = {"relpages", INT4OID}, [RELTUPLES_ARG] = {"reltuples", FLOAT4OID}, [RELALLVISIBLE_ARG] = {"relallvisible", INT4OID}, @@ -59,6 +64,9 @@ static bool relation_statistics_update(FunctionCallInfo fcinfo) { bool result = true; + char *nspname; + Oid nspoid; + char *relname; Oid reloid; Relation crel; BlockNumber relpages = 0; @@ -76,6 +84,32 @@ relation_statistics_update(FunctionCallInfo fcinfo) bool nulls[4] = {0}; int nreplaces = 0; + stats_check_required_arg(fcinfo, relarginfo, RELSCHEMA_ARG); + stats_check_required_arg(fcinfo, relarginfo, RELNAME_ARG); + + nspname = TextDatumGetCString(PG_GETARG_DATUM(RELSCHEMA_ARG)); + nspoid = stats_schema_check_privileges(nspname); + if (!OidIsValid(nspoid)) + return false; + + relname = TextDatumGetCString(PG_GETARG_DATUM(RELNAME_ARG)); + reloid = get_relname_relid(relname, nspoid); + if (!OidIsValid(reloid)) + { + ereport(WARNING, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("Relation \"%s\".\"%s\" not found.", nspname, relname))); + return false; + } + + if (RecoveryInProgress()) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("recovery is in progress"), + errhint("Statistics cannot be modified during recovery."))); + + stats_lock_check_privileges(reloid); + if (!PG_ARGISNULL(RELPAGES_ARG)) { relpages = PG_GETARG_UINT32(RELPAGES_ARG); @@ -108,17 +142,6 @@ relation_statistics_update(FunctionCallInfo fcinfo) update_relallfrozen = true; } - stats_check_required_arg(fcinfo, relarginfo, RELATION_ARG); - reloid = PG_GETARG_OID(RELATION_ARG); - - if (RecoveryInProgress()) - ereport(ERROR, - (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("recovery is in progress"), - errhint("Statistics cannot be modified during recovery."))); - - stats_lock_check_privileges(reloid); - /* * Take RowExclusiveLock on pg_class, consistent with * vac_update_relstats(). @@ -187,20 +210,22 @@ relation_statistics_update(FunctionCallInfo fcinfo) Datum pg_clear_relation_stats(PG_FUNCTION_ARGS) { - LOCAL_FCINFO(newfcinfo, 5); + LOCAL_FCINFO(newfcinfo, 6); - InitFunctionCallInfoData(*newfcinfo, NULL, 5, InvalidOid, NULL, NULL); + InitFunctionCallInfoData(*newfcinfo, NULL, 6, InvalidOid, NULL, NULL); - newfcinfo->args[0].value = PG_GETARG_OID(0); + newfcinfo->args[0].value = PG_GETARG_DATUM(0); newfcinfo->args[0].isnull = PG_ARGISNULL(0); - newfcinfo->args[1].value = UInt32GetDatum(0); - newfcinfo->args[1].isnull = false; - newfcinfo->args[2].value = Float4GetDatum(-1.0); + newfcinfo->args[1].value = PG_GETARG_DATUM(1); + newfcinfo->args[1].isnull = PG_ARGISNULL(1); + newfcinfo->args[2].value = UInt32GetDatum(0); newfcinfo->args[2].isnull = false; - newfcinfo->args[3].value = UInt32GetDatum(0); + newfcinfo->args[3].value = Float4GetDatum(-1.0); newfcinfo->args[3].isnull = false; newfcinfo->args[4].value = UInt32GetDatum(0); newfcinfo->args[4].isnull = false; + newfcinfo->args[5].value = UInt32GetDatum(0); + newfcinfo->args[5].isnull = false; relation_statistics_update(newfcinfo); PG_RETURN_VOID(); diff --git a/src/backend/statistics/stat_utils.c b/src/backend/statistics/stat_utils.c index 9647f5108b3..e037d4994e8 100644 --- a/src/backend/statistics/stat_utils.c +++ b/src/backend/statistics/stat_utils.c @@ -18,7 +18,9 @@ #include "access/relation.h" #include "catalog/index.h" +#include "catalog/namespace.h" #include "catalog/pg_database.h" +#include "catalog/pg_namespace.h" #include "funcapi.h" #include "miscadmin.h" #include "statistics/stat_utils.h" @@ -213,6 +215,41 @@ stats_lock_check_privileges(Oid reloid) relation_close(table, NoLock); } + +/* + * Resolve a schema name into an Oid, ensure that the user has usage privs on + * that schema. + */ +Oid +stats_schema_check_privileges(const char *nspname) +{ + Oid nspoid; + AclResult aclresult; + + nspoid = get_namespace_oid(nspname, true); + + if (nspoid == InvalidOid) + { + ereport(WARNING, + (errcode(ERRCODE_INVALID_SCHEMA_NAME), + errmsg("schema %s does not exist", nspname))); + return InvalidOid; + } + + aclresult = object_aclcheck(NamespaceRelationId, nspoid, GetUserId(), ACL_USAGE); + + if (aclresult != ACLCHECK_OK) + { + ereport(WARNING, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied for schema %s", nspname))); + return InvalidOid; + } + + return nspoid; +} + + /* * Find the argument number for the given argument name, returning -1 if not * found. diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 4f4ad2ee150..6cf2c7d1fe4 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -10492,7 +10492,6 @@ dumpRelationStats(Archive *fout, const RelStatsInfo *rsinfo) PQExpBuffer out; DumpId *deps = NULL; int ndeps = 0; - char *qualified_name; char reltuples_str[FLOAT_SHORTEST_DECIMAL_LEN]; int i_attname; int i_inherited; @@ -10558,15 +10557,16 @@ dumpRelationStats(Archive *fout, const RelStatsInfo *rsinfo) out = createPQExpBuffer(); - qualified_name = pg_strdup(fmtQualifiedDumpable(rsinfo)); - /* restore relation stats */ appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_relation_stats(\n"); appendPQExpBuffer(out, "\t'version', '%u'::integer,\n", fout->remoteVersion); - appendPQExpBufferStr(out, "\t'relation', "); - appendStringLiteralAH(out, qualified_name, fout); - appendPQExpBufferStr(out, "::regclass,\n"); + appendPQExpBufferStr(out, "\t'schemaname', "); + appendStringLiteralAH(out, rsinfo->dobj.namespace->dobj.name, fout); + appendPQExpBufferStr(out, ",\n"); + appendPQExpBufferStr(out, "\t'relname', "); + appendStringLiteralAH(out, rsinfo->dobj.name, fout); + appendPQExpBufferStr(out, ",\n"); appendPQExpBuffer(out, "\t'relpages', '%d'::integer,\n", rsinfo->relpages); float_to_shortest_decimal_buf(rsinfo->reltuples, reltuples_str); appendPQExpBuffer(out, "\t'reltuples', '%s'::real,\n", reltuples_str); @@ -10606,9 +10606,10 @@ dumpRelationStats(Archive *fout, const RelStatsInfo *rsinfo) appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_attribute_stats(\n"); appendPQExpBuffer(out, "\t'version', '%u'::integer,\n", fout->remoteVersion); - appendPQExpBufferStr(out, "\t'relation', "); - appendStringLiteralAH(out, qualified_name, fout); - appendPQExpBufferStr(out, "::regclass"); + appendPQExpBufferStr(out, "\t'schemaname', "); + appendStringLiteralAH(out, rsinfo->dobj.namespace->dobj.name, fout); + appendPQExpBufferStr(out, ",\n\t'relname', "); + appendStringLiteralAH(out, rsinfo->dobj.name, fout); if (PQgetisnull(res, rownum, i_attname)) pg_fatal("attname cannot be NULL"); @@ -10620,7 +10621,10 @@ dumpRelationStats(Archive *fout, const RelStatsInfo *rsinfo) * their attnames are not necessarily stable across dump/reload. */ if (rsinfo->nindAttNames == 0) - appendNamedArgument(out, fout, "attname", "name", attname); + { + appendPQExpBuffer(out, ",\n\t'attname', "); + appendStringLiteralAH(out, attname, fout); + } else { bool found = false; @@ -10700,7 +10704,6 @@ dumpRelationStats(Archive *fout, const RelStatsInfo *rsinfo) .deps = deps, .nDeps = ndeps)); - free(qualified_name); destroyPQExpBuffer(out); destroyPQExpBuffer(query); } diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl index c7bffc1b045..b037f239136 100644 --- a/src/bin/pg_dump/t/002_pg_dump.pl +++ b/src/bin/pg_dump/t/002_pg_dump.pl @@ -4725,14 +4725,16 @@ my %tests = ( regexp => qr/^ \QSELECT * FROM pg_catalog.pg_restore_relation_stats(\E\s+ 'version',\s'\d+'::integer,\s+ - 'relation',\s'dump_test.dup_test_post_data_ix'::regclass,\s+ + 'schemaname',\s'dump_test',\s+ + 'relname',\s'dup_test_post_data_ix',\s+ 'relpages',\s'\d+'::integer,\s+ 'reltuples',\s'\d+'::real,\s+ 'relallvisible',\s'\d+'::integer\s+ \);\s+ \QSELECT * FROM pg_catalog.pg_restore_attribute_stats(\E\s+ 'version',\s'\d+'::integer,\s+ - 'relation',\s'dump_test.dup_test_post_data_ix'::regclass,\s+ + 'schemaname',\s'dump_test',\s+ + 'relname',\s'dup_test_post_data_ix',\s+ 'attnum',\s'2'::smallint,\s+ 'inherited',\s'f'::boolean,\s+ 'null_frac',\s'0'::real,\s+ diff --git a/src/test/regress/expected/stats_import.out b/src/test/regress/expected/stats_import.out index 1f46d5e7854..2f1295f2149 100644 --- a/src/test/regress/expected/stats_import.out +++ b/src/test/regress/expected/stats_import.out @@ -14,7 +14,8 @@ CREATE TABLE stats_import.test( ) WITH (autovacuum_enabled = false); SELECT pg_catalog.pg_restore_relation_stats( - 'relation', 'stats_import.test'::regclass, + 'schemaname', 'stats_import', + 'relname', 'test', 'relpages', 18::integer, 'reltuples', 21::real, 'relallvisible', 24::integer, @@ -36,7 +37,7 @@ ORDER BY relname; test | 18 | 21 | 24 | 27 (1 row) -SELECT pg_clear_relation_stats('stats_import.test'::regclass); +SELECT pg_clear_relation_stats('stats_import', 'test'); pg_clear_relation_stats ------------------------- @@ -45,33 +46,54 @@ SELECT pg_clear_relation_stats('stats_import.test'::regclass); -- -- relstats tests -- ---- error: relation is wrong type +-- error: schemaname missing SELECT pg_catalog.pg_restore_relation_stats( - 'relation', 0::oid, + 'relname', 'test', 'relpages', 17::integer); -WARNING: argument "relation" has type "oid", expected type "regclass" -ERROR: "relation" cannot be NULL +ERROR: "schemaname" cannot be NULL +-- error: relname missing +SELECT pg_catalog.pg_restore_relation_stats( + 'schemaname', 'stats_import', + 'relpages', 17::integer); +ERROR: "relname" cannot be NULL +--- error: schemaname is wrong type +SELECT pg_catalog.pg_restore_relation_stats( + 'schemaname', 3.6::float, + 'relname', 'test', + 'relpages', 17::integer); +WARNING: argument "schemaname" has type "double precision", expected type "text" +ERROR: "schemaname" cannot be NULL +--- error: relname is wrong type +SELECT pg_catalog.pg_restore_relation_stats( + 'schemaname', 'stats_import', + 'relname', 0::oid, + 'relpages', 17::integer); +WARNING: argument "relname" has type "oid", expected type "text" +ERROR: "relname" cannot be NULL -- error: relation not found SELECT pg_catalog.pg_restore_relation_stats( - 'relation', 0::oid::regclass, + 'schemaname', 'stats_import', + 'relname', 'nope', 'relpages', 17::integer); -ERROR: could not open relation with OID 0 +WARNING: Relation "stats_import"."nope" not found. + pg_restore_relation_stats +--------------------------- + f +(1 row) + -- error: odd number of variadic arguments cannot be pairs SELECT pg_restore_relation_stats( - 'relation', 'stats_import.test'::regclass, + 'schemaname', 'stats_import', + 'relname', 'test', 'relallvisible'); ERROR: variadic arguments must be name/value pairs HINT: Provide an even number of variadic arguments that can be divided into pairs. -- error: argument name is NULL SELECT pg_restore_relation_stats( - 'relation', 'stats_import.test'::regclass, + 'schemaname', 'stats_import', + 'relname', 'test', NULL, '17'::integer); -ERROR: name at variadic position 3 is NULL --- error: argument name is not a text type -SELECT pg_restore_relation_stats( - 'relation', '0'::oid::regclass, - 17, '17'::integer); -ERROR: name at variadic position 3 has type "integer", expected type "text" +ERROR: name at variadic position 5 is NULL -- starting stats SELECT relpages, reltuples, relallvisible, relallfrozen FROM pg_class @@ -84,7 +106,8 @@ WHERE oid = 'stats_import.test_i'::regclass; -- regular indexes have special case locking rules BEGIN; SELECT pg_catalog.pg_restore_relation_stats( - 'relation', 'stats_import.test_i'::regclass, + 'schemaname', 'stats_import', + 'relname', 'test_i', 'relpages', 18::integer); pg_restore_relation_stats --------------------------- @@ -132,7 +155,8 @@ WHERE oid = 'stats_import.part_parent'::regclass; -- BEGIN; SELECT pg_catalog.pg_restore_relation_stats( - 'relation', 'stats_import.part_parent_i'::regclass, + 'schemaname', 'stats_import', + 'relname', 'part_parent_i', 'relpages', 2::integer); pg_restore_relation_stats --------------------------- @@ -166,7 +190,8 @@ WHERE oid = 'stats_import.part_parent_i'::regclass; -- ok: set all relstats, with version, no bounds checking SELECT pg_restore_relation_stats( - 'relation', 'stats_import.test'::regclass, + 'schemaname', 'stats_import', + 'relname', 'test', 'version', 150000::integer, 'relpages', '-17'::integer, 'reltuples', 400::real, @@ -187,7 +212,8 @@ WHERE oid = 'stats_import.test'::regclass; -- ok: set just relpages, rest stay same SELECT pg_restore_relation_stats( - 'relation', 'stats_import.test'::regclass, + 'schemaname', 'stats_import', + 'relname', 'test', 'relpages', '16'::integer); pg_restore_relation_stats --------------------------- @@ -204,7 +230,8 @@ WHERE oid = 'stats_import.test'::regclass; -- ok: set just reltuples, rest stay same SELECT pg_restore_relation_stats( - 'relation', 'stats_import.test'::regclass, + 'schemaname', 'stats_import', + 'relname', 'test', 'reltuples', '500'::real); pg_restore_relation_stats --------------------------- @@ -221,7 +248,8 @@ WHERE oid = 'stats_import.test'::regclass; -- ok: set just relallvisible, rest stay same SELECT pg_restore_relation_stats( - 'relation', 'stats_import.test'::regclass, + 'schemaname', 'stats_import', + 'relname', 'test', 'relallvisible', 5::integer); pg_restore_relation_stats --------------------------- @@ -238,7 +266,8 @@ WHERE oid = 'stats_import.test'::regclass; -- ok: just relallfrozen SELECT pg_restore_relation_stats( - 'relation', 'stats_import.test'::regclass, + 'schemaname', 'stats_import', + 'relname', 'test', 'version', 150000::integer, 'relallfrozen', 3::integer); pg_restore_relation_stats @@ -256,7 +285,8 @@ WHERE oid = 'stats_import.test'::regclass; -- warn: bad relpages type, rest updated SELECT pg_restore_relation_stats( - 'relation', 'stats_import.test'::regclass, + 'schemaname', 'stats_import', + 'relname', 'test', 'relpages', 'nope'::text, 'reltuples', 400.0::real, 'relallvisible', 4::integer, @@ -277,7 +307,8 @@ WHERE oid = 'stats_import.test'::regclass; -- unrecognized argument name, rest ok SELECT pg_restore_relation_stats( - 'relation', 'stats_import.test'::regclass, + 'schemaname', 'stats_import', + 'relname', 'test', 'relpages', '171'::integer, 'nope', 10::integer); WARNING: unrecognized argument name: "nope" @@ -295,8 +326,7 @@ WHERE oid = 'stats_import.test'::regclass; (1 row) -- ok: clear stats -SELECT pg_catalog.pg_clear_relation_stats( - relation => 'stats_import.test'::regclass); +SELECT pg_catalog.pg_clear_relation_stats(schemaname => 'stats_import', relname => 'test'); pg_clear_relation_stats ------------------------- @@ -313,87 +343,123 @@ WHERE oid = 'stats_import.test'::regclass; -- invalid relkinds for statistics CREATE SEQUENCE stats_import.testseq; SELECT pg_catalog.pg_restore_relation_stats( - 'relation', 'stats_import.testseq'::regclass); + 'schemaname', 'stats_import', + 'relname', 'testseq'); ERROR: cannot modify statistics for relation "testseq" DETAIL: This operation is not supported for sequences. -SELECT pg_catalog.pg_clear_relation_stats( - 'stats_import.testseq'::regclass); +SELECT pg_catalog.pg_clear_relation_stats(schemaname => 'stats_import', relname => 'testseq'); ERROR: cannot modify statistics for relation "testseq" DETAIL: This operation is not supported for sequences. CREATE VIEW stats_import.testview AS SELECT * FROM stats_import.test; -SELECT pg_catalog.pg_restore_relation_stats( - 'relation', 'stats_import.testview'::regclass); -ERROR: cannot modify statistics for relation "testview" -DETAIL: This operation is not supported for views. -SELECT pg_catalog.pg_clear_relation_stats( - 'stats_import.testview'::regclass); +SELECT pg_catalog.pg_clear_relation_stats(schemaname => 'stats_import', relname => 'testview'); ERROR: cannot modify statistics for relation "testview" DETAIL: This operation is not supported for views. -- -- attribute stats -- --- error: object does not exist +-- error: schemaname missing SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', '0'::oid::regclass, - 'attname', 'id'::name, + 'relname', 'test', + 'attname', 'id', 'inherited', false::boolean, 'null_frac', 0.1::real); -ERROR: could not open relation with OID 0 --- error: relation null +ERROR: "schemaname" cannot be NULL +-- error: schema does not exist SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', NULL::oid::regclass, - 'attname', 'id'::name, + 'schemaname', 'nope', + 'relname', 'test', + 'attname', 'id', 'inherited', false::boolean, 'null_frac', 0.1::real); -ERROR: "relation" cannot be NULL +WARNING: schema nope does not exist + pg_restore_attribute_stats +---------------------------- + f +(1 row) + +-- error: relname missing +SELECT pg_catalog.pg_restore_attribute_stats( + 'schemaname', 'stats_import', + 'attname', 'id', + 'inherited', false::boolean, + 'null_frac', 0.1::real); +ERROR: "relname" cannot be NULL +-- error: relname does not exist +SELECT pg_catalog.pg_restore_attribute_stats( + 'schemaname', 'stats_import', + 'relname', 'nope', + 'attname', 'id', + 'inherited', false::boolean, + 'null_frac', 0.1::real); +WARNING: Relation "stats_import"."nope" not found. + pg_restore_attribute_stats +---------------------------- + f +(1 row) + +-- error: relname null +SELECT pg_catalog.pg_restore_attribute_stats( + 'schemaname', 'stats_import', + 'relname', NULL, + 'attname', 'id', + 'inherited', false::boolean, + 'null_frac', 0.1::real); +ERROR: "relname" cannot be NULL -- error: NULL attname SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', NULL::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', NULL, 'inherited', false::boolean, 'null_frac', 0.1::real); ERROR: must specify either attname or attnum -- error: attname doesn't exist SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'nope'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'nope', 'inherited', false::boolean, 'null_frac', 0.1::real, 'avg_width', 2::integer, 'n_distinct', 0.3::real); -ERROR: column "nope" of relation "test" does not exist +ERROR: column "nope" of relation "stats_import"."test" does not exist -- error: both attname and attnum SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'id'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', 'attnum', 1::smallint, 'inherited', false::boolean, 'null_frac', 0.1::real); ERROR: cannot specify both attname and attnum -- error: neither attname nor attnum SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, + 'schemaname', 'stats_import', + 'relname', 'test', 'inherited', false::boolean, 'null_frac', 0.1::real); ERROR: must specify either attname or attnum -- error: attribute is system column SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'xmin'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'xmin', 'inherited', false::boolean, 'null_frac', 0.1::real); ERROR: cannot modify statistics on system column "xmin" -- error: inherited null SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'id'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', 'inherited', NULL::boolean, 'null_frac', 0.1::real); ERROR: "inherited" cannot be NULL -- ok: just the fixed values, with version, no stakinds SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'id'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', 'inherited', false::boolean, 'version', 150000::integer, 'null_frac', 0.2::real, @@ -421,7 +487,8 @@ AND attname = 'id'; -- for any stat-having relation. -- SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, + 'schemaname', 'stats_import', + 'relname', 'test', 'attnum', 1::smallint, 'inherited', false::boolean, 'null_frac', 0.4::real); @@ -443,8 +510,9 @@ AND attname = 'id'; -- warn: unrecognized argument name, rest get set SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'id'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', 'inherited', false::boolean, 'null_frac', 0.2::real, 'nope', 0.5::real); @@ -467,8 +535,9 @@ AND attname = 'id'; -- warn: mcv / mcf null mismatch part 1, rest get set SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'id'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', 'inherited', false::boolean, 'null_frac', 0.21::real, 'most_common_freqs', '{0.1,0.2,0.3}'::real[] @@ -492,8 +561,9 @@ AND attname = 'id'; -- warn: mcv / mcf null mismatch part 2, rest get set SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'id'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', 'inherited', false::boolean, 'null_frac', 0.21::real, 'most_common_vals', '{1,2,3}'::text @@ -517,8 +587,9 @@ AND attname = 'id'; -- warn: mcf type mismatch, mcv-pair fails, rest get set SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'id'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', 'inherited', false::boolean, 'null_frac', 0.22::real, 'most_common_vals', '{2,1,3}'::text, @@ -544,8 +615,9 @@ AND attname = 'id'; -- warn: mcv cast failure, mcv-pair fails, rest get set SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'id'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', 'inherited', false::boolean, 'null_frac', 0.23::real, 'most_common_vals', '{2,four,3}'::text, @@ -570,8 +642,9 @@ AND attname = 'id'; -- ok: mcv+mcf SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'id'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', 'inherited', false::boolean, 'most_common_vals', '{2,1,3}'::text, 'most_common_freqs', '{0.3,0.25,0.05}'::real[] @@ -594,8 +667,9 @@ AND attname = 'id'; -- warn: NULL in histogram array, rest get set SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'id'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', 'inherited', false::boolean, 'null_frac', 0.24::real, 'histogram_bounds', '{1,NULL,3,4}'::text @@ -619,8 +693,9 @@ AND attname = 'id'; -- ok: histogram_bounds SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'id'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', 'inherited', false::boolean, 'histogram_bounds', '{1,2,3,4}'::text ); @@ -642,8 +717,9 @@ AND attname = 'id'; -- warn: elem_count_histogram null element, rest get set SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'tags'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'tags', 'inherited', false::boolean, 'null_frac', 0.25::real, 'elem_count_histogram', '{1,1,NULL,1,1,1,1,1}'::real[] @@ -667,8 +743,9 @@ AND attname = 'tags'; -- ok: elem_count_histogram SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'tags'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'tags', 'inherited', false::boolean, 'null_frac', 0.26::real, 'elem_count_histogram', '{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}'::real[] @@ -691,8 +768,9 @@ AND attname = 'tags'; -- warn: range stats on a scalar type, rest ok SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'id'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', 'inherited', false::boolean, 'null_frac', 0.27::real, 'range_empty_frac', 0.5::real, @@ -718,8 +796,9 @@ AND attname = 'id'; -- warn: range_empty_frac range_length_hist null mismatch, rest ok SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'arange'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'arange', 'inherited', false::boolean, 'null_frac', 0.28::real, 'range_length_histogram', '{399,499,Infinity}'::text @@ -743,8 +822,9 @@ AND attname = 'arange'; -- warn: range_empty_frac range_length_hist null mismatch part 2, rest ok SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'arange'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'arange', 'inherited', false::boolean, 'null_frac', 0.29::real, 'range_empty_frac', 0.5::real @@ -768,8 +848,9 @@ AND attname = 'arange'; -- ok: range_empty_frac + range_length_hist SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'arange'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'arange', 'inherited', false::boolean, 'range_empty_frac', 0.5::real, 'range_length_histogram', '{399,499,Infinity}'::text @@ -792,8 +873,9 @@ AND attname = 'arange'; -- warn: range bounds histogram on scalar, rest ok SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'id'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', 'inherited', false::boolean, 'null_frac', 0.31::real, 'range_bounds_histogram', '{"[-1,1)","[0,4)","[1,4)","[1,100)"}'::text @@ -818,8 +900,9 @@ AND attname = 'id'; -- ok: range_bounds_histogram SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'arange'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'arange', 'inherited', false::boolean, 'range_bounds_histogram', '{"[-1,1)","[0,4)","[1,4)","[1,100)"}'::text ); @@ -841,8 +924,9 @@ AND attname = 'arange'; -- warn: cannot set most_common_elems for range type, rest ok SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'arange'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'arange', 'inherited', false::boolean, 'null_frac', 0.32::real, 'most_common_elems', '{3,1}'::text, @@ -868,8 +952,9 @@ AND attname = 'arange'; -- warn: scalars can't have mcelem, rest ok SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'id'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', 'inherited', false::boolean, 'null_frac', 0.33::real, 'most_common_elems', '{1,3}'::text, @@ -895,8 +980,9 @@ AND attname = 'id'; -- warn: mcelem / mcelem mismatch, rest ok SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'tags'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'tags', 'inherited', false::boolean, 'null_frac', 0.34::real, 'most_common_elems', '{one,two}'::text @@ -920,8 +1006,9 @@ AND attname = 'tags'; -- warn: mcelem / mcelem null mismatch part 2, rest ok SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'tags'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'tags', 'inherited', false::boolean, 'null_frac', 0.35::real, 'most_common_elem_freqs', '{0.3,0.2,0.2,0.3}'::real[] @@ -945,8 +1032,9 @@ AND attname = 'tags'; -- ok: mcelem SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'tags'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'tags', 'inherited', false::boolean, 'most_common_elems', '{one,three}'::text, 'most_common_elem_freqs', '{0.3,0.2,0.2,0.3,0.0}'::real[] @@ -969,8 +1057,9 @@ AND attname = 'tags'; -- warn: scalars can't have elem_count_histogram, rest ok SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'id'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', 'inherited', false::boolean, 'null_frac', 0.36::real, 'elem_count_histogram', '{1,1,1,1,1,1,1,1,1,1}'::real[] @@ -1022,8 +1111,9 @@ SELECT s.schemaname, s.tablename, s.attname, s.inherited, r.* FROM pg_catalog.pg_stats AS s CROSS JOIN LATERAL pg_catalog.pg_restore_attribute_stats( - 'relation', ('stats_import.' || s.tablename || '_clone')::regclass, - 'attname', s.attname, + 'schemaname', 'stats_import', + 'relname', s.tablename::text || '_clone', + 'attname', s.attname::text, 'inherited', s.inherited, 'version', 150000, 'null_frac', s.null_frac, @@ -1200,9 +1290,10 @@ AND attname = 'arange'; (1 row) SELECT pg_catalog.pg_clear_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'arange'::name, - inherited => false::boolean); + schemaname => 'stats_import', + relname => 'test', + attname => 'arange', + inherited => false); pg_clear_attribute_stats -------------------------- diff --git a/src/test/regress/sql/stats_import.sql b/src/test/regress/sql/stats_import.sql index 0ec590688c2..ccdc44e9236 100644 --- a/src/test/regress/sql/stats_import.sql +++ b/src/test/regress/sql/stats_import.sql @@ -17,7 +17,8 @@ CREATE TABLE stats_import.test( SELECT pg_catalog.pg_restore_relation_stats( - 'relation', 'stats_import.test'::regclass, + 'schemaname', 'stats_import', + 'relname', 'test', 'relpages', 18::integer, 'reltuples', 21::real, 'relallvisible', 24::integer, @@ -32,37 +33,52 @@ FROM pg_class WHERE oid = 'stats_import.test'::regclass ORDER BY relname; -SELECT pg_clear_relation_stats('stats_import.test'::regclass); +SELECT pg_clear_relation_stats('stats_import', 'test'); -- -- relstats tests -- ---- error: relation is wrong type +-- error: schemaname missing SELECT pg_catalog.pg_restore_relation_stats( - 'relation', 0::oid, + 'relname', 'test', + 'relpages', 17::integer); + +-- error: relname missing +SELECT pg_catalog.pg_restore_relation_stats( + 'schemaname', 'stats_import', + 'relpages', 17::integer); + +--- error: schemaname is wrong type +SELECT pg_catalog.pg_restore_relation_stats( + 'schemaname', 3.6::float, + 'relname', 'test', + 'relpages', 17::integer); + +--- error: relname is wrong type +SELECT pg_catalog.pg_restore_relation_stats( + 'schemaname', 'stats_import', + 'relname', 0::oid, 'relpages', 17::integer); -- error: relation not found SELECT pg_catalog.pg_restore_relation_stats( - 'relation', 0::oid::regclass, + 'schemaname', 'stats_import', + 'relname', 'nope', 'relpages', 17::integer); -- error: odd number of variadic arguments cannot be pairs SELECT pg_restore_relation_stats( - 'relation', 'stats_import.test'::regclass, + 'schemaname', 'stats_import', + 'relname', 'test', 'relallvisible'); -- error: argument name is NULL SELECT pg_restore_relation_stats( - 'relation', 'stats_import.test'::regclass, + 'schemaname', 'stats_import', + 'relname', 'test', NULL, '17'::integer); --- error: argument name is not a text type -SELECT pg_restore_relation_stats( - 'relation', '0'::oid::regclass, - 17, '17'::integer); - -- starting stats SELECT relpages, reltuples, relallvisible, relallfrozen FROM pg_class @@ -71,7 +87,8 @@ WHERE oid = 'stats_import.test_i'::regclass; -- regular indexes have special case locking rules BEGIN; SELECT pg_catalog.pg_restore_relation_stats( - 'relation', 'stats_import.test_i'::regclass, + 'schemaname', 'stats_import', + 'relname', 'test_i', 'relpages', 18::integer); SELECT mode FROM pg_locks @@ -108,7 +125,8 @@ WHERE oid = 'stats_import.part_parent'::regclass; BEGIN; SELECT pg_catalog.pg_restore_relation_stats( - 'relation', 'stats_import.part_parent_i'::regclass, + 'schemaname', 'stats_import', + 'relname', 'part_parent_i', 'relpages', 2::integer); SELECT mode FROM pg_locks @@ -127,7 +145,8 @@ WHERE oid = 'stats_import.part_parent_i'::regclass; -- ok: set all relstats, with version, no bounds checking SELECT pg_restore_relation_stats( - 'relation', 'stats_import.test'::regclass, + 'schemaname', 'stats_import', + 'relname', 'test', 'version', 150000::integer, 'relpages', '-17'::integer, 'reltuples', 400::real, @@ -140,7 +159,8 @@ WHERE oid = 'stats_import.test'::regclass; -- ok: set just relpages, rest stay same SELECT pg_restore_relation_stats( - 'relation', 'stats_import.test'::regclass, + 'schemaname', 'stats_import', + 'relname', 'test', 'relpages', '16'::integer); SELECT relpages, reltuples, relallvisible, relallfrozen @@ -149,7 +169,8 @@ WHERE oid = 'stats_import.test'::regclass; -- ok: set just reltuples, rest stay same SELECT pg_restore_relation_stats( - 'relation', 'stats_import.test'::regclass, + 'schemaname', 'stats_import', + 'relname', 'test', 'reltuples', '500'::real); SELECT relpages, reltuples, relallvisible, relallfrozen @@ -158,7 +179,8 @@ WHERE oid = 'stats_import.test'::regclass; -- ok: set just relallvisible, rest stay same SELECT pg_restore_relation_stats( - 'relation', 'stats_import.test'::regclass, + 'schemaname', 'stats_import', + 'relname', 'test', 'relallvisible', 5::integer); SELECT relpages, reltuples, relallvisible, relallfrozen @@ -167,7 +189,8 @@ WHERE oid = 'stats_import.test'::regclass; -- ok: just relallfrozen SELECT pg_restore_relation_stats( - 'relation', 'stats_import.test'::regclass, + 'schemaname', 'stats_import', + 'relname', 'test', 'version', 150000::integer, 'relallfrozen', 3::integer); @@ -177,7 +200,8 @@ WHERE oid = 'stats_import.test'::regclass; -- warn: bad relpages type, rest updated SELECT pg_restore_relation_stats( - 'relation', 'stats_import.test'::regclass, + 'schemaname', 'stats_import', + 'relname', 'test', 'relpages', 'nope'::text, 'reltuples', 400.0::real, 'relallvisible', 4::integer, @@ -189,7 +213,8 @@ WHERE oid = 'stats_import.test'::regclass; -- unrecognized argument name, rest ok SELECT pg_restore_relation_stats( - 'relation', 'stats_import.test'::regclass, + 'schemaname', 'stats_import', + 'relname', 'test', 'relpages', '171'::integer, 'nope', 10::integer); @@ -198,8 +223,7 @@ FROM pg_class WHERE oid = 'stats_import.test'::regclass; -- ok: clear stats -SELECT pg_catalog.pg_clear_relation_stats( - relation => 'stats_import.test'::regclass); +SELECT pg_catalog.pg_clear_relation_stats(schemaname => 'stats_import', relname => 'test'); SELECT relpages, reltuples, relallvisible FROM pg_class @@ -209,48 +233,70 @@ WHERE oid = 'stats_import.test'::regclass; CREATE SEQUENCE stats_import.testseq; SELECT pg_catalog.pg_restore_relation_stats( - 'relation', 'stats_import.testseq'::regclass); + 'schemaname', 'stats_import', + 'relname', 'testseq'); -SELECT pg_catalog.pg_clear_relation_stats( - 'stats_import.testseq'::regclass); +SELECT pg_catalog.pg_clear_relation_stats(schemaname => 'stats_import', relname => 'testseq'); CREATE VIEW stats_import.testview AS SELECT * FROM stats_import.test; -SELECT pg_catalog.pg_restore_relation_stats( - 'relation', 'stats_import.testview'::regclass); - -SELECT pg_catalog.pg_clear_relation_stats( - 'stats_import.testview'::regclass); +SELECT pg_catalog.pg_clear_relation_stats(schemaname => 'stats_import', relname => 'testview'); -- -- attribute stats -- --- error: object does not exist +-- error: schemaname missing SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', '0'::oid::regclass, - 'attname', 'id'::name, + 'relname', 'test', + 'attname', 'id', 'inherited', false::boolean, 'null_frac', 0.1::real); --- error: relation null +-- error: schema does not exist SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', NULL::oid::regclass, - 'attname', 'id'::name, + 'schemaname', 'nope', + 'relname', 'test', + 'attname', 'id', + 'inherited', false::boolean, + 'null_frac', 0.1::real); + +-- error: relname missing +SELECT pg_catalog.pg_restore_attribute_stats( + 'schemaname', 'stats_import', + 'attname', 'id', + 'inherited', false::boolean, + 'null_frac', 0.1::real); + +-- error: relname does not exist +SELECT pg_catalog.pg_restore_attribute_stats( + 'schemaname', 'stats_import', + 'relname', 'nope', + 'attname', 'id', + 'inherited', false::boolean, + 'null_frac', 0.1::real); + +-- error: relname null +SELECT pg_catalog.pg_restore_attribute_stats( + 'schemaname', 'stats_import', + 'relname', NULL, + 'attname', 'id', 'inherited', false::boolean, 'null_frac', 0.1::real); -- error: NULL attname SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', NULL::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', NULL, 'inherited', false::boolean, 'null_frac', 0.1::real); -- error: attname doesn't exist SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'nope'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'nope', 'inherited', false::boolean, 'null_frac', 0.1::real, 'avg_width', 2::integer, @@ -258,36 +304,41 @@ SELECT pg_catalog.pg_restore_attribute_stats( -- error: both attname and attnum SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'id'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', 'attnum', 1::smallint, 'inherited', false::boolean, 'null_frac', 0.1::real); -- error: neither attname nor attnum SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, + 'schemaname', 'stats_import', + 'relname', 'test', 'inherited', false::boolean, 'null_frac', 0.1::real); -- error: attribute is system column SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'xmin'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'xmin', 'inherited', false::boolean, 'null_frac', 0.1::real); -- error: inherited null SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'id'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', 'inherited', NULL::boolean, 'null_frac', 0.1::real); -- ok: just the fixed values, with version, no stakinds SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'id'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', 'inherited', false::boolean, 'version', 150000::integer, 'null_frac', 0.2::real, @@ -307,7 +358,8 @@ AND attname = 'id'; -- for any stat-having relation. -- SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, + 'schemaname', 'stats_import', + 'relname', 'test', 'attnum', 1::smallint, 'inherited', false::boolean, 'null_frac', 0.4::real); @@ -321,8 +373,9 @@ AND attname = 'id'; -- warn: unrecognized argument name, rest get set SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'id'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', 'inherited', false::boolean, 'null_frac', 0.2::real, 'nope', 0.5::real); @@ -336,8 +389,9 @@ AND attname = 'id'; -- warn: mcv / mcf null mismatch part 1, rest get set SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'id'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', 'inherited', false::boolean, 'null_frac', 0.21::real, 'most_common_freqs', '{0.1,0.2,0.3}'::real[] @@ -352,8 +406,9 @@ AND attname = 'id'; -- warn: mcv / mcf null mismatch part 2, rest get set SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'id'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', 'inherited', false::boolean, 'null_frac', 0.21::real, 'most_common_vals', '{1,2,3}'::text @@ -368,8 +423,9 @@ AND attname = 'id'; -- warn: mcf type mismatch, mcv-pair fails, rest get set SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'id'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', 'inherited', false::boolean, 'null_frac', 0.22::real, 'most_common_vals', '{2,1,3}'::text, @@ -385,8 +441,9 @@ AND attname = 'id'; -- warn: mcv cast failure, mcv-pair fails, rest get set SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'id'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', 'inherited', false::boolean, 'null_frac', 0.23::real, 'most_common_vals', '{2,four,3}'::text, @@ -402,8 +459,9 @@ AND attname = 'id'; -- ok: mcv+mcf SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'id'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', 'inherited', false::boolean, 'most_common_vals', '{2,1,3}'::text, 'most_common_freqs', '{0.3,0.25,0.05}'::real[] @@ -418,8 +476,9 @@ AND attname = 'id'; -- warn: NULL in histogram array, rest get set SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'id'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', 'inherited', false::boolean, 'null_frac', 0.24::real, 'histogram_bounds', '{1,NULL,3,4}'::text @@ -434,8 +493,9 @@ AND attname = 'id'; -- ok: histogram_bounds SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'id'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', 'inherited', false::boolean, 'histogram_bounds', '{1,2,3,4}'::text ); @@ -449,8 +509,9 @@ AND attname = 'id'; -- warn: elem_count_histogram null element, rest get set SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'tags'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'tags', 'inherited', false::boolean, 'null_frac', 0.25::real, 'elem_count_histogram', '{1,1,NULL,1,1,1,1,1}'::real[] @@ -465,8 +526,9 @@ AND attname = 'tags'; -- ok: elem_count_histogram SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'tags'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'tags', 'inherited', false::boolean, 'null_frac', 0.26::real, 'elem_count_histogram', '{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}'::real[] @@ -481,8 +543,9 @@ AND attname = 'tags'; -- warn: range stats on a scalar type, rest ok SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'id'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', 'inherited', false::boolean, 'null_frac', 0.27::real, 'range_empty_frac', 0.5::real, @@ -498,8 +561,9 @@ AND attname = 'id'; -- warn: range_empty_frac range_length_hist null mismatch, rest ok SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'arange'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'arange', 'inherited', false::boolean, 'null_frac', 0.28::real, 'range_length_histogram', '{399,499,Infinity}'::text @@ -514,8 +578,9 @@ AND attname = 'arange'; -- warn: range_empty_frac range_length_hist null mismatch part 2, rest ok SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'arange'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'arange', 'inherited', false::boolean, 'null_frac', 0.29::real, 'range_empty_frac', 0.5::real @@ -530,8 +595,9 @@ AND attname = 'arange'; -- ok: range_empty_frac + range_length_hist SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'arange'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'arange', 'inherited', false::boolean, 'range_empty_frac', 0.5::real, 'range_length_histogram', '{399,499,Infinity}'::text @@ -546,8 +612,9 @@ AND attname = 'arange'; -- warn: range bounds histogram on scalar, rest ok SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'id'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', 'inherited', false::boolean, 'null_frac', 0.31::real, 'range_bounds_histogram', '{"[-1,1)","[0,4)","[1,4)","[1,100)"}'::text @@ -562,8 +629,9 @@ AND attname = 'id'; -- ok: range_bounds_histogram SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'arange'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'arange', 'inherited', false::boolean, 'range_bounds_histogram', '{"[-1,1)","[0,4)","[1,4)","[1,100)"}'::text ); @@ -577,8 +645,9 @@ AND attname = 'arange'; -- warn: cannot set most_common_elems for range type, rest ok SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'arange'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'arange', 'inherited', false::boolean, 'null_frac', 0.32::real, 'most_common_elems', '{3,1}'::text, @@ -594,8 +663,9 @@ AND attname = 'arange'; -- warn: scalars can't have mcelem, rest ok SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'id'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', 'inherited', false::boolean, 'null_frac', 0.33::real, 'most_common_elems', '{1,3}'::text, @@ -611,8 +681,9 @@ AND attname = 'id'; -- warn: mcelem / mcelem mismatch, rest ok SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'tags'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'tags', 'inherited', false::boolean, 'null_frac', 0.34::real, 'most_common_elems', '{one,two}'::text @@ -627,8 +698,9 @@ AND attname = 'tags'; -- warn: mcelem / mcelem null mismatch part 2, rest ok SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'tags'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'tags', 'inherited', false::boolean, 'null_frac', 0.35::real, 'most_common_elem_freqs', '{0.3,0.2,0.2,0.3}'::real[] @@ -643,8 +715,9 @@ AND attname = 'tags'; -- ok: mcelem SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'tags'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'tags', 'inherited', false::boolean, 'most_common_elems', '{one,three}'::text, 'most_common_elem_freqs', '{0.3,0.2,0.2,0.3,0.0}'::real[] @@ -659,8 +732,9 @@ AND attname = 'tags'; -- warn: scalars can't have elem_count_histogram, rest ok SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'id'::name, + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', 'inherited', false::boolean, 'null_frac', 0.36::real, 'elem_count_histogram', '{1,1,1,1,1,1,1,1,1,1}'::real[] @@ -707,8 +781,9 @@ SELECT s.schemaname, s.tablename, s.attname, s.inherited, r.* FROM pg_catalog.pg_stats AS s CROSS JOIN LATERAL pg_catalog.pg_restore_attribute_stats( - 'relation', ('stats_import.' || s.tablename || '_clone')::regclass, - 'attname', s.attname, + 'schemaname', 'stats_import', + 'relname', s.tablename::text || '_clone', + 'attname', s.attname::text, 'inherited', s.inherited, 'version', 150000, 'null_frac', s.null_frac, @@ -853,9 +928,10 @@ AND inherited = false AND attname = 'arange'; SELECT pg_catalog.pg_clear_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'arange'::name, - inherited => false::boolean); + schemaname => 'stats_import', + relname => 'test', + attname => 'arange', + inherited => false); SELECT COUNT(*) FROM pg_stats diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 51dd8ad6571..63a260a8ff8 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -30348,22 +30348,24 @@ postgres=# SELECT '0/0'::pg_lsn + pd.segment_number * ps.setting::int + :offset mytable: SELECT pg_restore_relation_stats( - 'relation', 'mytable'::regclass, - 'relpages', 173::integer, - 'reltuples', 10000::real); + 'schemaname', 'myschema', + 'relname', 'mytable', + 'relpages', 173::integer, + 'reltuples', 10000::real); - The argument relation with a value of type - regclass is required, and specifies the table. Other - arguments are the names and values of statistics corresponding to - certain columns in schemaname with a value of type + regclass and relname are required, + and specifies the table. Other arguments are the names and values + of statistics corresponding to certain columns in pg_class. The currently-supported relation statistics are relpages with a value of type integer, reltuples with a value of - type real, and relallvisible with a - value of type integer. + type real, relallvisible with a + value of type integer, and relallfrozen + with a value of type integer. Additionally, this function accepts argument name @@ -30391,7 +30393,7 @@ postgres=# SELECT '0/0'::pg_lsn + pd.segment_number * ps.setting::int + :offset pg_clear_relation_stats - pg_clear_relation_stats ( relation regclass ) + pg_clear_relation_stats ( schemaname text, relname text ) void @@ -30440,16 +30442,18 @@ postgres=# SELECT '0/0'::pg_lsn + pd.segment_number * ps.setting::int + :offset mytable: SELECT pg_restore_attribute_stats( - 'relation', 'mytable'::regclass, - 'attname', 'col1'::name, - 'inherited', false, - 'avg_width', 125::integer, - 'null_frac', 0.5::real); + 'schemaname', 'myschema', + 'relname', 'mytable', + 'attname', 'col1', + 'inherited', false, + 'avg_width', 125::integer, + 'null_frac', 0.5::real); - The required arguments are relation with a value - of type regclass, which specifies the table; either + The required arguments are schemaname with a value + of type regclass and relname with a value + of type text which specify the table; either attname with a value of type name or attnum with a value of type smallint, which specifies the column; and inherited, which @@ -30485,7 +30489,8 @@ postgres=# SELECT '0/0'::pg_lsn + pd.segment_number * ps.setting::int + :offset pg_clear_attribute_stats pg_clear_attribute_stats ( - relation regclass, + schemaname text, + relname text, attname name, inherited boolean ) void base-commit: 21f653cc0024100f8ecc279162631f2b1ba8c46c -- 2.48.1