Updated and rebase patches. 0001 is the same as v6-0002, but with proper ACL checks on schemas after cache lookup
0002 attempts to replace all possible ERRORs in the restore/clear functions with WARNINGs. This is done with an eye towards reducing the set of things that could potentially cause an upgrade to fail. Spoke with Nathan about how best to batch the pg_stats fetches. I'll be working on that now. Given that, the patch that optimized out getAttributeStats() calls on indexes without expressions has been withdrawn. It's a clear incremental gain, and we're looking for a couple orders of magnitude gain.
From 9cd4b4e0e280d0fd8cb120ac105d6e65a491cd7e Mon Sep 17 00:00:00 2001 From: Corey Huinker <corey.huin...@gmail.com> 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 <structname>mytable</structname>: <programlisting> SELECT pg_restore_relation_stats( - 'relation', 'mytable'::regclass, - 'relpages', 173::integer, - 'reltuples', 10000::real); + 'schemaname', 'myschema', + 'relname', 'mytable', + 'relpages', 173::integer, + 'reltuples', 10000::real); </programlisting> </para> <para> - The argument <literal>relation</literal> with a value of type - <type>regclass</type> is required, and specifies the table. Other - arguments are the names and values of statistics corresponding to - certain columns in <link + The arguments <literal>schemaname</literal> with a value of type + <type>regclass</type> and <literal>relname</literal> are required, + and specifies the table. Other arguments are the names and values + of statistics corresponding to certain columns in <link linkend="catalog-pg-class"><structname>pg_class</structname></link>. The currently-supported relation statistics are <literal>relpages</literal> with a value of type <type>integer</type>, <literal>reltuples</literal> with a value of - type <type>real</type>, and <literal>relallvisible</literal> with a - value of type <type>integer</type>. + type <type>real</type>, <literal>relallvisible</literal> with a + value of type <type>integer</type>, and <literal>relallfrozen</literal> + with a value of type <type>integer</type>. </para> <para> Additionally, this function accepts argument name @@ -30391,7 +30393,7 @@ postgres=# SELECT '0/0'::pg_lsn + pd.segment_number * ps.setting::int + :offset <indexterm> <primary>pg_clear_relation_stats</primary> </indexterm> - <function>pg_clear_relation_stats</function> ( <parameter>relation</parameter> <type>regclass</type> ) + <function>pg_clear_relation_stats</function> ( <parameter>schemaname</parameter> <type>text</type>, <parameter>relname</parameter> <type>text</type> ) <returnvalue>void</returnvalue> </para> <para> @@ -30440,16 +30442,18 @@ postgres=# SELECT '0/0'::pg_lsn + pd.segment_number * ps.setting::int + :offset <structname>mytable</structname>: <programlisting> 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); </programlisting> </para> <para> - The required arguments are <literal>relation</literal> with a value - of type <type>regclass</type>, which specifies the table; either + The required arguments are <literal>schemaname</literal> with a value + of type <type>regclass</type> and <literal>relname</literal> with a value + of type <type>text</type> which specify the table; either <literal>attname</literal> with a value of type <type>name</type> or <literal>attnum</literal> with a value of type <type>smallint</type>, which specifies the column; and <literal>inherited</literal>, which @@ -30485,7 +30489,8 @@ postgres=# SELECT '0/0'::pg_lsn + pd.segment_number * ps.setting::int + :offset <primary>pg_clear_attribute_stats</primary> </indexterm> <function>pg_clear_attribute_stats</function> ( - <parameter>relation</parameter> <type>regclass</type>, + <parameter>schemaname</parameter> <type>text</type>, + <parameter>relname</parameter> <type>text</type>, <parameter>attname</parameter> <type>name</type>, <parameter>inherited</parameter> <type>boolean</type> ) <returnvalue>void</returnvalue> base-commit: 21f653cc0024100f8ecc279162631f2b1ba8c46c -- 2.48.1
From 4d8d76b78b87f53d0adbd6781a2a66beac5bc264 Mon Sep 17 00:00:00 2001 From: Corey Huinker <corey.huin...@gmail.com> Date: Sat, 8 Mar 2025 00:52:41 -0500 Subject: [PATCH v7 2/2] Downgrade as man pg_restore_*_stats errors to warnings. We want to avoid errors that can potentially stop an otherwise successful pg_upgrade or pg_restore operation. With that in mind, change as many ERROR reports to WARNING + early termination with no data updated. --- src/include/statistics/stat_utils.h | 4 +- src/backend/statistics/attribute_stats.c | 124 +++++++++++----- src/backend/statistics/relation_stats.c | 10 +- src/backend/statistics/stat_utils.c | 51 +++++-- src/test/regress/expected/stats_import.out | 163 ++++++++++++++++----- src/test/regress/sql/stats_import.sql | 36 ++--- 6 files changed, 277 insertions(+), 111 deletions(-) diff --git a/src/include/statistics/stat_utils.h b/src/include/statistics/stat_utils.h index cad042c8e4a..298cbae3436 100644 --- a/src/include/statistics/stat_utils.h +++ b/src/include/statistics/stat_utils.h @@ -21,7 +21,7 @@ struct StatsArgInfo Oid argtype; }; -extern void stats_check_required_arg(FunctionCallInfo fcinfo, +extern bool stats_check_required_arg(FunctionCallInfo fcinfo, struct StatsArgInfo *arginfo, int argnum); extern bool stats_check_arg_array(FunctionCallInfo fcinfo, @@ -30,7 +30,7 @@ extern bool stats_check_arg_pair(FunctionCallInfo fcinfo, struct StatsArgInfo *arginfo, int argnum1, int argnum2); -extern void stats_lock_check_privileges(Oid reloid); +extern bool stats_lock_check_privileges(Oid reloid); extern Oid stats_schema_check_privileges(const char *nspname); diff --git a/src/backend/statistics/attribute_stats.c b/src/backend/statistics/attribute_stats.c index f87db2d6102..4f9bc18f8c6 100644 --- a/src/backend/statistics/attribute_stats.c +++ b/src/backend/statistics/attribute_stats.c @@ -100,7 +100,7 @@ static struct StatsArgInfo cleararginfo[] = static bool attribute_statistics_update(FunctionCallInfo fcinfo); static Node *get_attr_expr(Relation rel, int attnum); -static void get_attr_stat_type(Oid reloid, AttrNumber attnum, +static bool get_attr_stat_type(Oid reloid, AttrNumber attnum, Oid *atttypid, int32 *atttypmod, char *atttyptype, Oid *atttypcoll, Oid *eq_opr, Oid *lt_opr); @@ -129,10 +129,12 @@ static void init_empty_stats_tuple(Oid reloid, int16 attnum, bool inherited, * stored as an anyarray, and the representation of the array needs to store * the correct element type, which must be derived from the attribute. * - * Major errors, such as the table not existing, the attribute not existing, - * or a permissions failure are always reported at ERROR. Other errors, such - * as a conversion failure on one statistic kind, are reported as a WARNING - * and other statistic kinds may still be updated. + * This function is called during database upgrades and restorations, therefore + * it is imperative to avoid ERRORs that could potentially end the upgrade or + * restore unless. Major errors, such as the table not existing, the attribute + * not existing, or permissions failure are reported as WARNINGs with an end to + * the function, thus allowing the upgrade/restore to continue, but without the + * stats that can be regenereated once the database is online again. */ static bool attribute_statistics_update(FunctionCallInfo fcinfo) @@ -149,8 +151,8 @@ attribute_statistics_update(FunctionCallInfo fcinfo) HeapTuple statup; Oid atttypid = InvalidOid; - int32 atttypmod; - char atttyptype; + int32 atttypmod = -1; + char atttyptype = TYPTYPE_PSEUDO; /* Not a great default, but there is no TYPTYPE_INVALID */ Oid atttypcoll = InvalidOid; Oid eq_opr = InvalidOid; Oid lt_opr = InvalidOid; @@ -177,17 +179,19 @@ attribute_statistics_update(FunctionCallInfo fcinfo) bool result = true; - stats_check_required_arg(fcinfo, attarginfo, ATTRELSCHEMA_ARG); - stats_check_required_arg(fcinfo, attarginfo, ATTRELNAME_ARG); + if (!stats_check_required_arg(fcinfo, attarginfo, ATTRELSCHEMA_ARG)) + return false; + if (!stats_check_required_arg(fcinfo, attarginfo, ATTRELNAME_ARG)) + return false; nspname = TextDatumGetCString(PG_GETARG_DATUM(ATTRELSCHEMA_ARG)); nspoid = stats_schema_check_privileges(nspname); - if (nspoid == InvalidOid) + if (!OidIsValid(nspoid)) return false; relname = TextDatumGetCString(PG_GETARG_DATUM(ATTRELNAME_ARG)); reloid = get_relname_relid(relname, nspoid); - if (reloid == InvalidOid) + if (!OidIsValid(reloid)) { ereport(WARNING, (errcode(ERRCODE_UNDEFINED_OBJECT), @@ -196,29 +200,39 @@ attribute_statistics_update(FunctionCallInfo fcinfo) } if (RecoveryInProgress()) - ereport(ERROR, + { + ereport(WARNING, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("recovery is in progress"), errhint("Statistics cannot be modified during recovery."))); + return false; + } /* lock before looking up attribute */ - stats_lock_check_privileges(reloid); + if (!stats_lock_check_privileges(reloid)) + return false; /* user can specify either attname or attnum, but not both */ if (!PG_ARGISNULL(ATTNAME_ARG)) { if (!PG_ARGISNULL(ATTNUM_ARG)) - ereport(ERROR, + { + ereport(WARNING, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("cannot specify both attname and attnum"))); + return false; + } 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, + { + ereport(WARNING, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("column \"%s\" of relation \"%s\".\"%s\" does not exist", attname, nspname, relname))); + return false; + } } else if (!PG_ARGISNULL(ATTNUM_ARG)) { @@ -227,27 +241,33 @@ attribute_statistics_update(FunctionCallInfo fcinfo) /* annoyingly, get_attname doesn't check attisdropped */ if (attname == NULL || !SearchSysCacheExistsAttName(reloid, attname)) - ereport(ERROR, + { + ereport(WARNING, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("column %d of relation \"%s\".\"%s\" does not exist", attnum, nspname, relname))); + return false; + } } else { - ereport(ERROR, + ereport(WARNING, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("must specify either attname or attnum"))); - attname = NULL; /* keep compiler quiet */ - attnum = 0; + return false; } if (attnum < 0) - ereport(ERROR, + { + ereport(WARNING, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot modify statistics on system column \"%s\"", attname))); + return false; + } - stats_check_required_arg(fcinfo, attarginfo, INHERITED_ARG); + if (!stats_check_required_arg(fcinfo, attarginfo, INHERITED_ARG)) + return false; inherited = PG_GETARG_BOOL(INHERITED_ARG); /* @@ -296,10 +316,11 @@ attribute_statistics_update(FunctionCallInfo fcinfo) } /* derive information from attribute */ - get_attr_stat_type(reloid, attnum, - &atttypid, &atttypmod, - &atttyptype, &atttypcoll, - &eq_opr, <_opr); + if (!get_attr_stat_type(reloid, attnum, + &atttypid, &atttypmod, + &atttyptype, &atttypcoll, + &eq_opr, <_opr)) + result = false; /* if needed, derive element type */ if (do_mcelem || do_dechist) @@ -579,7 +600,7 @@ get_attr_expr(Relation rel, int attnum) /* * Derive type information from the attribute. */ -static void +static bool get_attr_stat_type(Oid reloid, AttrNumber attnum, Oid *atttypid, int32 *atttypmod, char *atttyptype, Oid *atttypcoll, @@ -596,18 +617,26 @@ get_attr_stat_type(Oid reloid, AttrNumber attnum, /* Attribute not found */ if (!HeapTupleIsValid(atup)) - ereport(ERROR, + { + ereport(WARNING, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("attribute %d of relation \"%s\" does not exist", attnum, RelationGetRelationName(rel)))); + relation_close(rel, NoLock); + return false; + } attr = (Form_pg_attribute) GETSTRUCT(atup); if (attr->attisdropped) - ereport(ERROR, + { + ereport(WARNING, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("attribute %d of relation \"%s\" does not exist", attnum, RelationGetRelationName(rel)))); + relation_close(rel, NoLock); + return false; + } expr = get_attr_expr(rel, attr->attnum); @@ -656,6 +685,7 @@ get_attr_stat_type(Oid reloid, AttrNumber attnum, *atttypcoll = DEFAULT_COLLATION_OID; relation_close(rel, NoLock); + return true; } /* @@ -781,6 +811,10 @@ set_stats_slot(Datum *values, bool *nulls, bool *replaces, if (slotidx >= STATISTIC_NUM_SLOTS && first_empty >= 0) slotidx = first_empty; + /* + * Currently there is no datatype that can have more than STATISTIC_NUM_SLOTS + * statistic kinds, so this can safely remain an ERROR for now. + */ if (slotidx >= STATISTIC_NUM_SLOTS) ereport(ERROR, (errmsg("maximum number of statistics slots exceeded: %d", @@ -927,15 +961,19 @@ pg_clear_attribute_stats(PG_FUNCTION_ARGS) AttrNumber attnum; bool inherited; - 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); + if (!stats_check_required_arg(fcinfo, cleararginfo, C_ATTRELSCHEMA_ARG)) + PG_RETURN_VOID(); + if (!stats_check_required_arg(fcinfo, cleararginfo, C_ATTRELNAME_ARG)) + PG_RETURN_VOID(); + if (!stats_check_required_arg(fcinfo, cleararginfo, C_ATTNAME_ARG)) + PG_RETURN_VOID(); + if (!stats_check_required_arg(fcinfo, cleararginfo, C_INHERITED_ARG)) + PG_RETURN_VOID(); nspname = TextDatumGetCString(PG_GETARG_DATUM(C_ATTRELSCHEMA_ARG)); nspoid = stats_schema_check_privileges(nspname); if (!OidIsValid(nspoid)) - return false; + PG_RETURN_VOID(); relname = TextDatumGetCString(PG_GETARG_DATUM(C_ATTRELNAME_ARG)); reloid = get_relname_relid(relname, nspoid); @@ -944,31 +982,41 @@ pg_clear_attribute_stats(PG_FUNCTION_ARGS) ereport(WARNING, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("Relation \"%s\".\"%s\" not found.", nspname, relname))); - return false; + PG_RETURN_VOID(); } if (RecoveryInProgress()) - ereport(ERROR, + { + ereport(WARNING, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("recovery is in progress"), errhint("Statistics cannot be modified during recovery."))); + PG_RETURN_VOID(); + } - stats_lock_check_privileges(reloid); + if (!stats_lock_check_privileges(reloid)) + PG_RETURN_VOID(); attname = TextDatumGetCString(PG_GETARG_DATUM(C_ATTNAME_ARG)); attnum = get_attnum(reloid, attname); if (attnum < 0) - ereport(ERROR, + { + ereport(WARNING, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot clear statistics on system column \"%s\"", attname))); + PG_RETURN_VOID(); + } if (attnum == InvalidAttrNumber) - ereport(ERROR, + { + ereport(WARNING, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("column \"%s\" of relation \"%s\" does not exist", attname, get_rel_name(reloid)))); + PG_RETURN_VOID(); + } inherited = PG_GETARG_BOOL(C_INHERITED_ARG); diff --git a/src/backend/statistics/relation_stats.c b/src/backend/statistics/relation_stats.c index fdc69bc93e2..49109cf721d 100644 --- a/src/backend/statistics/relation_stats.c +++ b/src/backend/statistics/relation_stats.c @@ -84,8 +84,11 @@ 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); + if (!stats_check_required_arg(fcinfo, relarginfo, RELSCHEMA_ARG)) + return false; + + if (!stats_check_required_arg(fcinfo, relarginfo, RELNAME_ARG)) + return false; nspname = TextDatumGetCString(PG_GETARG_DATUM(RELSCHEMA_ARG)); nspoid = stats_schema_check_privileges(nspname); @@ -108,7 +111,8 @@ relation_statistics_update(FunctionCallInfo fcinfo) errmsg("recovery is in progress"), errhint("Statistics cannot be modified during recovery."))); - stats_lock_check_privileges(reloid); + if (!stats_lock_check_privileges(reloid)) + return false; if (!PG_ARGISNULL(RELPAGES_ARG)) { diff --git a/src/backend/statistics/stat_utils.c b/src/backend/statistics/stat_utils.c index e037d4994e8..dd9d88ac1c5 100644 --- a/src/backend/statistics/stat_utils.c +++ b/src/backend/statistics/stat_utils.c @@ -34,16 +34,20 @@ /* * Ensure that a given argument is not null. */ -void +bool stats_check_required_arg(FunctionCallInfo fcinfo, struct StatsArgInfo *arginfo, int argnum) { if (PG_ARGISNULL(argnum)) - ereport(ERROR, + { + ereport(WARNING, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("\"%s\" cannot be NULL", arginfo[argnum].argname))); + return false; + } + return true; } /* @@ -128,13 +132,14 @@ stats_check_arg_pair(FunctionCallInfo fcinfo, * - the role owns the current database and the relation is not shared * - the role has the MAINTAIN privilege on the relation */ -void +bool stats_lock_check_privileges(Oid reloid) { Relation table; Oid table_oid = reloid; Oid index_oid = InvalidOid; LOCKMODE index_lockmode = NoLock; + bool ok = true; /* * For indexes, we follow the locking behavior in do_analyze_rel() and @@ -174,14 +179,15 @@ stats_lock_check_privileges(Oid reloid) case RELKIND_PARTITIONED_TABLE: break; default: - ereport(ERROR, + ereport(WARNING, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("cannot modify statistics for relation \"%s\"", RelationGetRelationName(table)), errdetail_relkind_not_supported(table->rd_rel->relkind))); + ok = false; } - if (OidIsValid(index_oid)) + if (ok && (OidIsValid(index_oid))) { Relation index; @@ -194,25 +200,33 @@ stats_lock_check_privileges(Oid reloid) relation_close(index, NoLock); } - if (table->rd_rel->relisshared) - ereport(ERROR, + if (ok && (table->rd_rel->relisshared)) + { + ereport(WARNING, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot modify statistics for shared relation"))); + ok = false; + } - if (!object_ownercheck(DatabaseRelationId, MyDatabaseId, GetUserId())) + if (ok && (!object_ownercheck(DatabaseRelationId, MyDatabaseId, GetUserId()))) { AclResult aclresult = pg_class_aclcheck(RelationGetRelid(table), GetUserId(), ACL_MAINTAIN); if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, - get_relkind_objtype(table->rd_rel->relkind), - NameStr(table->rd_rel->relname)); + { + ereport(WARNING, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied for relation %s", + NameStr(table->rd_rel->relname)))); + ok = false; + } } /* retain lock on table */ relation_close(table, NoLock); + return ok; } @@ -318,9 +332,12 @@ stats_fill_fcinfo_from_arg_pairs(FunctionCallInfo pairs_fcinfo, &args, &types, &argnulls); if (nargs % 2 != 0) - ereport(ERROR, + { + ereport(WARNING, errmsg("variadic arguments must be name/value pairs"), errhint("Provide an even number of variadic arguments that can be divided into pairs.")); + return false; + } /* * For each argument name/value pair, find corresponding positional @@ -333,14 +350,20 @@ stats_fill_fcinfo_from_arg_pairs(FunctionCallInfo pairs_fcinfo, char *argname; if (argnulls[i]) - ereport(ERROR, + { + ereport(WARNING, (errmsg("name at variadic position %d is NULL", i + 1))); + return false; + } if (types[i] != TEXTOID) - ereport(ERROR, + { + ereport(WARNING, (errmsg("name at variadic position %d has type \"%s\", expected type \"%s\"", i + 1, format_type_be(types[i]), format_type_be(TEXTOID)))); + return false; + } if (argnulls[i + 1]) continue; diff --git a/src/test/regress/expected/stats_import.out b/src/test/regress/expected/stats_import.out index 2f1295f2149..6551d6bf099 100644 --- a/src/test/regress/expected/stats_import.out +++ b/src/test/regress/expected/stats_import.out @@ -46,31 +46,51 @@ SELECT pg_clear_relation_stats('stats_import', 'test'); -- -- relstats tests -- --- error: schemaname missing +-- warning: schemaname missing, nothing updated SELECT pg_catalog.pg_restore_relation_stats( 'relname', 'test', 'relpages', 17::integer); -ERROR: "schemaname" cannot be NULL --- error: relname missing +WARNING: "schemaname" cannot be NULL + pg_restore_relation_stats +--------------------------- + f +(1 row) + +-- warning: relname missing, nothing updated SELECT pg_catalog.pg_restore_relation_stats( 'schemaname', 'stats_import', 'relpages', 17::integer); -ERROR: "relname" cannot be NULL ---- error: schemaname is wrong type +WARNING: "relname" cannot be NULL + pg_restore_relation_stats +--------------------------- + f +(1 row) + +--- warning: schemaname is wrong type, nothing updated 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 +WARNING: "schemaname" cannot be NULL + pg_restore_relation_stats +--------------------------- + f +(1 row) + +--- warning: relname is wrong type, nothing updated 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 +WARNING: "relname" cannot be NULL + pg_restore_relation_stats +--------------------------- + f +(1 row) + +-- warning: relation not found, nothing updated SELECT pg_catalog.pg_restore_relation_stats( 'schemaname', 'stats_import', 'relname', 'nope', @@ -81,19 +101,30 @@ WARNING: Relation "stats_import"."nope" not found. f (1 row) --- error: odd number of variadic arguments cannot be pairs +-- warning: odd number of variadic arguments cannot be pairs, nothing updated SELECT pg_restore_relation_stats( 'schemaname', 'stats_import', 'relname', 'test', 'relallvisible'); -ERROR: variadic arguments must be name/value pairs +WARNING: 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 +WARNING: "schemaname" cannot be NULL + pg_restore_relation_stats +--------------------------- + f +(1 row) + +-- warning: argument name is NULL, nothing updated SELECT pg_restore_relation_stats( 'schemaname', 'stats_import', 'relname', 'test', NULL, '17'::integer); -ERROR: name at variadic position 5 is NULL +WARNING: name at variadic position 5 is NULL + pg_restore_relation_stats +--------------------------- + f +(1 row) + -- starting stats SELECT relpages, reltuples, relallvisible, relallfrozen FROM pg_class @@ -345,26 +376,46 @@ CREATE SEQUENCE stats_import.testseq; SELECT pg_catalog.pg_restore_relation_stats( 'schemaname', 'stats_import', 'relname', 'testseq'); -ERROR: cannot modify statistics for relation "testseq" +WARNING: cannot modify statistics for relation "testseq" DETAIL: This operation is not supported for sequences. + pg_restore_relation_stats +--------------------------- + f +(1 row) + SELECT pg_catalog.pg_clear_relation_stats(schemaname => 'stats_import', relname => 'testseq'); -ERROR: cannot modify statistics for relation "testseq" +WARNING: cannot modify statistics for relation "testseq" DETAIL: This operation is not supported for sequences. + pg_clear_relation_stats +------------------------- + +(1 row) + CREATE VIEW stats_import.testview AS SELECT * FROM stats_import.test; SELECT pg_catalog.pg_clear_relation_stats(schemaname => 'stats_import', relname => 'testview'); -ERROR: cannot modify statistics for relation "testview" +WARNING: cannot modify statistics for relation "testview" DETAIL: This operation is not supported for views. + pg_clear_relation_stats +------------------------- + +(1 row) + -- -- attribute stats -- --- error: schemaname missing +-- warning: schemaname missing, nothing updated SELECT pg_catalog.pg_restore_attribute_stats( 'relname', 'test', 'attname', 'id', 'inherited', false::boolean, 'null_frac', 0.1::real); -ERROR: "schemaname" cannot be NULL --- error: schema does not exist +WARNING: "schemaname" cannot be NULL + pg_restore_attribute_stats +---------------------------- + f +(1 row) + +-- warning: schema does not exist, nothing updated SELECT pg_catalog.pg_restore_attribute_stats( 'schemaname', 'nope', 'relname', 'test', @@ -377,14 +428,19 @@ WARNING: schema nope does not exist f (1 row) --- error: relname missing +-- warning: relname missing, nothing updated 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 +WARNING: "relname" cannot be NULL + pg_restore_attribute_stats +---------------------------- + f +(1 row) + +-- warning: relname does not exist, nothing updated SELECT pg_catalog.pg_restore_attribute_stats( 'schemaname', 'stats_import', 'relname', 'nope', @@ -397,23 +453,33 @@ WARNING: Relation "stats_import"."nope" not found. f (1 row) --- error: relname null +-- warning: relname null, nothing updated 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 +WARNING: "relname" cannot be NULL + pg_restore_attribute_stats +---------------------------- + f +(1 row) + +-- warning: NULL attname, nothing updated SELECT pg_catalog.pg_restore_attribute_stats( '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 +WARNING: must specify either attname or attnum + pg_restore_attribute_stats +---------------------------- + f +(1 row) + +-- warning: attname doesn't exist, nothing updated SELECT pg_catalog.pg_restore_attribute_stats( 'schemaname', 'stats_import', 'relname', 'test', @@ -422,8 +488,13 @@ SELECT pg_catalog.pg_restore_attribute_stats( 'null_frac', 0.1::real, 'avg_width', 2::integer, 'n_distinct', 0.3::real); -ERROR: column "nope" of relation "stats_import"."test" does not exist --- error: both attname and attnum +WARNING: column "nope" of relation "stats_import"."test" does not exist + pg_restore_attribute_stats +---------------------------- + f +(1 row) + +-- warning: both attname and attnum, nothing updated SELECT pg_catalog.pg_restore_attribute_stats( 'schemaname', 'stats_import', 'relname', 'test', @@ -431,30 +502,50 @@ SELECT pg_catalog.pg_restore_attribute_stats( 'attnum', 1::smallint, 'inherited', false::boolean, 'null_frac', 0.1::real); -ERROR: cannot specify both attname and attnum --- error: neither attname nor attnum +WARNING: cannot specify both attname and attnum + pg_restore_attribute_stats +---------------------------- + f +(1 row) + +-- warning: neither attname nor attnum, nothing updated SELECT pg_catalog.pg_restore_attribute_stats( '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 +WARNING: must specify either attname or attnum + pg_restore_attribute_stats +---------------------------- + f +(1 row) + +-- warning: attribute is system column, nothing updated SELECT pg_catalog.pg_restore_attribute_stats( '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 +WARNING: cannot modify statistics on system column "xmin" + pg_restore_attribute_stats +---------------------------- + f +(1 row) + +-- warning: inherited null, nothing updated SELECT pg_catalog.pg_restore_attribute_stats( 'schemaname', 'stats_import', 'relname', 'test', 'attname', 'id', 'inherited', NULL::boolean, 'null_frac', 0.1::real); -ERROR: "inherited" cannot be NULL +WARNING: "inherited" cannot be NULL + pg_restore_attribute_stats +---------------------------- + f +(1 row) + -- ok: just the fixed values, with version, no stakinds SELECT pg_catalog.pg_restore_attribute_stats( 'schemaname', 'stats_import', diff --git a/src/test/regress/sql/stats_import.sql b/src/test/regress/sql/stats_import.sql index ccdc44e9236..dbbebce1673 100644 --- a/src/test/regress/sql/stats_import.sql +++ b/src/test/regress/sql/stats_import.sql @@ -39,41 +39,41 @@ SELECT pg_clear_relation_stats('stats_import', 'test'); -- relstats tests -- --- error: schemaname missing +-- warning: schemaname missing, nothing updated SELECT pg_catalog.pg_restore_relation_stats( 'relname', 'test', 'relpages', 17::integer); --- error: relname missing +-- warning: relname missing, nothing updated SELECT pg_catalog.pg_restore_relation_stats( 'schemaname', 'stats_import', 'relpages', 17::integer); ---- error: schemaname is wrong type +--- warning: schemaname is wrong type, nothing updated SELECT pg_catalog.pg_restore_relation_stats( 'schemaname', 3.6::float, 'relname', 'test', 'relpages', 17::integer); ---- error: relname is wrong type +--- warning: relname is wrong type, nothing updated SELECT pg_catalog.pg_restore_relation_stats( 'schemaname', 'stats_import', 'relname', 0::oid, 'relpages', 17::integer); --- error: relation not found +-- warning: relation not found, nothing updated SELECT pg_catalog.pg_restore_relation_stats( 'schemaname', 'stats_import', 'relname', 'nope', 'relpages', 17::integer); --- error: odd number of variadic arguments cannot be pairs +-- warning: odd number of variadic arguments cannot be pairs, nothing updated SELECT pg_restore_relation_stats( 'schemaname', 'stats_import', 'relname', 'test', 'relallvisible'); --- error: argument name is NULL +-- warning: argument name is NULL, nothing updated SELECT pg_restore_relation_stats( 'schemaname', 'stats_import', 'relname', 'test', @@ -246,14 +246,14 @@ SELECT pg_catalog.pg_clear_relation_stats(schemaname => 'stats_import', relname -- attribute stats -- --- error: schemaname missing +-- warning: schemaname missing, nothing updated SELECT pg_catalog.pg_restore_attribute_stats( 'relname', 'test', 'attname', 'id', 'inherited', false::boolean, 'null_frac', 0.1::real); --- error: schema does not exist +-- warning: schema does not exist, nothing updated SELECT pg_catalog.pg_restore_attribute_stats( 'schemaname', 'nope', 'relname', 'test', @@ -261,14 +261,14 @@ SELECT pg_catalog.pg_restore_attribute_stats( 'inherited', false::boolean, 'null_frac', 0.1::real); --- error: relname missing +-- warning: relname missing, nothing updated 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 +-- warning: relname does not exist, nothing updated SELECT pg_catalog.pg_restore_attribute_stats( 'schemaname', 'stats_import', 'relname', 'nope', @@ -276,7 +276,7 @@ SELECT pg_catalog.pg_restore_attribute_stats( 'inherited', false::boolean, 'null_frac', 0.1::real); --- error: relname null +-- warning: relname null, nothing updated SELECT pg_catalog.pg_restore_attribute_stats( 'schemaname', 'stats_import', 'relname', NULL, @@ -284,7 +284,7 @@ SELECT pg_catalog.pg_restore_attribute_stats( 'inherited', false::boolean, 'null_frac', 0.1::real); --- error: NULL attname +-- warning: NULL attname, nothing updated SELECT pg_catalog.pg_restore_attribute_stats( 'schemaname', 'stats_import', 'relname', 'test', @@ -292,7 +292,7 @@ SELECT pg_catalog.pg_restore_attribute_stats( 'inherited', false::boolean, 'null_frac', 0.1::real); --- error: attname doesn't exist +-- warning: attname doesn't exist, nothing updated SELECT pg_catalog.pg_restore_attribute_stats( 'schemaname', 'stats_import', 'relname', 'test', @@ -302,7 +302,7 @@ SELECT pg_catalog.pg_restore_attribute_stats( 'avg_width', 2::integer, 'n_distinct', 0.3::real); --- error: both attname and attnum +-- warning: both attname and attnum, nothing updated SELECT pg_catalog.pg_restore_attribute_stats( 'schemaname', 'stats_import', 'relname', 'test', @@ -311,14 +311,14 @@ SELECT pg_catalog.pg_restore_attribute_stats( 'inherited', false::boolean, 'null_frac', 0.1::real); --- error: neither attname nor attnum +-- warning: neither attname nor attnum, nothing updated SELECT pg_catalog.pg_restore_attribute_stats( 'schemaname', 'stats_import', 'relname', 'test', 'inherited', false::boolean, 'null_frac', 0.1::real); --- error: attribute is system column +-- warning: attribute is system column, nothing updated SELECT pg_catalog.pg_restore_attribute_stats( 'schemaname', 'stats_import', 'relname', 'test', @@ -326,7 +326,7 @@ SELECT pg_catalog.pg_restore_attribute_stats( 'inherited', false::boolean, 'null_frac', 0.1::real); --- error: inherited null +-- warning: inherited null, nothing updated SELECT pg_catalog.pg_restore_attribute_stats( 'schemaname', 'stats_import', 'relname', 'test', -- 2.48.1