diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index f0ccb751106..12206e0cfc6 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -30181,41 +30181,72 @@ postgres=# SELECT '0/0'::pg_lsn + pd.segment_number * ps.setting::int + :offset - - - - pg_set_relation_stats - - pg_set_relation_stats ( - relation regclass - , relpages integer - , reltuples real - , relallvisible integer ) - void + + + pg_restore_relation_stats + + pg_restore_relation_stats ( + VARIADIC kwargs "any" ) + boolean + + + Updates table-level statistics. Ordinarily, these statistics are + collected automatically or updated as a part of or , so it's not + necessary to call this function. However, it is useful after a + restore to enable the optimizer to choose better plans if + ANALYZE has not been run yet. - Updates relation-level statistics for the given relation to the - specified values. The parameters correspond to columns in pg_class. Unspecified - or NULL values leave the setting unchanged. + The tracked statistics may change from version to version, so + arguments are passed as pairs of argname + and argvalue in the form: + + SELECT pg_restore_relation_stats( + 'arg1name', 'arg1value'::arg1type, + 'arg2name', 'arg2value'::arg2type, + 'arg3name', 'arg3value'::arg3type); + - Ordinarily, these statistics are collected automatically or updated - as a part of or , so it's not necessary to call this - function. However, it may be useful when testing the effects of - statistics on the planner to understand or anticipate plan changes. + For example, to set the relpages and + reltuples of the table + mytable: + + SELECT pg_restore_relation_stats( + 'relation', 'mytable'::regclass, + 'relpages', 173::integer, + 'reltuples', 10000::real); + - The caller must have the MAINTAIN privilege on - the table or be the owner of the database. + The argument relation with a value of type + regclass is required, and specifies the table. Other + arguments are the names 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. - The value of relpages must be greater than - or equal to -1, - reltuples must be greater than or equal to - -1.0, and relallvisible - must be greater than or equal to 0. + Additionally, this function supports argument name + version of type integer, which + specifies the version from which the statistics originated, improving + interpretation of statistics from older versions of + PostgreSQL. + + + Minor errors are reported as a WARNING and + ignored, and remaining statistics will still be restored. If all + specified statistics are successfully restored, return + true, otherwise false. + + + The caller must have the MAINTAIN privilege on the + table or be the owner of the database. @@ -30234,8 +30265,8 @@ postgres=# SELECT '0/0'::pg_lsn + pd.segment_number * ps.setting::int + :offset table was newly created. - The caller must have the MAINTAIN privilege on - the table or be the owner of the database. + The caller must have the MAINTAIN privilege on the + table or be the owner of the database. @@ -30243,42 +30274,61 @@ postgres=# SELECT '0/0'::pg_lsn + pd.segment_number * ps.setting::int + :offset - pg_restore_relation_stats + pg_restore_attribute_stats - pg_restore_relation_stats ( + pg_restore_attribute_stats ( VARIADIC kwargs "any" ) boolean + + + Create or update column-level statistics. Ordinarily, these + statistics are collected automatically or updated as a part of or , so it's not + necessary to call this function. However, it is useful after a + restore to enable the optimizer to choose better plans if + ANALYZE has not been run yet. - Similar to pg_set_relation_stats(), but intended - for bulk restore of relation statistics. The tracked statistics may - change from version to version, so the primary purpose of this - function is to maintain a consistent function signature to avoid - errors when restoring statistics from previous versions. + The tracked statistics may change from version to version, so + arguments are passed as pairs of argname + and argvalue in the form: + + SELECT pg_restore_attribute_stats( + 'arg1name', 'arg1value'::arg1type, + 'arg2name', 'arg2value'::arg2type, + 'arg3name', 'arg3value'::arg3type); + - Arguments are passed as pairs of argname - and argvalue, where - argname corresponds to a named argument in - pg_set_relation_stats() and - argvalue is of the corresponding type. + For example, to set the avg_width and + null_frac for the attribute + col1 of the table + mytable: + + SELECT pg_restore_attribute_stats( + 'relation', 'mytable'::regclass, + 'attname', 'col1'::name, + '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; + attname with a value of type name, + which specifies the column; and inherited, which + specifies whether the statistics includes values from child tables. + Other arguments are the names of statistics corresponding to columns + in pg_stats. Additionally, this function supports argument name version of type integer, which specifies the version from which the statistics originated, improving - interpretation of older statistics. - - - For example, to set the relpages and - reltuples of the table - mytable: - - SELECT pg_restore_relation_stats( - 'relation', 'mytable'::regclass, - 'relpages', 173::integer, - 'reltuples', 10000::float4); - + interpretation of statistics from older versions of + PostgreSQL. Minor errors are reported as a WARNING and @@ -30286,53 +30336,9 @@ postgres=# SELECT '0/0'::pg_lsn + pd.segment_number * ps.setting::int + :offset specified statistics are successfully restored, return true, otherwise false. - - - - - - - - pg_set_attribute_stats - - pg_set_attribute_stats ( - relation regclass, - attname name, - inherited boolean - , null_frac real - , avg_width integer - , n_distinct real - , most_common_vals text, most_common_freqs real[] - , histogram_bounds text - , correlation real - , most_common_elems text, most_common_elem_freqs real[] - , elem_count_histogram real[] - , range_length_histogram text - , range_empty_frac real - , range_bounds_histogram text ) - void - - Creates or updates attribute-level statistics for the given relation - and attribute name to the specified values. The parameters correspond - to attributes of the same name found in the pg_stats - view. - - - Optional parameters default to NULL, which leave - the corresponding statistic unchanged. - - - Ordinarily, these statistics are collected automatically or updated - as a part of or , so it's not necessary to call this - function. However, it may be useful when testing the effects of - statistics on the planner to understand or anticipate plan changes. - - - The caller must have the MAINTAIN privilege on - the table or be the owner of the database. + The caller must have the MAINTAIN privilege on the + table or be the owner of the database. @@ -30350,8 +30356,8 @@ postgres=# SELECT '0/0'::pg_lsn + pd.segment_number * ps.setting::int + :offset void - Clears table-level statistics for the given relation attribute, as - though the table was newly created. + Clears column-level statistics for the given relation and + attribute, as though the table was newly created. The caller must have the MAINTAIN privilege on @@ -30359,58 +30365,6 @@ postgres=# SELECT '0/0'::pg_lsn + pd.segment_number * ps.setting::int + :offset - - - - - pg_restore_attribute_stats - - pg_restore_attribute_stats ( - VARIADIC kwargs "any" ) - boolean - - - Similar to pg_set_attribute_stats(), but - intended for bulk restore of attribute statistics. The tracked - statistics may change from version to version, so the primary purpose - of this function is to maintain a consistent function signature to - avoid errors when restoring statistics from previous versions. - - - Arguments are passed as pairs of argname - and argvalue, where - argname corresponds to a named argument in - pg_set_attribute_stats() and - argvalue is of the corresponding type. - - - Additionally, this function supports argument name - version of type integer, which - specifies the version from which the statistics originated, improving - interpretation of older statistics. - - - For example, to set the avg_width and - null_frac for the attribute - col1 of the table - mytable: - - SELECT pg_restore_attribute_stats( - 'relation', 'mytable'::regclass, - 'attname', 'col1'::name, - 'inherited', false, - 'avg_width', 125::integer, - 'null_frac', 0.5::real); - - - - Minor errors are reported as a WARNING and - ignored, and remaining statistics will still be restored. If all - specified statistics are successfully restored, return - true, otherwise false. - - - diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql index 591157b1d1b..86888cd3201 100644 --- a/src/backend/catalog/system_functions.sql +++ b/src/backend/catalog/system_functions.sql @@ -636,38 +636,6 @@ LANGUAGE INTERNAL CALLED ON NULL INPUT VOLATILE PARALLEL SAFE AS 'pg_stat_reset_slru'; -CREATE OR REPLACE FUNCTION - pg_set_relation_stats(relation regclass, - relpages integer DEFAULT NULL, - reltuples real DEFAULT NULL, - relallvisible integer DEFAULT NULL) -RETURNS void -LANGUAGE INTERNAL -CALLED ON NULL INPUT VOLATILE -AS 'pg_set_relation_stats'; - -CREATE OR REPLACE FUNCTION - pg_set_attribute_stats(relation regclass, - attname name, - inherited bool, - null_frac real DEFAULT NULL, - avg_width integer DEFAULT NULL, - n_distinct real DEFAULT NULL, - most_common_vals text DEFAULT NULL, - most_common_freqs real[] DEFAULT NULL, - histogram_bounds text DEFAULT NULL, - correlation real DEFAULT NULL, - most_common_elems text DEFAULT NULL, - most_common_elem_freqs real[] DEFAULT NULL, - elem_count_histogram real[] DEFAULT NULL, - range_length_histogram text DEFAULT NULL, - range_empty_frac real DEFAULT NULL, - range_bounds_histogram text DEFAULT NULL) -RETURNS void -LANGUAGE INTERNAL -CALLED ON NULL INPUT VOLATILE -AS 'pg_set_attribute_stats'; - -- -- The default permissions for functions mean that anyone can execute them. -- A number of functions shouldn't be executable by just anyone, but rather diff --git a/src/backend/statistics/attribute_stats.c b/src/backend/statistics/attribute_stats.c index c0c398a4bb2..66a5676c810 100644 --- a/src/backend/statistics/attribute_stats.c +++ b/src/backend/statistics/attribute_stats.c @@ -76,16 +76,16 @@ static struct StatsArgInfo attarginfo[] = [NUM_ATTRIBUTE_STATS_ARGS] = {0} }; -static bool attribute_statistics_update(FunctionCallInfo fcinfo, int elevel); +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, int elevel, +static void get_attr_stat_type(Oid reloid, AttrNumber attnum, Oid *atttypid, int32 *atttypmod, char *atttyptype, Oid *atttypcoll, Oid *eq_opr, Oid *lt_opr); -static bool get_elem_stat_type(Oid atttypid, char atttyptype, int elevel, +static bool get_elem_stat_type(Oid atttypid, char atttyptype, Oid *elemtypid, Oid *elem_eq_opr); static Datum text_to_stavalues(const char *staname, FmgrInfo *array_in, Datum d, - Oid typid, int32 typmod, int elevel, bool *ok); + Oid typid, int32 typmod, bool *ok); static void set_stats_slot(Datum *values, bool *nulls, bool *replaces, int16 stakind, Oid staop, Oid stacoll, Datum stanumbers, bool stanumbers_isnull, @@ -109,11 +109,11 @@ static void init_empty_stats_tuple(Oid reloid, int16 attnum, bool inherited, * * 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 at 'elevel', + * as a conversion failure on one statistic kind, are reported as a WARNING * and other statistic kinds may still be updated. */ static bool -attribute_statistics_update(FunctionCallInfo fcinfo, int elevel) +attribute_statistics_update(FunctionCallInfo fcinfo) { Oid reloid; Name attname; @@ -184,33 +184,29 @@ attribute_statistics_update(FunctionCallInfo fcinfo, int elevel) inherited = PG_GETARG_BOOL(INHERITED_ARG); /* - * Check argument sanity. If some arguments are unusable, emit at elevel + * Check argument sanity. If some arguments are unusable, emit a WARNING * and set the corresponding argument to NULL in fcinfo. */ - if (!stats_check_arg_array(fcinfo, attarginfo, MOST_COMMON_FREQS_ARG, - elevel)) + if (!stats_check_arg_array(fcinfo, attarginfo, MOST_COMMON_FREQS_ARG)) { do_mcv = false; result = false; } - if (!stats_check_arg_array(fcinfo, attarginfo, MOST_COMMON_ELEM_FREQS_ARG, - elevel)) + if (!stats_check_arg_array(fcinfo, attarginfo, MOST_COMMON_ELEM_FREQS_ARG)) { do_mcelem = false; result = false; } - if (!stats_check_arg_array(fcinfo, attarginfo, ELEM_COUNT_HISTOGRAM_ARG, - elevel)) + if (!stats_check_arg_array(fcinfo, attarginfo, ELEM_COUNT_HISTOGRAM_ARG)) { do_dechist = false; result = false; } if (!stats_check_arg_pair(fcinfo, attarginfo, - MOST_COMMON_VALS_ARG, MOST_COMMON_FREQS_ARG, - elevel)) + MOST_COMMON_VALS_ARG, MOST_COMMON_FREQS_ARG)) { do_mcv = false; result = false; @@ -218,7 +214,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo, int elevel) if (!stats_check_arg_pair(fcinfo, attarginfo, MOST_COMMON_ELEMS_ARG, - MOST_COMMON_ELEM_FREQS_ARG, elevel)) + MOST_COMMON_ELEM_FREQS_ARG)) { do_mcelem = false; result = false; @@ -226,14 +222,14 @@ attribute_statistics_update(FunctionCallInfo fcinfo, int elevel) if (!stats_check_arg_pair(fcinfo, attarginfo, RANGE_LENGTH_HISTOGRAM_ARG, - RANGE_EMPTY_FRAC_ARG, elevel)) + RANGE_EMPTY_FRAC_ARG)) { do_range_length_histogram = false; result = false; } /* derive information from attribute */ - get_attr_stat_type(reloid, attnum, elevel, + get_attr_stat_type(reloid, attnum, &atttypid, &atttypmod, &atttyptype, &atttypcoll, &eq_opr, <_opr); @@ -241,10 +237,10 @@ attribute_statistics_update(FunctionCallInfo fcinfo, int elevel) /* if needed, derive element type */ if (do_mcelem || do_dechist) { - if (!get_elem_stat_type(atttypid, atttyptype, elevel, + if (!get_elem_stat_type(atttypid, atttyptype, &elemtypid, &elem_eq_opr)) { - ereport(elevel, + ereport(WARNING, (errmsg("unable to determine element type of attribute \"%s\"", NameStr(*attname)), errdetail("Cannot set STATISTIC_KIND_MCELEM or STATISTIC_KIND_DECHIST."))); elemtypid = InvalidOid; @@ -259,7 +255,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo, int elevel) /* histogram and correlation require less-than operator */ if ((do_histogram || do_correlation) && !OidIsValid(lt_opr)) { - ereport(elevel, + ereport(WARNING, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("could not determine less-than operator for attribute \"%s\"", NameStr(*attname)), errdetail("Cannot set STATISTIC_KIND_HISTOGRAM or STATISTIC_KIND_CORRELATION."))); @@ -273,7 +269,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo, int elevel) if ((do_range_length_histogram || do_bounds_histogram) && !(atttyptype == TYPTYPE_RANGE || atttyptype == TYPTYPE_MULTIRANGE)) { - ereport(elevel, + ereport(WARNING, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("attribute \"%s\" is not a range type", NameStr(*attname)), errdetail("Cannot set STATISTIC_KIND_RANGE_LENGTH_HISTOGRAM or STATISTIC_KIND_BOUNDS_HISTOGRAM."))); @@ -322,7 +318,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo, int elevel) &array_in_fn, PG_GETARG_DATUM(MOST_COMMON_VALS_ARG), atttypid, atttypmod, - elevel, &converted); + &converted); if (converted) { @@ -344,7 +340,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo, int elevel) stavalues = text_to_stavalues("histogram_bounds", &array_in_fn, PG_GETARG_DATUM(HISTOGRAM_BOUNDS_ARG), - atttypid, atttypmod, elevel, + atttypid, atttypmod, &converted); if (converted) @@ -382,7 +378,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo, int elevel) &array_in_fn, PG_GETARG_DATUM(MOST_COMMON_ELEMS_ARG), elemtypid, atttypmod, - elevel, &converted); + &converted); if (converted) { @@ -422,7 +418,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo, int elevel) &array_in_fn, PG_GETARG_DATUM(RANGE_BOUNDS_HISTOGRAM_ARG), atttypid, atttypmod, - elevel, &converted); + &converted); if (converted) { @@ -449,7 +445,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo, int elevel) stavalues = text_to_stavalues("range_length_histogram", &array_in_fn, PG_GETARG_DATUM(RANGE_LENGTH_HISTOGRAM_ARG), - FLOAT8OID, 0, elevel, &converted); + FLOAT8OID, 0, &converted); if (converted) { @@ -517,7 +513,7 @@ get_attr_expr(Relation rel, int attnum) * Derive type information from the attribute. */ static void -get_attr_stat_type(Oid reloid, AttrNumber attnum, int elevel, +get_attr_stat_type(Oid reloid, AttrNumber attnum, Oid *atttypid, int32 *atttypmod, char *atttyptype, Oid *atttypcoll, Oid *eq_opr, Oid *lt_opr) @@ -599,7 +595,7 @@ get_attr_stat_type(Oid reloid, AttrNumber attnum, int elevel, * Derive element type information from the attribute type. */ static bool -get_elem_stat_type(Oid atttypid, char atttyptype, int elevel, +get_elem_stat_type(Oid atttypid, char atttyptype, Oid *elemtypid, Oid *elem_eq_opr) { TypeCacheEntry *elemtypcache; @@ -634,13 +630,13 @@ get_elem_stat_type(Oid atttypid, char atttyptype, int elevel, /* * Cast a text datum into an array with element type elemtypid. * - * If an error is encountered, capture it and re-throw at elevel, and set ok - * to false. If the resulting array contains NULLs, raise an error at elevel - * and set ok to false. Otherwise, set ok to true. + * If an error is encountered, capture it and re-throw a WARNING, and set ok + * to false. If the resulting array contains NULLs, raise a WARNING and set ok + * to false. Otherwise, set ok to true. */ static Datum text_to_stavalues(const char *staname, FmgrInfo *array_in, Datum d, Oid typid, - int32 typmod, int elevel, bool *ok) + int32 typmod, bool *ok) { LOCAL_FCINFO(fcinfo, 8); char *s; @@ -667,8 +663,7 @@ text_to_stavalues(const char *staname, FmgrInfo *array_in, Datum d, Oid typid, if (escontext.error_occurred) { - if (elevel != ERROR) - escontext.error_data->elevel = elevel; + escontext.error_data->elevel = WARNING; ThrowErrorData(escontext.error_data); *ok = false; return (Datum) 0; @@ -676,7 +671,7 @@ text_to_stavalues(const char *staname, FmgrInfo *array_in, Datum d, Oid typid, if (array_contains_nulls(DatumGetArrayTypeP(result))) { - ereport(elevel, + ereport(WARNING, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("\"%s\" array cannot contain NULL values", staname))); *ok = false; @@ -851,33 +846,6 @@ init_empty_stats_tuple(Oid reloid, int16 attnum, bool inherited, } } -/* - * Import statistics for a given relation attribute. - * - * Inserts or replaces a row in pg_statistic for the given relation and - * attribute name. It takes input parameters that correspond to columns in the - * view pg_stats. - * - * Parameters null_frac, avg_width, and n_distinct all correspond to NOT NULL - * columns in pg_statistic. The remaining parameters all belong to a specific - * stakind. Some stakinds require multiple parameters, which must be specified - * together (or neither specified). - * - * Parameters are only superficially validated. Omitting a parameter or - * passing NULL leaves the statistic unchanged. - * - * Parameters corresponding to ANYARRAY columns are instead passed in as text - * values, which is a valid input string for an array of the type or element - * type of the attribute. Any error generated by the array_in() function will - * in turn fail the function. - */ -Datum -pg_set_attribute_stats(PG_FUNCTION_ARGS) -{ - attribute_statistics_update(fcinfo, ERROR); - PG_RETURN_VOID(); -} - /* * Delete statistics for the given attribute. */ @@ -933,10 +901,10 @@ pg_restore_attribute_stats(PG_FUNCTION_ARGS) InvalidOid, NULL, NULL); if (!stats_fill_fcinfo_from_arg_pairs(fcinfo, positional_fcinfo, - attarginfo, WARNING)) + attarginfo)) result = false; - if (!attribute_statistics_update(positional_fcinfo, WARNING)) + if (!attribute_statistics_update(positional_fcinfo)) result = false; PG_RETURN_BOOL(result); diff --git a/src/backend/statistics/relation_stats.c b/src/backend/statistics/relation_stats.c index 66731290a3e..11b1ef2dbc2 100644 --- a/src/backend/statistics/relation_stats.c +++ b/src/backend/statistics/relation_stats.c @@ -48,13 +48,13 @@ static struct StatsArgInfo relarginfo[] = [NUM_RELATION_STATS_ARGS] = {0} }; -static bool relation_statistics_update(FunctionCallInfo fcinfo, int elevel); +static bool relation_statistics_update(FunctionCallInfo fcinfo); /* * Internal function for modifying statistics for a relation. */ static bool -relation_statistics_update(FunctionCallInfo fcinfo, int elevel) +relation_statistics_update(FunctionCallInfo fcinfo) { bool result = true; Oid reloid; @@ -83,7 +83,7 @@ relation_statistics_update(FunctionCallInfo fcinfo, int elevel) reltuples = PG_GETARG_FLOAT4(RELTUPLES_ARG); if (reltuples < -1.0) { - ereport(elevel, + ereport(WARNING, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("reltuples cannot be < -1.0"))); result = false; @@ -118,7 +118,7 @@ relation_statistics_update(FunctionCallInfo fcinfo, int elevel) ctup = SearchSysCache1(RELOID, ObjectIdGetDatum(reloid)); if (!HeapTupleIsValid(ctup)) { - ereport(elevel, + ereport(WARNING, (errcode(ERRCODE_OBJECT_IN_USE), errmsg("pg_class entry for relid %u not found", reloid))); table_close(crel, RowExclusiveLock); @@ -169,16 +169,6 @@ relation_statistics_update(FunctionCallInfo fcinfo, int elevel) return result; } -/* - * Set statistics for a given pg_class entry. - */ -Datum -pg_set_relation_stats(PG_FUNCTION_ARGS) -{ - relation_statistics_update(fcinfo, ERROR); - PG_RETURN_VOID(); -} - /* * Clear statistics for a given pg_class entry; that is, set back to initial * stats for a newly-created table. @@ -199,7 +189,7 @@ pg_clear_relation_stats(PG_FUNCTION_ARGS) newfcinfo->args[3].value = UInt32GetDatum(0); newfcinfo->args[3].isnull = false; - relation_statistics_update(newfcinfo, ERROR); + relation_statistics_update(newfcinfo); PG_RETURN_VOID(); } @@ -214,10 +204,10 @@ pg_restore_relation_stats(PG_FUNCTION_ARGS) InvalidOid, NULL, NULL); if (!stats_fill_fcinfo_from_arg_pairs(fcinfo, positional_fcinfo, - relarginfo, WARNING)) + relarginfo)) result = false; - if (!relation_statistics_update(positional_fcinfo, WARNING)) + if (!relation_statistics_update(positional_fcinfo)) result = false; PG_RETURN_BOOL(result); diff --git a/src/backend/statistics/stat_utils.c b/src/backend/statistics/stat_utils.c index e70ea1ce738..54ead90b5bb 100644 --- a/src/backend/statistics/stat_utils.c +++ b/src/backend/statistics/stat_utils.c @@ -48,13 +48,13 @@ stats_check_required_arg(FunctionCallInfo fcinfo, * Check that argument is either NULL or a one dimensional array with no * NULLs. * - * If a problem is found, emit at elevel, and return false. Otherwise return + * If a problem is found, emit a WARNING, and return false. Otherwise return * true. */ bool stats_check_arg_array(FunctionCallInfo fcinfo, struct StatsArgInfo *arginfo, - int argnum, int elevel) + int argnum) { ArrayType *arr; @@ -65,7 +65,7 @@ stats_check_arg_array(FunctionCallInfo fcinfo, if (ARR_NDIM(arr) != 1) { - ereport(elevel, + ereport(WARNING, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("\"%s\" cannot be a multidimensional array", arginfo[argnum].argname))); @@ -74,7 +74,7 @@ stats_check_arg_array(FunctionCallInfo fcinfo, if (array_contains_nulls(arr)) { - ereport(elevel, + ereport(WARNING, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("\"%s\" array cannot contain NULL values", arginfo[argnum].argname))); @@ -89,13 +89,13 @@ stats_check_arg_array(FunctionCallInfo fcinfo, * a particular stakind, such as most_common_vals and most_common_freqs for * STATISTIC_KIND_MCV. * - * If a problem is found, emit at elevel, and return false. Otherwise return + * If a problem is found, emit a WARNING, and return false. Otherwise return * true. */ bool stats_check_arg_pair(FunctionCallInfo fcinfo, struct StatsArgInfo *arginfo, - int argnum1, int argnum2, int elevel) + int argnum1, int argnum2) { if (PG_ARGISNULL(argnum1) && PG_ARGISNULL(argnum2)) return true; @@ -105,7 +105,7 @@ stats_check_arg_pair(FunctionCallInfo fcinfo, int nullarg = PG_ARGISNULL(argnum1) ? argnum1 : argnum2; int otherarg = PG_ARGISNULL(argnum1) ? argnum2 : argnum1; - ereport(elevel, + ereport(WARNING, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("\"%s\" must be specified when \"%s\" is specified", arginfo[nullarg].argname, @@ -216,7 +216,7 @@ stats_lock_check_privileges(Oid reloid) * found. */ static int -get_arg_by_name(const char *argname, struct StatsArgInfo *arginfo, int elevel) +get_arg_by_name(const char *argname, struct StatsArgInfo *arginfo) { int argnum; @@ -224,7 +224,7 @@ get_arg_by_name(const char *argname, struct StatsArgInfo *arginfo, int elevel) if (pg_strcasecmp(argname, arginfo[argnum].argname) == 0) return argnum; - ereport(elevel, + ereport(WARNING, (errmsg("unrecognized argument name: \"%s\"", argname))); return -1; @@ -234,11 +234,11 @@ get_arg_by_name(const char *argname, struct StatsArgInfo *arginfo, int elevel) * Ensure that a given argument matched the expected type. */ static bool -stats_check_arg_type(const char *argname, Oid argtype, Oid expectedtype, int elevel) +stats_check_arg_type(const char *argname, Oid argtype, Oid expectedtype) { if (argtype != expectedtype) { - ereport(elevel, + ereport(WARNING, (errmsg("argument \"%s\" has type \"%s\", expected type \"%s\"", argname, format_type_be(argtype), format_type_be(expectedtype)))); @@ -260,8 +260,7 @@ stats_check_arg_type(const char *argname, Oid argtype, Oid expectedtype, int ele bool stats_fill_fcinfo_from_arg_pairs(FunctionCallInfo pairs_fcinfo, FunctionCallInfo positional_fcinfo, - struct StatsArgInfo *arginfo, - int elevel) + struct StatsArgInfo *arginfo) { Datum *args; bool *argnulls; @@ -319,11 +318,10 @@ stats_fill_fcinfo_from_arg_pairs(FunctionCallInfo pairs_fcinfo, if (pg_strcasecmp(argname, "version") == 0) continue; - argnum = get_arg_by_name(argname, arginfo, elevel); + argnum = get_arg_by_name(argname, arginfo); if (argnum < 0 || !stats_check_arg_type(argname, types[i + 1], - arginfo[argnum].argtype, - elevel)) + arginfo[argnum].argtype)) { result = false; continue; diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index f6a99472e76..12163ae94be 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -57,6 +57,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 202502241 +#define CATALOG_VERSION_NO 202502242 #endif diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index af9546de23d..1c1d96e0c7e 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -1,4 +1,4 @@ -#---------------------------------------------------------------------- +\#---------------------------------------------------------------------- # # pg_proc.dat # Initial contents of the pg_proc system catalog. @@ -12420,7 +12420,14 @@ proargnames => '{kwargs}', proargmodes => '{v}', prosrc => 'pg_restore_relation_stats' }, -{ oid => '8460', +{ oid => '9160', + descr => 'clear statistics on relation', + proname => 'pg_clear_relation_stats', provolatile => 'v', proisstrict => 'f', + proparallel => 'u', prorettype => 'void', + proargtypes => 'regclass', + proargnames => '{relation}', + prosrc => 'pg_clear_relation_stats' }, +{ oid => '8461', descr => 'restore statistics on attribute', proname => 'pg_restore_attribute_stats', provolatile => 'v', proisstrict => 'f', provariadic => 'any', @@ -12430,33 +12437,12 @@ proargmodes => '{v}', prosrc => 'pg_restore_attribute_stats' }, { oid => '9162', - descr => 'set statistics on attribute', - proname => 'pg_set_attribute_stats', provolatile => 'v', proisstrict => 'f', - proparallel => 'u', prorettype => 'void', - proargtypes => 'regclass name bool float4 int4 float4 text _float4 text float4 text _float4 _float4 text float4 text', - proargnames => '{relation,attname,inherited,null_frac,avg_width,n_distinct,most_common_vals,most_common_freqs,histogram_bounds,correlation,most_common_elems,most_common_elem_freqs,elem_count_histogram,range_length_histogram,range_empty_frac,range_bounds_histogram}', - prosrc => 'pg_set_attribute_stats' }, -{ oid => '9163', 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}', prosrc => 'pg_clear_attribute_stats' }, -{ oid => '9944', - descr => 'set statistics on relation', - proname => 'pg_set_relation_stats', provolatile => 'v', proisstrict => 'f', - proparallel => 'u', prorettype => 'void', - proargtypes => 'regclass int4 float4 int4', - proargnames => '{relation,relpages,reltuples,relallvisible}', - prosrc => 'pg_set_relation_stats' }, -{ oid => '9945', - descr => 'clear statistics on relation', - proname => 'pg_clear_relation_stats', provolatile => 'v', proisstrict => 'f', - proparallel => 'u', prorettype => 'void', - proargtypes => 'regclass', - proargnames => '{relation}', - prosrc => 'pg_clear_relation_stats' }, # GiST stratnum implementations { oid => '8047', descr => 'GiST support', diff --git a/src/include/statistics/stat_utils.h b/src/include/statistics/stat_utils.h index 6edb5ea0321..0eb4decfcac 100644 --- a/src/include/statistics/stat_utils.h +++ b/src/include/statistics/stat_utils.h @@ -25,17 +25,15 @@ extern void stats_check_required_arg(FunctionCallInfo fcinfo, struct StatsArgInfo *arginfo, int argnum); extern bool stats_check_arg_array(FunctionCallInfo fcinfo, - struct StatsArgInfo *arginfo, int argnum, - int elevel); + struct StatsArgInfo *arginfo, int argnum); extern bool stats_check_arg_pair(FunctionCallInfo fcinfo, struct StatsArgInfo *arginfo, - int argnum1, int argnum2, int elevel); + int argnum1, int argnum2); extern void stats_lock_check_privileges(Oid reloid); extern bool stats_fill_fcinfo_from_arg_pairs(FunctionCallInfo pairs_fcinfo, FunctionCallInfo positional_fcinfo, - struct StatsArgInfo *arginfo, - int elevel); + struct StatsArgInfo *arginfo); #endif /* STATS_UTILS_H */ diff --git a/src/test/regress/expected/stats_import.out b/src/test/regress/expected/stats_import.out index d6713eacc2c..7e8b7f429c9 100644 --- a/src/test/regress/expected/stats_import.out +++ b/src/test/regress/expected/stats_import.out @@ -12,6 +12,7 @@ CREATE TABLE stats_import.test( arange int4range, tags text[] ) WITH (autovacuum_enabled = false); +CREATE INDEX test_i ON stats_import.test(id); -- starting stats SELECT relpages, reltuples, relallvisible FROM pg_class @@ -21,80 +22,15 @@ WHERE oid = 'stats_import.test'::regclass; 0 | -1 | 0 (1 row) --- error: regclass not found -SELECT - pg_catalog.pg_set_relation_stats( - relation => 0::Oid, - relpages => 17::integer, - reltuples => 400.0::real, - relallvisible => 4::integer); -ERROR: could not open relation with OID 0 --- relpages default -SELECT - pg_catalog.pg_set_relation_stats( - relation => 'stats_import.test'::regclass, - relpages => NULL::integer, - reltuples => 400.0::real, - relallvisible => 4::integer); - pg_set_relation_stats ------------------------ - -(1 row) - --- reltuples default -SELECT - pg_catalog.pg_set_relation_stats( - relation => 'stats_import.test'::regclass, - relpages => 17::integer, - reltuples => NULL::real, - relallvisible => 4::integer); - pg_set_relation_stats ------------------------ - -(1 row) - --- relallvisible default -SELECT - pg_catalog.pg_set_relation_stats( - relation => 'stats_import.test'::regclass, - relpages => 17::integer, - reltuples => 400.0::real, - relallvisible => NULL::integer); - pg_set_relation_stats ------------------------ - -(1 row) - --- named arguments -SELECT - pg_catalog.pg_set_relation_stats( - relation => 'stats_import.test'::regclass, - relpages => 17::integer, - reltuples => 400.0::real, - relallvisible => 4::integer); - pg_set_relation_stats ------------------------ - -(1 row) - -SELECT relpages, reltuples, relallvisible -FROM pg_class -WHERE oid = 'stats_import.test'::regclass; - relpages | reltuples | relallvisible -----------+-----------+--------------- - 17 | 400 | 4 -(1 row) - -CREATE INDEX test_i ON stats_import.test(id); BEGIN; -- regular indexes have special case locking rules SELECT - pg_catalog.pg_set_relation_stats( - relation => 'stats_import.test_i'::regclass, - relpages => 18::integer); - pg_set_relation_stats ------------------------ - + pg_catalog.pg_restore_relation_stats( + 'relation', 'stats_import.test_i'::regclass, + 'relpages', 18::integer); + pg_restore_relation_stats +--------------------------- + t (1 row) SELECT mode FROM pg_locks @@ -123,34 +59,6 @@ SELECT t (1 row) --- positional arguments -SELECT - pg_catalog.pg_set_relation_stats( - 'stats_import.test'::regclass, - 18::integer, - 401.0::real, - 5::integer); - pg_set_relation_stats ------------------------ - -(1 row) - -SELECT relpages, reltuples, relallvisible -FROM pg_class -WHERE oid = 'stats_import.test'::regclass; - relpages | reltuples | relallvisible -----------+-----------+--------------- - 18 | 401 | 5 -(1 row) - -SELECT relpages, reltuples, relallvisible -FROM pg_class -WHERE oid = 'stats_import.test'::regclass; - relpages | reltuples | relallvisible -----------+-----------+--------------- - 18 | 401 | 5 -(1 row) - -- clear SELECT pg_catalog.pg_clear_relation_stats( @@ -168,19 +76,6 @@ WHERE oid = 'stats_import.test'::regclass; 0 | -1 | 0 (1 row) --- invalid relkinds for statistics -CREATE SEQUENCE stats_import.testseq; -CREATE VIEW stats_import.testview AS SELECT * FROM stats_import.test; -SELECT - pg_catalog.pg_clear_relation_stats( - 'stats_import.testseq'::regclass); -ERROR: cannot modify statistics for relation "testseq" -DETAIL: This operation is not supported for sequences. -SELECT - pg_catalog.pg_clear_relation_stats( - 'stats_import.testview'::regclass); -ERROR: cannot modify statistics for relation "testview" -DETAIL: This operation is not supported for views. -- relpages may be -1 for partitioned tables CREATE TABLE stats_import.part_parent ( i integer ) PARTITION BY RANGE(i); CREATE TABLE stats_import.part_child_1 @@ -200,21 +95,21 @@ WHERE oid = 'stats_import.part_parent'::regclass; -- although partitioned tables have no storage, setting relpages to a -- positive value is still allowed SELECT - pg_catalog.pg_set_relation_stats( - relation => 'stats_import.part_parent_i'::regclass, - relpages => 2::integer); - pg_set_relation_stats ------------------------ - + pg_catalog.pg_restore_relation_stats( + 'relation', 'stats_import.part_parent_i'::regclass, + 'relpages', 2::integer); + pg_restore_relation_stats +--------------------------- + t (1 row) SELECT - pg_catalog.pg_set_relation_stats( - relation => 'stats_import.part_parent'::regclass, - relpages => 2::integer); - pg_set_relation_stats ------------------------ - + pg_catalog.pg_restore_relation_stats( + 'relation', 'stats_import.part_parent'::regclass, + 'relpages', 2::integer); + pg_restore_relation_stats +--------------------------- + t (1 row) -- @@ -225,12 +120,12 @@ SELECT -- BEGIN; SELECT - pg_catalog.pg_set_relation_stats( - relation => 'stats_import.part_parent_i'::regclass, - relpages => 2::integer); - pg_set_relation_stats ------------------------ - + pg_catalog.pg_restore_relation_stats( + 'relation', 'stats_import.part_parent_i'::regclass, + 'relpages', 2::integer); + pg_restore_relation_stats +--------------------------- + t (1 row) SELECT mode FROM pg_locks @@ -261,527 +156,14 @@ SELECT -- nothing stops us from setting it to -1 SELECT - pg_catalog.pg_set_relation_stats( - relation => 'stats_import.part_parent'::regclass, - relpages => -1::integer); - pg_set_relation_stats ------------------------ - + pg_catalog.pg_restore_relation_stats( + 'relation', 'stats_import.part_parent'::regclass, + 'relpages', -1::integer); + pg_restore_relation_stats +--------------------------- + t (1 row) --- error: object doesn't exist -SELECT pg_catalog.pg_set_attribute_stats( - relation => '0'::oid, - attname => 'id'::name, - inherited => false::boolean, - null_frac => 0.1::real, - avg_width => 2::integer, - n_distinct => 0.3::real); -ERROR: could not open relation with OID 0 --- error: object doesn't exist -SELECT pg_catalog.pg_clear_attribute_stats( - relation => '0'::oid, - attname => 'id'::name, - inherited => false::boolean); -ERROR: could not open relation with OID 0 --- error: relation null -SELECT pg_catalog.pg_set_attribute_stats( - relation => NULL::oid, - attname => 'id'::name, - inherited => false::boolean, - null_frac => 0.1::real, - avg_width => 2::integer, - n_distinct => 0.3::real); -ERROR: "relation" cannot be NULL --- error: attribute is system column -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'xmin'::name, - inherited => false::boolean, - null_frac => 0.1::real, - avg_width => 2::integer, - n_distinct => 0.3::real); -ERROR: cannot modify statistics on system column "xmin" --- error: attname doesn't exist -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'nope'::name, - 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: attribute is system column -SELECT pg_catalog.pg_clear_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'ctid'::name, - inherited => false::boolean); -ERROR: cannot clear statistics on system column "ctid" --- error: attname doesn't exist -SELECT pg_catalog.pg_clear_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'nope'::name, - inherited => false::boolean); -ERROR: column "nope" of relation "test" does not exist --- error: attname null -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => NULL::name, - inherited => false::boolean, - null_frac => 0.1::real, - avg_width => 2::integer, - n_distinct => 0.3::real); -ERROR: "attname" cannot be NULL --- error: inherited null -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'id'::name, - inherited => NULL::boolean, - null_frac => 0.1::real, - avg_width => 2::integer, - n_distinct => 0.3::real); -ERROR: "inherited" cannot be NULL --- ok: no stakinds -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'id'::name, - inherited => false::boolean, - null_frac => 0.1::real, - avg_width => 2::integer, - n_distinct => 0.3::real); - pg_set_attribute_stats ------------------------- - -(1 row) - -SELECT stanullfrac, stawidth, stadistinct -FROM pg_statistic -WHERE starelid = 'stats_import.test'::regclass; - stanullfrac | stawidth | stadistinct --------------+----------+------------- - 0.1 | 2 | 0.3 -(1 row) - --- error: mcv / mcf null mismatch -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'id'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - most_common_freqs => '{0.1,0.2,0.3}'::real[] - ); -ERROR: "most_common_vals" must be specified when "most_common_freqs" is specified --- error: mcv / mcf null mismatch part 2 -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'id'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - most_common_vals => '{1,2,3}'::text - ); -ERROR: "most_common_freqs" must be specified when "most_common_vals" is specified --- error: mcv / mcf type mismatch -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'id'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - most_common_vals => '{2023-09-30,2024-10-31,3}'::text, - most_common_freqs => '{0.2,0.1}'::real[] - ); -ERROR: invalid input syntax for type integer: "2023-09-30" --- error: mcv cast failure -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'id'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - most_common_vals => '{2,four,3}'::text, - most_common_freqs => '{0.3,0.25,0.05}'::real[] - ); -ERROR: invalid input syntax for type integer: "four" --- ok: mcv+mcf -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'id'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - most_common_vals => '{2,1,3}'::text, - most_common_freqs => '{0.3,0.25,0.05}'::real[] - ); - pg_set_attribute_stats ------------------------- - -(1 row) - -SELECT * -FROM pg_stats -WHERE schemaname = 'stats_import' -AND tablename = 'test' -AND inherited = false -AND attname = 'id'; - schemaname | tablename | attname | inherited | null_frac | avg_width | n_distinct | most_common_vals | most_common_freqs | histogram_bounds | correlation | most_common_elems | most_common_elem_freqs | elem_count_histogram | range_length_histogram | range_empty_frac | range_bounds_histogram ---------------+-----------+---------+-----------+-----------+-----------+------------+------------------+-------------------+------------------+-------------+-------------------+------------------------+----------------------+------------------------+------------------+------------------------ - stats_import | test | id | f | 0.5 | 2 | -0.1 | {2,1,3} | {0.3,0.25,0.05} | | | | | | | | -(1 row) - --- error: histogram elements null value --- this generates no warnings, but perhaps it should -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'id'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - histogram_bounds => '{1,NULL,3,4}'::text - ); -ERROR: "histogram_bounds" array cannot contain NULL values --- ok: histogram_bounds -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'id'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - histogram_bounds => '{1,2,3,4}'::text - ); - pg_set_attribute_stats ------------------------- - -(1 row) - -SELECT * -FROM pg_stats -WHERE schemaname = 'stats_import' -AND tablename = 'test' -AND inherited = false -AND attname = 'id'; - schemaname | tablename | attname | inherited | null_frac | avg_width | n_distinct | most_common_vals | most_common_freqs | histogram_bounds | correlation | most_common_elems | most_common_elem_freqs | elem_count_histogram | range_length_histogram | range_empty_frac | range_bounds_histogram ---------------+-----------+---------+-----------+-----------+-----------+------------+------------------+-------------------+------------------+-------------+-------------------+------------------------+----------------------+------------------------+------------------+------------------------ - stats_import | test | id | f | 0.5 | 2 | -0.1 | {2,1,3} | {0.3,0.25,0.05} | {1,2,3,4} | | | | | | | -(1 row) - --- ok: correlation -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'id'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - correlation => 0.5::real); - pg_set_attribute_stats ------------------------- - -(1 row) - -SELECT * -FROM pg_stats -WHERE schemaname = 'stats_import' -AND tablename = 'test' -AND inherited = false -AND attname = 'id'; - schemaname | tablename | attname | inherited | null_frac | avg_width | n_distinct | most_common_vals | most_common_freqs | histogram_bounds | correlation | most_common_elems | most_common_elem_freqs | elem_count_histogram | range_length_histogram | range_empty_frac | range_bounds_histogram ---------------+-----------+---------+-----------+-----------+-----------+------------+------------------+-------------------+------------------+-------------+-------------------+------------------------+----------------------+------------------------+------------------+------------------------ - stats_import | test | id | f | 0.5 | 2 | -0.1 | {2,1,3} | {0.3,0.25,0.05} | {1,2,3,4} | 0.5 | | | | | | -(1 row) - --- error: scalars can't have mcelem -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'id'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - most_common_elems => '{1,3}'::text, - most_common_elem_freqs => '{0.3,0.2,0.2,0.3,0.0}'::real[] - ); -ERROR: unable to determine element type of attribute "id" -DETAIL: Cannot set STATISTIC_KIND_MCELEM or STATISTIC_KIND_DECHIST. --- error: mcelem / mcelem mismatch -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'tags'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - most_common_elems => '{one,two}'::text - ); -ERROR: "most_common_elem_freqs" must be specified when "most_common_elems" is specified --- error: mcelem / mcelem null mismatch part 2 -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'tags'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - most_common_elem_freqs => '{0.3,0.2,0.2,0.3}'::real[] - ); -ERROR: "most_common_elems" must be specified when "most_common_elem_freqs" is specified --- ok: mcelem -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'tags'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - most_common_elems => '{one,three}'::text, - most_common_elem_freqs => '{0.3,0.2,0.2,0.3,0.0}'::real[] - ); - pg_set_attribute_stats ------------------------- - -(1 row) - -SELECT * -FROM pg_stats -WHERE schemaname = 'stats_import' -AND tablename = 'test' -AND inherited = false -AND attname = 'tags'; - schemaname | tablename | attname | inherited | null_frac | avg_width | n_distinct | most_common_vals | most_common_freqs | histogram_bounds | correlation | most_common_elems | most_common_elem_freqs | elem_count_histogram | range_length_histogram | range_empty_frac | range_bounds_histogram ---------------+-----------+---------+-----------+-----------+-----------+------------+------------------+-------------------+------------------+-------------+-------------------+------------------------+----------------------+------------------------+------------------+------------------------ - stats_import | test | tags | f | 0.5 | 2 | -0.1 | | | | | {one,three} | {0.3,0.2,0.2,0.3,0} | | | | -(1 row) - --- error: scalars can't have elem_count_histogram -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'id'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::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[] - ); -ERROR: unable to determine element type of attribute "id" -DETAIL: Cannot set STATISTIC_KIND_MCELEM or STATISTIC_KIND_DECHIST. --- error: elem_count_histogram null element -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'tags'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - elem_count_histogram => '{1,1,NULL,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,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[] - ); -ERROR: "elem_count_histogram" array cannot contain NULL values --- ok: elem_count_histogram -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'tags'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::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[] - ); - pg_set_attribute_stats ------------------------- - -(1 row) - -SELECT * -FROM pg_stats -WHERE schemaname = 'stats_import' -AND tablename = 'test' -AND inherited = false -AND attname = 'tags'; - schemaname | tablename | attname | inherited | null_frac | avg_width | n_distinct | most_common_vals | most_common_freqs | histogram_bounds | correlation | most_common_elems | most_common_elem_freqs | elem_count_histogram | range_length_histogram | range_empty_frac | range_bounds_histogram ---------------+-----------+---------+-----------+-----------+-----------+------------+------------------+-------------------+------------------+-------------+-------------------+------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------+------------------+------------------------ - stats_import | test | tags | f | 0.5 | 2 | -0.1 | | | | | {one,three} | {0.3,0.2,0.2,0.3,0} | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1} | | | -(1 row) - --- error: scalars can't have range stats -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'id'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - range_empty_frac => 0.5::real, - range_length_histogram => '{399,499,Infinity}'::text - ); -ERROR: attribute "id" is not a range type -DETAIL: Cannot set STATISTIC_KIND_RANGE_LENGTH_HISTOGRAM or STATISTIC_KIND_BOUNDS_HISTOGRAM. --- error: range_empty_frac range_length_hist null mismatch -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'arange'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - range_length_histogram => '{399,499,Infinity}'::text - ); -ERROR: "range_empty_frac" must be specified when "range_length_histogram" is specified --- error: range_empty_frac range_length_hist null mismatch part 2 -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'arange'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - range_empty_frac => 0.5::real - ); -ERROR: "range_length_histogram" must be specified when "range_empty_frac" is specified --- ok: range_empty_frac + range_length_hist -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'arange'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - range_empty_frac => 0.5::real, - range_length_histogram => '{399,499,Infinity}'::text - ); - pg_set_attribute_stats ------------------------- - -(1 row) - -SELECT * -FROM pg_stats -WHERE schemaname = 'stats_import' -AND tablename = 'test' -AND inherited = false -AND attname = 'arange'; - schemaname | tablename | attname | inherited | null_frac | avg_width | n_distinct | most_common_vals | most_common_freqs | histogram_bounds | correlation | most_common_elems | most_common_elem_freqs | elem_count_histogram | range_length_histogram | range_empty_frac | range_bounds_histogram ---------------+-----------+---------+-----------+-----------+-----------+------------+------------------+-------------------+------------------+-------------+-------------------+------------------------+----------------------+------------------------+------------------+------------------------ - stats_import | test | arange | f | 0.5 | 2 | -0.1 | | | | | | | | {399,499,Infinity} | 0.5 | -(1 row) - --- error: scalars can't have range stats -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'id'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - range_bounds_histogram => '{"[-1,1)","[0,4)","[1,4)","[1,100)"}'::text - ); -ERROR: attribute "id" is not a range type -DETAIL: Cannot set STATISTIC_KIND_RANGE_LENGTH_HISTOGRAM or STATISTIC_KIND_BOUNDS_HISTOGRAM. --- ok: range_bounds_histogram -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'arange'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - range_bounds_histogram => '{"[-1,1)","[0,4)","[1,4)","[1,100)"}'::text - ); - pg_set_attribute_stats ------------------------- - -(1 row) - -SELECT * -FROM pg_stats -WHERE schemaname = 'stats_import' -AND tablename = 'test' -AND inherited = false -AND attname = 'arange'; - schemaname | tablename | attname | inherited | null_frac | avg_width | n_distinct | most_common_vals | most_common_freqs | histogram_bounds | correlation | most_common_elems | most_common_elem_freqs | elem_count_histogram | range_length_histogram | range_empty_frac | range_bounds_histogram ---------------+-----------+---------+-----------+-----------+-----------+------------+------------------+-------------------+------------------+-------------+-------------------+------------------------+----------------------+------------------------+------------------+-------------------------------------- - stats_import | test | arange | f | 0.5 | 2 | -0.1 | | | | | | | | {399,499,Infinity} | 0.5 | {"[-1,1)","[0,4)","[1,4)","[1,100)"} -(1 row) - --- error: cannot set most_common_elems for range type -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'arange'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - most_common_vals => '{"[2,3)","[1,2)","[3,4)"}'::text, - most_common_freqs => '{0.3,0.25,0.05}'::real[], - histogram_bounds => '{"[1,2)","[2,3)","[3,4)","[4,5)"}'::text, - correlation => 1.1::real, - most_common_elems => '{3,1}'::text, - most_common_elem_freqs => '{0.3,0.2,0.2,0.3,0.0}'::real[], - range_empty_frac => -0.5::real, - range_length_histogram => '{399,499,Infinity}'::text, - range_bounds_histogram => '{"[-1,1)","[0,4)","[1,4)","[1,100)"}'::text - ); -ERROR: unable to determine element type of attribute "arange" -DETAIL: Cannot set STATISTIC_KIND_MCELEM or STATISTIC_KIND_DECHIST. --- --- Clear attribute stats to try again with restore functions --- (relation stats were already cleared). --- -SELECT - pg_catalog.pg_clear_attribute_stats( - 'stats_import.test'::regclass, - s.attname, - s.inherited) -FROM pg_catalog.pg_stats AS s -WHERE s.schemaname = 'stats_import' -AND s.tablename = 'test' -ORDER BY s.attname, s.inherited; - pg_clear_attribute_stats --------------------------- - - - -(3 rows) - --- reject: argument name is NULL -SELECT pg_restore_relation_stats( - 'relation', '0'::oid::regclass, - 'version', 150000::integer, - NULL, '17'::integer, - 'reltuples', 400::real, - 'relallvisible', 4::integer); -ERROR: name at variadic position 5 is NULL --- reject: argument name is an integer -SELECT pg_restore_relation_stats( - 'relation', '0'::oid::regclass, - 'version', 150000::integer, - 17, '17'::integer, - 'reltuples', 400::real, - 'relallvisible', 4::integer); -ERROR: name at variadic position 5 has type "integer", expected type "text" --- reject: odd number of variadic arguments cannot be pairs -SELECT pg_restore_relation_stats( - 'relation', '0'::oid::regclass, - 'version', 150000::integer, - 'relpages', '17'::integer, - 'reltuples', 400::real, - 'relallvisible'); -ERROR: variadic arguments must be name/value pairs -HINT: Provide an even number of variadic arguments that can be divided into pairs. --- reject: object doesn't exist -SELECT pg_restore_relation_stats( - 'relation', '0'::oid::regclass, - 'version', 150000::integer, - 'relpages', '17'::integer, - 'reltuples', 400::real, - 'relallvisible', 4::integer); -ERROR: could not open relation with OID 0 -- ok: set all stats SELECT pg_restore_relation_stats( 'relation', 'stats_import.test'::regclass, @@ -856,15 +238,6 @@ WHERE oid = 'stats_import.test'::regclass; 16 | 500 | 5 (1 row) --- warn and error: unrecognized argument name -SELECT pg_restore_relation_stats( - 'relation', '0'::oid::regclass, - 'version', 150000::integer, - 'relpages', '17'::integer, - 'reltuples', 400::real, - 'nope', 4::integer); -WARNING: unrecognized argument name: "nope" -ERROR: could not open relation with OID 0 -- warn: bad relpages type SELECT pg_restore_relation_stats( 'relation', 'stats_import.test'::regclass, @@ -886,56 +259,19 @@ WHERE oid = 'stats_import.test'::regclass; 16 | 400 | 4 (1 row) --- error: object does not exist -SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', '0'::oid::regclass, - 'attname', 'id'::name, - 'inherited', false::boolean, - 'version', 150000::integer, - 'null_frac', 0.1::real, - 'avg_width', 2::integer, - 'n_distinct', 0.3::real); -ERROR: could not open relation with OID 0 --- error: relation null -SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', NULL::oid, - 'attname', 'id'::name, - 'inherited', false::boolean, - 'version', 150000::integer, - 'null_frac', 0.1::real, - 'avg_width', 2::integer, - 'n_distinct', 0.3::real); -ERROR: "relation" cannot be NULL --- error: attname null -SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', NULL::name, - 'inherited', false::boolean, - 'version', 150000::integer, - 'null_frac', 0.1::real, - 'avg_width', 2::integer, - 'n_distinct', 0.3::real); -ERROR: "attname" cannot be NULL --- error: attname doesn't exist -SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'nope'::name, - 'inherited', false::boolean, - 'version', 150000::integer, - 'null_frac', 0.1::real, - 'avg_width', 2::integer, - 'n_distinct', 0.3::real); -ERROR: column "nope" of relation "test" does not exist --- error: inherited null -SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'id'::name, - 'inherited', NULL::boolean, - 'version', 150000::integer, - 'null_frac', 0.1::real, - 'avg_width', 2::integer, - 'n_distinct', 0.3::real); -ERROR: "inherited" cannot be NULL +-- invalid relkinds for statistics +CREATE SEQUENCE stats_import.testseq; +CREATE VIEW stats_import.testview AS SELECT * FROM stats_import.test; +SELECT + pg_catalog.pg_clear_relation_stats( + 'stats_import.testseq'::regclass); +ERROR: cannot modify statistics for relation "testseq" +DETAIL: This operation is not supported for sequences. +SELECT + pg_catalog.pg_clear_relation_stats( + 'stats_import.testview'::regclass); +ERROR: cannot modify statistics for relation "testview" +DETAIL: This operation is not supported for views. -- ok: no stakinds SELECT pg_catalog.pg_restore_attribute_stats( 'relation', 'stats_import.test'::regclass, @@ -1409,6 +745,169 @@ AND attname = 'arange'; stats_import | test | arange | f | 0.2 | 3 | -0.39 | | | | | | | | {399,499,Infinity} | 0.5 | {"[-1,1)","[0,4)","[1,4)","[1,100)"} (1 row) +-- warn: cannot set most_common_elems for range type +SELECT pg_catalog.pg_restore_attribute_stats( + 'relation', 'stats_import.test'::regclass, + 'attname', 'arange'::name, + 'inherited', false::boolean, + 'null_frac', 0.5::real, + 'avg_width', 2::integer, + 'n_distinct', -0.1::real, + 'most_common_vals', '{"[2,3)","[1,2)","[3,4)"}'::text, + 'most_common_freqs', '{0.3,0.25,0.05}'::real[], + 'histogram_bounds', '{"[1,2)","[2,3)","[3,4)","[4,5)"}'::text, + 'correlation', 1.1::real, + 'most_common_elems', '{3,1}'::text, + 'most_common_elem_freqs', '{0.3,0.2,0.2,0.3,0.0}'::real[], + 'range_empty_frac', -0.5::real, + 'range_length_histogram', '{399,499,Infinity}'::text, + 'range_bounds_histogram', '{"[-1,1)","[0,4)","[1,4)","[1,100)"}'::text + ); +WARNING: unable to determine element type of attribute "arange" +DETAIL: Cannot set STATISTIC_KIND_MCELEM or STATISTIC_KIND_DECHIST. + pg_restore_attribute_stats +---------------------------- + f +(1 row) + +SELECT * +FROM pg_stats +WHERE schemaname = 'stats_import' +AND tablename = 'test' +AND inherited = false +AND attname = 'arange'; + schemaname | tablename | attname | inherited | null_frac | avg_width | n_distinct | most_common_vals | most_common_freqs | histogram_bounds | correlation | most_common_elems | most_common_elem_freqs | elem_count_histogram | range_length_histogram | range_empty_frac | range_bounds_histogram +--------------+-----------+---------+-----------+-----------+-----------+------------+---------------------------+-------------------+-----------------------------------+-------------+-------------------+------------------------+----------------------+------------------------+------------------+-------------------------------------- + stats_import | test | arange | f | 0.5 | 2 | -0.1 | {"[2,3)","[1,2)","[3,4)"} | {0.3,0.25,0.05} | {"[1,2)","[2,3)","[3,4)","[4,5)"} | 1.1 | | | | {399,499,Infinity} | -0.5 | {"[-1,1)","[0,4)","[1,4)","[1,100)"} +(1 row) + +-- warn: scalars can't have mcelem +SELECT pg_catalog.pg_restore_attribute_stats( + 'relation', 'stats_import.test'::regclass, + 'attname', 'id'::name, + 'inherited', false::boolean, + 'null_frac', 0.5::real, + 'avg_width', 2::integer, + 'n_distinct', -0.1::real, + 'most_common_elems', '{1,3}'::text, + 'most_common_elem_freqs', '{0.3,0.2,0.2,0.3,0.0}'::real[] + ); +WARNING: unable to determine element type of attribute "id" +DETAIL: Cannot set STATISTIC_KIND_MCELEM or STATISTIC_KIND_DECHIST. + pg_restore_attribute_stats +---------------------------- + f +(1 row) + +SELECT * +FROM pg_stats +WHERE schemaname = 'stats_import' +AND tablename = 'test' +AND inherited = false +AND attname = 'id'; + schemaname | tablename | attname | inherited | null_frac | avg_width | n_distinct | most_common_vals | most_common_freqs | histogram_bounds | correlation | most_common_elems | most_common_elem_freqs | elem_count_histogram | range_length_histogram | range_empty_frac | range_bounds_histogram +--------------+-----------+---------+-----------+-----------+-----------+------------+------------------+-------------------+------------------+-------------+-------------------+------------------------+----------------------+------------------------+------------------+------------------------ + stats_import | test | id | f | 0.5 | 2 | -0.1 | {2,1,3} | {0.3,0.25,0.05} | {1,2,3,4} | | | | | | | +(1 row) + +-- warn: mcelem / mcelem mismatch +SELECT pg_catalog.pg_restore_attribute_stats( + 'relation', 'stats_import.test'::regclass, + 'attname', 'tags'::name, + 'inherited', false::boolean, + 'null_frac', 0.5::real, + 'avg_width', 2::integer, + 'n_distinct', -0.1::real, + 'most_common_elems', '{one,two}'::text + ); +WARNING: "most_common_elem_freqs" must be specified when "most_common_elems" is specified + pg_restore_attribute_stats +---------------------------- + f +(1 row) + +SELECT * +FROM pg_stats +WHERE schemaname = 'stats_import' +AND tablename = 'test' +AND inherited = false +AND attname = 'tags'; + schemaname | tablename | attname | inherited | null_frac | avg_width | n_distinct | most_common_vals | most_common_freqs | histogram_bounds | correlation | most_common_elems | most_common_elem_freqs | elem_count_histogram | range_length_histogram | range_empty_frac | range_bounds_histogram +--------------+-----------+---------+-----------+-----------+-----------+------------+------------------+-------------------+------------------+-------------+-------------------+------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------+------------------+------------------------ + stats_import | test | tags | f | 0.5 | 2 | -0.1 | | | | | | | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1} | | | +(1 row) + +-- warn: mcelem / mcelem null mismatch part 2 +SELECT pg_catalog.pg_restore_attribute_stats( + 'relation', 'stats_import.test'::regclass, + 'attname', 'tags'::name, + 'inherited', false::boolean, + 'null_frac', 0.5::real, + 'avg_width', 2::integer, + 'n_distinct', -0.1::real, + 'most_common_elem_freqs', '{0.3,0.2,0.2,0.3}'::real[] + ); +WARNING: "most_common_elems" must be specified when "most_common_elem_freqs" is specified + pg_restore_attribute_stats +---------------------------- + f +(1 row) + +-- ok: mcelem +SELECT pg_catalog.pg_restore_attribute_stats( + 'relation', 'stats_import.test'::regclass, + 'attname', 'tags'::name, + 'inherited', false::boolean, + 'null_frac', 0.5::real, + 'avg_width', 2::integer, + 'n_distinct', -0.1::real, + 'most_common_elems', '{one,three}'::text, + 'most_common_elem_freqs', '{0.3,0.2,0.2,0.3,0.0}'::real[] + ); + pg_restore_attribute_stats +---------------------------- + t +(1 row) + +SELECT * +FROM pg_stats +WHERE schemaname = 'stats_import' +AND tablename = 'test' +AND inherited = false +AND attname = 'tags'; + schemaname | tablename | attname | inherited | null_frac | avg_width | n_distinct | most_common_vals | most_common_freqs | histogram_bounds | correlation | most_common_elems | most_common_elem_freqs | elem_count_histogram | range_length_histogram | range_empty_frac | range_bounds_histogram +--------------+-----------+---------+-----------+-----------+-----------+------------+------------------+-------------------+------------------+-------------+-------------------+------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------+------------------+------------------------ + stats_import | test | tags | f | 0.5 | 2 | -0.1 | | | | | {one,three} | {0.3,0.2,0.2,0.3,0} | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1} | | | +(1 row) + +-- warn: scalars can't have elem_count_histogram +SELECT pg_catalog.pg_restore_attribute_stats( + 'relation', 'stats_import.test'::regclass, + 'attname', 'id'::name, + 'inherited', false::boolean, + 'null_frac', 0.5::real, + 'avg_width', 2::integer, + 'n_distinct', -0.1::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[] + ); +WARNING: unable to determine element type of attribute "id" +DETAIL: Cannot set STATISTIC_KIND_MCELEM or STATISTIC_KIND_DECHIST. + pg_restore_attribute_stats +---------------------------- + f +(1 row) + +SELECT * +FROM pg_stats +WHERE schemaname = 'stats_import' +AND tablename = 'test' +AND inherited = false +AND attname = 'id'; + schemaname | tablename | attname | inherited | null_frac | avg_width | n_distinct | most_common_vals | most_common_freqs | histogram_bounds | correlation | most_common_elems | most_common_elem_freqs | elem_count_histogram | range_length_histogram | range_empty_frac | range_bounds_histogram +--------------+-----------+---------+-----------+-----------+-----------+------------+------------------+-------------------+------------------+-------------+-------------------+------------------------+----------------------+------------------------+------------------+------------------------ + stats_import | test | id | f | 0.5 | 2 | -0.1 | {2,1,3} | {0.3,0.25,0.05} | {1,2,3,4} | | | | | | | +(1 row) + -- warn: too many stat kinds SELECT pg_catalog.pg_restore_attribute_stats( 'relation', 'stats_import.test'::regclass, @@ -1434,6 +933,17 @@ DETAIL: Cannot set STATISTIC_KIND_MCELEM or STATISTIC_KIND_DECHIST. f (1 row) +SELECT * +FROM pg_stats +WHERE schemaname = 'stats_import' +AND tablename = 'test' +AND inherited = false +AND attname = 'arange'; + schemaname | tablename | attname | inherited | null_frac | avg_width | n_distinct | most_common_vals | most_common_freqs | histogram_bounds | correlation | most_common_elems | most_common_elem_freqs | elem_count_histogram | range_length_histogram | range_empty_frac | range_bounds_histogram +--------------+-----------+---------+-----------+-----------+-----------+------------+---------------------------+-------------------+----------------------------------+-------------+-------------------+------------------------+----------------------+------------------------+------------------+-------------------------------------- + stats_import | test | arange | f | 0.5 | 2 | -0.1 | {"[2,3)","[1,3)","[3,9)"} | {0.3,0.25,0.05} | {"[1,2)","[2,3)","[3,4)","[4,)"} | 1.1 | | | | {399,499,Infinity} | -0.5 | {"[-1,1)","[0,4)","[1,4)","[1,100)"} +(1 row) + -- -- Test the ability to exactly copy data from one table to an identical table, -- correctly reconstructing the stakind order as well as the staopN and @@ -1472,216 +982,6 @@ CREATE INDEX is_odd_clone ON stats_import.test_clone(((comp).a % 2 = 1)); -- -- Copy stats from test to test_clone, and is_odd to is_odd_clone -- -SELECT s.schemaname, s.tablename, s.attname, s.inherited -FROM pg_catalog.pg_stats AS s -CROSS JOIN LATERAL - pg_catalog.pg_set_attribute_stats( - relation => ('stats_import.' || s.tablename || '_clone')::regclass::oid, - attname => s.attname, - inherited => s.inherited, - null_frac => s.null_frac, - avg_width => s.avg_width, - n_distinct => s.n_distinct, - most_common_vals => s.most_common_vals::text, - most_common_freqs => s.most_common_freqs, - histogram_bounds => s.histogram_bounds::text, - correlation => s.correlation, - most_common_elems => s.most_common_elems::text, - most_common_elem_freqs => s.most_common_elem_freqs, - elem_count_histogram => s.elem_count_histogram, - range_bounds_histogram => s.range_bounds_histogram::text, - range_empty_frac => s.range_empty_frac, - range_length_histogram => s.range_length_histogram::text) AS r -WHERE s.schemaname = 'stats_import' -AND s.tablename IN ('test', 'is_odd') -ORDER BY s.tablename, s.attname, s.inherited; - schemaname | tablename | attname | inherited ---------------+-----------+---------+----------- - stats_import | is_odd | expr | f - stats_import | test | arange | f - stats_import | test | comp | f - stats_import | test | id | f - stats_import | test | name | f - stats_import | test | tags | f -(6 rows) - -SELECT c.relname, COUNT(*) AS num_stats -FROM pg_class AS c -JOIN pg_statistic s ON s.starelid = c.oid -WHERE c.relnamespace = 'stats_import'::regnamespace -AND c.relname IN ('test', 'test_clone', 'is_odd', 'is_odd_clone') -GROUP BY c.relname -ORDER BY c.relname; - relname | num_stats ---------------+----------- - is_odd | 1 - is_odd_clone | 1 - test | 5 - test_clone | 5 -(4 rows) - --- check test minus test_clone -SELECT - a.attname, s.stainherit, s.stanullfrac, s.stawidth, s.stadistinct, - s.stakind1, s.stakind2, s.stakind3, s.stakind4, s.stakind5, - s.staop1, s.staop2, s.staop3, s.staop4, s.staop5, - s.stacoll1, s.stacoll2, s.stacoll3, s.stacoll4, s.stacoll5, - s.stanumbers1, s.stanumbers2, s.stanumbers3, s.stanumbers4, s.stanumbers5, - s.stavalues1::text AS sv1, s.stavalues2::text AS sv2, - s.stavalues3::text AS sv3, s.stavalues4::text AS sv4, - s.stavalues5::text AS sv5, 'test' AS direction -FROM pg_statistic s -JOIN pg_attribute a ON a.attrelid = s.starelid AND a.attnum = s.staattnum -WHERE s.starelid = 'stats_import.test'::regclass -EXCEPT -SELECT - a.attname, s.stainherit, s.stanullfrac, s.stawidth, s.stadistinct, - s.stakind1, s.stakind2, s.stakind3, s.stakind4, s.stakind5, - s.staop1, s.staop2, s.staop3, s.staop4, s.staop5, - s.stacoll1, s.stacoll2, s.stacoll3, s.stacoll4, s.stacoll5, - s.stanumbers1, s.stanumbers2, s.stanumbers3, s.stanumbers4, s.stanumbers5, - s.stavalues1::text AS sv1, s.stavalues2::text AS sv2, - s.stavalues3::text AS sv3, s.stavalues4::text AS sv4, - s.stavalues5::text AS sv5, 'test' AS direction -FROM pg_statistic s -JOIN pg_attribute a ON a.attrelid = s.starelid AND a.attnum = s.staattnum -WHERE s.starelid = 'stats_import.test_clone'::regclass; - attname | stainherit | stanullfrac | stawidth | stadistinct | stakind1 | stakind2 | stakind3 | stakind4 | stakind5 | staop1 | staop2 | staop3 | staop4 | staop5 | stacoll1 | stacoll2 | stacoll3 | stacoll4 | stacoll5 | stanumbers1 | stanumbers2 | stanumbers3 | stanumbers4 | stanumbers5 | sv1 | sv2 | sv3 | sv4 | sv5 | direction ----------+------------+-------------+----------+-------------+----------+----------+----------+----------+----------+--------+--------+--------+--------+--------+----------+----------+----------+----------+----------+-------------+-------------+-------------+-------------+-------------+-----+-----+-----+-----+-----+----------- -(0 rows) - --- check test_clone minus test -SELECT - a.attname, s.stainherit, s.stanullfrac, s.stawidth, s.stadistinct, - s.stakind1, s.stakind2, s.stakind3, s.stakind4, s.stakind5, - s.staop1, s.staop2, s.staop3, s.staop4, s.staop5, - s.stacoll1, s.stacoll2, s.stacoll3, s.stacoll4, s.stacoll5, - s.stanumbers1, s.stanumbers2, s.stanumbers3, s.stanumbers4, s.stanumbers5, - s.stavalues1::text AS sv1, s.stavalues2::text AS sv2, - s.stavalues3::text AS sv3, s.stavalues4::text AS sv4, - s.stavalues5::text AS sv5, 'test_clone' AS direction -FROM pg_statistic s -JOIN pg_attribute a ON a.attrelid = s.starelid AND a.attnum = s.staattnum -WHERE s.starelid = 'stats_import.test_clone'::regclass -EXCEPT -SELECT - a.attname, s.stainherit, s.stanullfrac, s.stawidth, s.stadistinct, - s.stakind1, s.stakind2, s.stakind3, s.stakind4, s.stakind5, - s.staop1, s.staop2, s.staop3, s.staop4, s.staop5, - s.stacoll1, s.stacoll2, s.stacoll3, s.stacoll4, s.stacoll5, - s.stanumbers1, s.stanumbers2, s.stanumbers3, s.stanumbers4, s.stanumbers5, - s.stavalues1::text AS sv1, s.stavalues2::text AS sv2, - s.stavalues3::text AS sv3, s.stavalues4::text AS sv4, - s.stavalues5::text AS sv5, 'test_clone' AS direction -FROM pg_statistic s -JOIN pg_attribute a ON a.attrelid = s.starelid AND a.attnum = s.staattnum -WHERE s.starelid = 'stats_import.test'::regclass; - attname | stainherit | stanullfrac | stawidth | stadistinct | stakind1 | stakind2 | stakind3 | stakind4 | stakind5 | staop1 | staop2 | staop3 | staop4 | staop5 | stacoll1 | stacoll2 | stacoll3 | stacoll4 | stacoll5 | stanumbers1 | stanumbers2 | stanumbers3 | stanumbers4 | stanumbers5 | sv1 | sv2 | sv3 | sv4 | sv5 | direction ----------+------------+-------------+----------+-------------+----------+----------+----------+----------+----------+--------+--------+--------+--------+--------+----------+----------+----------+----------+----------+-------------+-------------+-------------+-------------+-------------+-----+-----+-----+-----+-----+----------- -(0 rows) - --- check is_odd minus is_odd_clone -SELECT - a.attname, s.stainherit, s.stanullfrac, s.stawidth, s.stadistinct, - s.stakind1, s.stakind2, s.stakind3, s.stakind4, s.stakind5, - s.staop1, s.staop2, s.staop3, s.staop4, s.staop5, - s.stacoll1, s.stacoll2, s.stacoll3, s.stacoll4, s.stacoll5, - s.stanumbers1, s.stanumbers2, s.stanumbers3, s.stanumbers4, s.stanumbers5, - s.stavalues1::text AS sv1, s.stavalues2::text AS sv2, - s.stavalues3::text AS sv3, s.stavalues4::text AS sv4, - s.stavalues5::text AS sv5, 'is_odd' AS direction -FROM pg_statistic s -JOIN pg_attribute a ON a.attrelid = s.starelid AND a.attnum = s.staattnum -WHERE s.starelid = 'stats_import.is_odd'::regclass -EXCEPT -SELECT - a.attname, s.stainherit, s.stanullfrac, s.stawidth, s.stadistinct, - s.stakind1, s.stakind2, s.stakind3, s.stakind4, s.stakind5, - s.staop1, s.staop2, s.staop3, s.staop4, s.staop5, - s.stacoll1, s.stacoll2, s.stacoll3, s.stacoll4, s.stacoll5, - s.stanumbers1, s.stanumbers2, s.stanumbers3, s.stanumbers4, s.stanumbers5, - s.stavalues1::text AS sv1, s.stavalues2::text AS sv2, - s.stavalues3::text AS sv3, s.stavalues4::text AS sv4, - s.stavalues5::text AS sv5, 'is_odd' AS direction -FROM pg_statistic s -JOIN pg_attribute a ON a.attrelid = s.starelid AND a.attnum = s.staattnum -WHERE s.starelid = 'stats_import.is_odd_clone'::regclass; - attname | stainherit | stanullfrac | stawidth | stadistinct | stakind1 | stakind2 | stakind3 | stakind4 | stakind5 | staop1 | staop2 | staop3 | staop4 | staop5 | stacoll1 | stacoll2 | stacoll3 | stacoll4 | stacoll5 | stanumbers1 | stanumbers2 | stanumbers3 | stanumbers4 | stanumbers5 | sv1 | sv2 | sv3 | sv4 | sv5 | direction ----------+------------+-------------+----------+-------------+----------+----------+----------+----------+----------+--------+--------+--------+--------+--------+----------+----------+----------+----------+----------+-------------+-------------+-------------+-------------+-------------+-----+-----+-----+-----+-----+----------- -(0 rows) - --- check is_odd_clone minus is_odd -SELECT - a.attname, s.stainherit, s.stanullfrac, s.stawidth, s.stadistinct, - s.stakind1, s.stakind2, s.stakind3, s.stakind4, s.stakind5, - s.staop1, s.staop2, s.staop3, s.staop4, s.staop5, - s.stacoll1, s.stacoll2, s.stacoll3, s.stacoll4, s.stacoll5, - s.stanumbers1, s.stanumbers2, s.stanumbers3, s.stanumbers4, s.stanumbers5, - s.stavalues1::text AS sv1, s.stavalues2::text AS sv2, - s.stavalues3::text AS sv3, s.stavalues4::text AS sv4, - s.stavalues5::text AS sv5, 'is_odd_clone' AS direction -FROM pg_statistic s -JOIN pg_attribute a ON a.attrelid = s.starelid AND a.attnum = s.staattnum -WHERE s.starelid = 'stats_import.is_odd_clone'::regclass -EXCEPT -SELECT - a.attname, s.stainherit, s.stanullfrac, s.stawidth, s.stadistinct, - s.stakind1, s.stakind2, s.stakind3, s.stakind4, s.stakind5, - s.staop1, s.staop2, s.staop3, s.staop4, s.staop5, - s.stacoll1, s.stacoll2, s.stacoll3, s.stacoll4, s.stacoll5, - s.stanumbers1, s.stanumbers2, s.stanumbers3, s.stanumbers4, s.stanumbers5, - s.stavalues1::text AS sv1, s.stavalues2::text AS sv2, - s.stavalues3::text AS sv3, s.stavalues4::text AS sv4, - s.stavalues5::text AS sv5, 'is_odd_clone' AS direction -FROM pg_statistic s -JOIN pg_attribute a ON a.attrelid = s.starelid AND a.attnum = s.staattnum -WHERE s.starelid = 'stats_import.is_odd'::regclass; - attname | stainherit | stanullfrac | stawidth | stadistinct | stakind1 | stakind2 | stakind3 | stakind4 | stakind5 | staop1 | staop2 | staop3 | staop4 | staop5 | stacoll1 | stacoll2 | stacoll3 | stacoll4 | stacoll5 | stanumbers1 | stanumbers2 | stanumbers3 | stanumbers4 | stanumbers5 | sv1 | sv2 | sv3 | sv4 | sv5 | direction ----------+------------+-------------+----------+-------------+----------+----------+----------+----------+----------+--------+--------+--------+--------+--------+----------+----------+----------+----------+----------+-------------+-------------+-------------+-------------+-------------+-----+-----+-----+-----+-----+----------- -(0 rows) - --- -SELECT relpages, reltuples, relallvisible -FROM pg_class -WHERE oid = 'stats_import.test'::regclass; - relpages | reltuples | relallvisible -----------+-----------+--------------- - 1 | 4 | 0 -(1 row) - --- --- Clear clone stats to try again with pg_restore_attribute_stats --- -SELECT - pg_catalog.pg_clear_attribute_stats( - ('stats_import.' || s.tablename)::regclass, - s.attname, - s.inherited) -FROM pg_catalog.pg_stats AS s -WHERE s.schemaname = 'stats_import' -AND s.tablename IN ('test_clone', 'is_odd_clone') -ORDER BY s.tablename, s.attname, s.inherited; - pg_clear_attribute_stats --------------------------- - - - - - - -(6 rows) - -SELECT -SELECT COUNT(*) -FROM pg_catalog.pg_stats AS s -WHERE s.schemaname = 'stats_import' -AND s.tablename IN ('test_clone', 'is_odd_clone'); -ERROR: syntax error at or near "SELECT" -LINE 2: SELECT COUNT(*) - ^ --- --- Copy stats from test to test_clone, and is_odd to is_odd_clone --- SELECT s.schemaname, s.tablename, s.attname, s.inherited, r.* FROM pg_catalog.pg_stats AS s CROSS JOIN LATERAL @@ -1851,11 +1151,158 @@ WHERE s.starelid = 'stats_import.is_odd'::regclass; ---------+------------+-------------+----------+-------------+----------+----------+----------+----------+----------+--------+--------+--------+--------+--------+----------+----------+----------+----------+----------+-------------+-------------+-------------+-------------+-------------+-----+-----+-----+-----+-----+----------- (0 rows) +-- ok +SELECT pg_catalog.pg_clear_attribute_stats( + relation => 'stats_import.test'::regclass, + attname => 'arange'::name, + inherited => false::boolean); + pg_clear_attribute_stats +-------------------------- + +(1 row) + +-- +-- Negative tests +-- +--- error: relation is wrong type +SELECT pg_catalog.pg_restore_relation_stats( + 'relation', 0::oid, + 'relpages', 17::integer, + 'reltuples', 400.0::real, + 'relallvisible', 4::integer); +WARNING: argument "relation" has type "oid", expected type "regclass" +ERROR: "relation" cannot be NULL +--- error: relation not found +SELECT pg_catalog.pg_restore_relation_stats( + 'relation', 0::regclass, + 'relpages', 17::integer, + 'reltuples', 400.0::real, + 'relallvisible', 4::integer); +ERROR: could not open relation with OID 0 +-- warn and error: unrecognized argument name +SELECT pg_restore_relation_stats( + 'relation', '0'::oid::regclass, + 'version', 150000::integer, + 'relpages', '17'::integer, + 'reltuples', 400::real, + 'nope', 4::integer); +WARNING: unrecognized argument name: "nope" +ERROR: could not open relation with OID 0 +-- error: argument name is NULL +SELECT pg_restore_relation_stats( + 'relation', '0'::oid::regclass, + 'version', 150000::integer, + NULL, '17'::integer, + 'reltuples', 400::real, + 'relallvisible', 4::integer); +ERROR: name at variadic position 5 is NULL +-- error: argument name is an integer +SELECT pg_restore_relation_stats( + 'relation', '0'::oid::regclass, + 'version', 150000::integer, + 17, '17'::integer, + 'reltuples', 400::real, + 'relallvisible', 4::integer); +ERROR: name at variadic position 5 has type "integer", expected type "text" +-- error: odd number of variadic arguments cannot be pairs +SELECT pg_restore_relation_stats( + 'relation', '0'::oid::regclass, + 'version', 150000::integer, + 'relpages', '17'::integer, + 'reltuples', 400::real, + 'relallvisible'); +ERROR: variadic arguments must be name/value pairs +HINT: Provide an even number of variadic arguments that can be divided into pairs. +-- error: object doesn't exist +SELECT pg_restore_relation_stats( + 'relation', '0'::oid::regclass, + 'version', 150000::integer, + 'relpages', '17'::integer, + 'reltuples', 400::real, + 'relallvisible', 4::integer); +ERROR: could not open relation with OID 0 +-- error: object does not exist +SELECT pg_catalog.pg_restore_attribute_stats( + 'relation', '0'::oid::regclass, + 'attname', 'id'::name, + 'inherited', false::boolean, + 'version', 150000::integer, + 'null_frac', 0.1::real, + 'avg_width', 2::integer, + 'n_distinct', 0.3::real); +ERROR: could not open relation with OID 0 +-- error: relation null +SELECT pg_catalog.pg_restore_attribute_stats( + 'relation', NULL::oid, + 'attname', 'id'::name, + 'inherited', false::boolean, + 'version', 150000::integer, + 'null_frac', 0.1::real, + 'avg_width', 2::integer, + 'n_distinct', 0.3::real); +ERROR: "relation" cannot be NULL +-- error: attname null +SELECT pg_catalog.pg_restore_attribute_stats( + 'relation', 'stats_import.test'::regclass, + 'attname', NULL::name, + 'inherited', false::boolean, + 'version', 150000::integer, + 'null_frac', 0.1::real, + 'avg_width', 2::integer, + 'n_distinct', 0.3::real); +ERROR: "attname" cannot be NULL +-- error: attname doesn't exist +SELECT pg_catalog.pg_restore_attribute_stats( + 'relation', 'stats_import.test'::regclass, + 'attname', 'nope'::name, + 'inherited', false::boolean, + 'version', 150000::integer, + 'null_frac', 0.1::real, + 'avg_width', 2::integer, + 'n_distinct', 0.3::real); +ERROR: column "nope" of relation "test" does not exist +-- error: attribute is system column +SELECT pg_catalog.pg_restore_attribute_stats( + 'relation', 'stats_import.test'::regclass, + 'attname', 'xmin'::name, + 'inherited', false::boolean, + 'null_frac', 0.1::real, + 'avg_width', 2::integer, + 'n_distinct', 0.3::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, + 'inherited', NULL::boolean, + 'version', 150000::integer, + 'null_frac', 0.1::real, + 'avg_width', 2::integer, + 'n_distinct', 0.3::real); +ERROR: "inherited" cannot be NULL +-- error: relation not found +SELECT pg_catalog.pg_clear_relation_stats( + relation => 'stats_import.nope'::regclass); +ERROR: relation "stats_import.nope" does not exist +LINE 2: relation => 'stats_import.nope'::regclass); + ^ +-- error: attribute is system column +SELECT pg_catalog.pg_clear_attribute_stats( + relation => 'stats_import.test'::regclass, + attname => 'ctid'::name, + inherited => false::boolean); +ERROR: cannot clear statistics on system column "ctid" +-- error: attname doesn't exist +SELECT pg_catalog.pg_clear_attribute_stats( + relation => 'stats_import.test'::regclass, + attname => 'nope'::name, + inherited => false::boolean); +ERROR: column "nope" of relation "test" does not exist DROP SCHEMA stats_import CASCADE; NOTICE: drop cascades to 6 other objects DETAIL: drop cascades to type stats_import.complex_type drop cascades to table stats_import.test +drop cascades to table stats_import.part_parent drop cascades to sequence stats_import.testseq drop cascades to view stats_import.testview -drop cascades to table stats_import.part_parent drop cascades to table stats_import.test_clone diff --git a/src/test/regress/sql/stats_import.sql b/src/test/regress/sql/stats_import.sql index 9740ab3ff02..57422750b90 100644 --- a/src/test/regress/sql/stats_import.sql +++ b/src/test/regress/sql/stats_import.sql @@ -15,63 +15,19 @@ CREATE TABLE stats_import.test( tags text[] ) WITH (autovacuum_enabled = false); +CREATE INDEX test_i ON stats_import.test(id); + -- starting stats SELECT relpages, reltuples, relallvisible FROM pg_class WHERE oid = 'stats_import.test'::regclass; --- error: regclass not found -SELECT - pg_catalog.pg_set_relation_stats( - relation => 0::Oid, - relpages => 17::integer, - reltuples => 400.0::real, - relallvisible => 4::integer); - --- relpages default -SELECT - pg_catalog.pg_set_relation_stats( - relation => 'stats_import.test'::regclass, - relpages => NULL::integer, - reltuples => 400.0::real, - relallvisible => 4::integer); - --- reltuples default -SELECT - pg_catalog.pg_set_relation_stats( - relation => 'stats_import.test'::regclass, - relpages => 17::integer, - reltuples => NULL::real, - relallvisible => 4::integer); - --- relallvisible default -SELECT - pg_catalog.pg_set_relation_stats( - relation => 'stats_import.test'::regclass, - relpages => 17::integer, - reltuples => 400.0::real, - relallvisible => NULL::integer); - --- named arguments -SELECT - pg_catalog.pg_set_relation_stats( - relation => 'stats_import.test'::regclass, - relpages => 17::integer, - reltuples => 400.0::real, - relallvisible => 4::integer); - -SELECT relpages, reltuples, relallvisible -FROM pg_class -WHERE oid = 'stats_import.test'::regclass; - -CREATE INDEX test_i ON stats_import.test(id); - BEGIN; -- regular indexes have special case locking rules SELECT - pg_catalog.pg_set_relation_stats( - relation => 'stats_import.test_i'::regclass, - relpages => 18::integer); + pg_catalog.pg_restore_relation_stats( + 'relation', 'stats_import.test_i'::regclass, + 'relpages', 18::integer); SELECT mode FROM pg_locks WHERE relation = 'stats_import.test'::regclass AND @@ -88,22 +44,6 @@ SELECT 'relation', 'stats_import.test_i'::regclass, 'relpages', 19::integer ); --- positional arguments -SELECT - pg_catalog.pg_set_relation_stats( - 'stats_import.test'::regclass, - 18::integer, - 401.0::real, - 5::integer); - -SELECT relpages, reltuples, relallvisible -FROM pg_class -WHERE oid = 'stats_import.test'::regclass; - -SELECT relpages, reltuples, relallvisible -FROM pg_class -WHERE oid = 'stats_import.test'::regclass; - -- clear SELECT pg_catalog.pg_clear_relation_stats( @@ -113,16 +53,6 @@ SELECT relpages, reltuples, relallvisible FROM pg_class WHERE oid = 'stats_import.test'::regclass; --- invalid relkinds for statistics -CREATE SEQUENCE stats_import.testseq; -CREATE VIEW stats_import.testview AS SELECT * FROM stats_import.test; -SELECT - pg_catalog.pg_clear_relation_stats( - 'stats_import.testseq'::regclass); -SELECT - pg_catalog.pg_clear_relation_stats( - 'stats_import.testview'::regclass); - -- relpages may be -1 for partitioned tables CREATE TABLE stats_import.part_parent ( i integer ) PARTITION BY RANGE(i); CREATE TABLE stats_import.part_child_1 @@ -141,14 +71,14 @@ WHERE oid = 'stats_import.part_parent'::regclass; -- although partitioned tables have no storage, setting relpages to a -- positive value is still allowed SELECT - pg_catalog.pg_set_relation_stats( - relation => 'stats_import.part_parent_i'::regclass, - relpages => 2::integer); + pg_catalog.pg_restore_relation_stats( + 'relation', 'stats_import.part_parent_i'::regclass, + 'relpages', 2::integer); SELECT - pg_catalog.pg_set_relation_stats( - relation => 'stats_import.part_parent'::regclass, - relpages => 2::integer); + pg_catalog.pg_restore_relation_stats( + 'relation', 'stats_import.part_parent'::regclass, + 'relpages', 2::integer); -- -- Partitioned indexes aren't analyzed but it is possible to set @@ -159,9 +89,9 @@ SELECT BEGIN; SELECT - pg_catalog.pg_set_relation_stats( - relation => 'stats_import.part_parent_i'::regclass, - relpages => 2::integer); + pg_catalog.pg_restore_relation_stats( + 'relation', 'stats_import.part_parent_i'::regclass, + 'relpages', 2::integer); SELECT mode FROM pg_locks WHERE relation = 'stats_import.part_parent'::regclass AND @@ -180,440 +110,9 @@ SELECT -- nothing stops us from setting it to -1 SELECT - pg_catalog.pg_set_relation_stats( - relation => 'stats_import.part_parent'::regclass, - relpages => -1::integer); - --- error: object doesn't exist -SELECT pg_catalog.pg_set_attribute_stats( - relation => '0'::oid, - attname => 'id'::name, - inherited => false::boolean, - null_frac => 0.1::real, - avg_width => 2::integer, - n_distinct => 0.3::real); - --- error: object doesn't exist -SELECT pg_catalog.pg_clear_attribute_stats( - relation => '0'::oid, - attname => 'id'::name, - inherited => false::boolean); - --- error: relation null -SELECT pg_catalog.pg_set_attribute_stats( - relation => NULL::oid, - attname => 'id'::name, - inherited => false::boolean, - null_frac => 0.1::real, - avg_width => 2::integer, - n_distinct => 0.3::real); - --- error: attribute is system column -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'xmin'::name, - inherited => false::boolean, - null_frac => 0.1::real, - avg_width => 2::integer, - n_distinct => 0.3::real); - --- error: attname doesn't exist -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'nope'::name, - inherited => false::boolean, - null_frac => 0.1::real, - avg_width => 2::integer, - n_distinct => 0.3::real); - --- error: attribute is system column -SELECT pg_catalog.pg_clear_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'ctid'::name, - inherited => false::boolean); - --- error: attname doesn't exist -SELECT pg_catalog.pg_clear_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'nope'::name, - inherited => false::boolean); - --- error: attname null -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => NULL::name, - inherited => false::boolean, - null_frac => 0.1::real, - avg_width => 2::integer, - n_distinct => 0.3::real); - --- error: inherited null -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'id'::name, - inherited => NULL::boolean, - null_frac => 0.1::real, - avg_width => 2::integer, - n_distinct => 0.3::real); - --- ok: no stakinds -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'id'::name, - inherited => false::boolean, - null_frac => 0.1::real, - avg_width => 2::integer, - n_distinct => 0.3::real); - -SELECT stanullfrac, stawidth, stadistinct -FROM pg_statistic -WHERE starelid = 'stats_import.test'::regclass; - --- error: mcv / mcf null mismatch -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'id'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - most_common_freqs => '{0.1,0.2,0.3}'::real[] - ); - --- error: mcv / mcf null mismatch part 2 -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'id'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - most_common_vals => '{1,2,3}'::text - ); - --- error: mcv / mcf type mismatch -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'id'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - most_common_vals => '{2023-09-30,2024-10-31,3}'::text, - most_common_freqs => '{0.2,0.1}'::real[] - ); - --- error: mcv cast failure -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'id'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - most_common_vals => '{2,four,3}'::text, - most_common_freqs => '{0.3,0.25,0.05}'::real[] - ); - --- ok: mcv+mcf -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'id'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - most_common_vals => '{2,1,3}'::text, - most_common_freqs => '{0.3,0.25,0.05}'::real[] - ); - -SELECT * -FROM pg_stats -WHERE schemaname = 'stats_import' -AND tablename = 'test' -AND inherited = false -AND attname = 'id'; - --- error: histogram elements null value --- this generates no warnings, but perhaps it should -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'id'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - histogram_bounds => '{1,NULL,3,4}'::text - ); - --- ok: histogram_bounds -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'id'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - histogram_bounds => '{1,2,3,4}'::text - ); - -SELECT * -FROM pg_stats -WHERE schemaname = 'stats_import' -AND tablename = 'test' -AND inherited = false -AND attname = 'id'; - --- ok: correlation -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'id'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - correlation => 0.5::real); - -SELECT * -FROM pg_stats -WHERE schemaname = 'stats_import' -AND tablename = 'test' -AND inherited = false -AND attname = 'id'; - --- error: scalars can't have mcelem -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'id'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - most_common_elems => '{1,3}'::text, - most_common_elem_freqs => '{0.3,0.2,0.2,0.3,0.0}'::real[] - ); - --- error: mcelem / mcelem mismatch -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'tags'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - most_common_elems => '{one,two}'::text - ); - --- error: mcelem / mcelem null mismatch part 2 -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'tags'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - most_common_elem_freqs => '{0.3,0.2,0.2,0.3}'::real[] - ); - --- ok: mcelem -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'tags'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - most_common_elems => '{one,three}'::text, - most_common_elem_freqs => '{0.3,0.2,0.2,0.3,0.0}'::real[] - ); - -SELECT * -FROM pg_stats -WHERE schemaname = 'stats_import' -AND tablename = 'test' -AND inherited = false -AND attname = 'tags'; - --- error: scalars can't have elem_count_histogram -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'id'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::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[] - ); --- error: elem_count_histogram null element -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'tags'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - elem_count_histogram => '{1,1,NULL,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,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[] - ); --- ok: elem_count_histogram -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'tags'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::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[] - ); - -SELECT * -FROM pg_stats -WHERE schemaname = 'stats_import' -AND tablename = 'test' -AND inherited = false -AND attname = 'tags'; - --- error: scalars can't have range stats -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'id'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - range_empty_frac => 0.5::real, - range_length_histogram => '{399,499,Infinity}'::text - ); --- error: range_empty_frac range_length_hist null mismatch -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'arange'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - range_length_histogram => '{399,499,Infinity}'::text - ); --- error: range_empty_frac range_length_hist null mismatch part 2 -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'arange'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - range_empty_frac => 0.5::real - ); --- ok: range_empty_frac + range_length_hist -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'arange'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - range_empty_frac => 0.5::real, - range_length_histogram => '{399,499,Infinity}'::text - ); - -SELECT * -FROM pg_stats -WHERE schemaname = 'stats_import' -AND tablename = 'test' -AND inherited = false -AND attname = 'arange'; - --- error: scalars can't have range stats -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'id'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - range_bounds_histogram => '{"[-1,1)","[0,4)","[1,4)","[1,100)"}'::text - ); --- ok: range_bounds_histogram -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'arange'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - range_bounds_histogram => '{"[-1,1)","[0,4)","[1,4)","[1,100)"}'::text - ); - -SELECT * -FROM pg_stats -WHERE schemaname = 'stats_import' -AND tablename = 'test' -AND inherited = false -AND attname = 'arange'; - --- error: cannot set most_common_elems for range type -SELECT pg_catalog.pg_set_attribute_stats( - relation => 'stats_import.test'::regclass, - attname => 'arange'::name, - inherited => false::boolean, - null_frac => 0.5::real, - avg_width => 2::integer, - n_distinct => -0.1::real, - most_common_vals => '{"[2,3)","[1,2)","[3,4)"}'::text, - most_common_freqs => '{0.3,0.25,0.05}'::real[], - histogram_bounds => '{"[1,2)","[2,3)","[3,4)","[4,5)"}'::text, - correlation => 1.1::real, - most_common_elems => '{3,1}'::text, - most_common_elem_freqs => '{0.3,0.2,0.2,0.3,0.0}'::real[], - range_empty_frac => -0.5::real, - range_length_histogram => '{399,499,Infinity}'::text, - range_bounds_histogram => '{"[-1,1)","[0,4)","[1,4)","[1,100)"}'::text - ); - --- --- Clear attribute stats to try again with restore functions --- (relation stats were already cleared). --- -SELECT - pg_catalog.pg_clear_attribute_stats( - 'stats_import.test'::regclass, - s.attname, - s.inherited) -FROM pg_catalog.pg_stats AS s -WHERE s.schemaname = 'stats_import' -AND s.tablename = 'test' -ORDER BY s.attname, s.inherited; - --- reject: argument name is NULL -SELECT pg_restore_relation_stats( - 'relation', '0'::oid::regclass, - 'version', 150000::integer, - NULL, '17'::integer, - 'reltuples', 400::real, - 'relallvisible', 4::integer); - --- reject: argument name is an integer -SELECT pg_restore_relation_stats( - 'relation', '0'::oid::regclass, - 'version', 150000::integer, - 17, '17'::integer, - 'reltuples', 400::real, - 'relallvisible', 4::integer); - --- reject: odd number of variadic arguments cannot be pairs -SELECT pg_restore_relation_stats( - 'relation', '0'::oid::regclass, - 'version', 150000::integer, - 'relpages', '17'::integer, - 'reltuples', 400::real, - 'relallvisible'); - --- reject: object doesn't exist -SELECT pg_restore_relation_stats( - 'relation', '0'::oid::regclass, - 'version', 150000::integer, - 'relpages', '17'::integer, - 'reltuples', 400::real, - 'relallvisible', 4::integer); + pg_catalog.pg_restore_relation_stats( + 'relation', 'stats_import.part_parent'::regclass, + 'relpages', -1::integer); -- ok: set all stats SELECT pg_restore_relation_stats( @@ -657,14 +156,6 @@ SELECT relpages, reltuples, relallvisible FROM pg_class WHERE oid = 'stats_import.test'::regclass; --- warn and error: unrecognized argument name -SELECT pg_restore_relation_stats( - 'relation', '0'::oid::regclass, - 'version', 150000::integer, - 'relpages', '17'::integer, - 'reltuples', 400::real, - 'nope', 4::integer); - -- warn: bad relpages type SELECT pg_restore_relation_stats( 'relation', 'stats_import.test'::regclass, @@ -677,55 +168,15 @@ SELECT relpages, reltuples, relallvisible FROM pg_class WHERE oid = 'stats_import.test'::regclass; --- error: object does not exist -SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', '0'::oid::regclass, - 'attname', 'id'::name, - 'inherited', false::boolean, - 'version', 150000::integer, - 'null_frac', 0.1::real, - 'avg_width', 2::integer, - 'n_distinct', 0.3::real); - --- error: relation null -SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', NULL::oid, - 'attname', 'id'::name, - 'inherited', false::boolean, - 'version', 150000::integer, - 'null_frac', 0.1::real, - 'avg_width', 2::integer, - 'n_distinct', 0.3::real); - --- error: attname null -SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', NULL::name, - 'inherited', false::boolean, - 'version', 150000::integer, - 'null_frac', 0.1::real, - 'avg_width', 2::integer, - 'n_distinct', 0.3::real); - --- error: attname doesn't exist -SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'nope'::name, - 'inherited', false::boolean, - 'version', 150000::integer, - 'null_frac', 0.1::real, - 'avg_width', 2::integer, - 'n_distinct', 0.3::real); - --- error: inherited null -SELECT pg_catalog.pg_restore_attribute_stats( - 'relation', 'stats_import.test'::regclass, - 'attname', 'id'::name, - 'inherited', NULL::boolean, - 'version', 150000::integer, - 'null_frac', 0.1::real, - 'avg_width', 2::integer, - 'n_distinct', 0.3::real); +-- invalid relkinds for statistics +CREATE SEQUENCE stats_import.testseq; +CREATE VIEW stats_import.testview AS SELECT * FROM stats_import.test; +SELECT + pg_catalog.pg_clear_relation_stats( + 'stats_import.testseq'::regclass); +SELECT + pg_catalog.pg_clear_relation_stats( + 'stats_import.testview'::regclass); -- ok: no stakinds SELECT pg_catalog.pg_restore_attribute_stats( @@ -1050,6 +501,117 @@ AND tablename = 'test' AND inherited = false AND attname = 'arange'; +-- warn: cannot set most_common_elems for range type +SELECT pg_catalog.pg_restore_attribute_stats( + 'relation', 'stats_import.test'::regclass, + 'attname', 'arange'::name, + 'inherited', false::boolean, + 'null_frac', 0.5::real, + 'avg_width', 2::integer, + 'n_distinct', -0.1::real, + 'most_common_vals', '{"[2,3)","[1,2)","[3,4)"}'::text, + 'most_common_freqs', '{0.3,0.25,0.05}'::real[], + 'histogram_bounds', '{"[1,2)","[2,3)","[3,4)","[4,5)"}'::text, + 'correlation', 1.1::real, + 'most_common_elems', '{3,1}'::text, + 'most_common_elem_freqs', '{0.3,0.2,0.2,0.3,0.0}'::real[], + 'range_empty_frac', -0.5::real, + 'range_length_histogram', '{399,499,Infinity}'::text, + 'range_bounds_histogram', '{"[-1,1)","[0,4)","[1,4)","[1,100)"}'::text + ); + +SELECT * +FROM pg_stats +WHERE schemaname = 'stats_import' +AND tablename = 'test' +AND inherited = false +AND attname = 'arange'; + +-- warn: scalars can't have mcelem +SELECT pg_catalog.pg_restore_attribute_stats( + 'relation', 'stats_import.test'::regclass, + 'attname', 'id'::name, + 'inherited', false::boolean, + 'null_frac', 0.5::real, + 'avg_width', 2::integer, + 'n_distinct', -0.1::real, + 'most_common_elems', '{1,3}'::text, + 'most_common_elem_freqs', '{0.3,0.2,0.2,0.3,0.0}'::real[] + ); + +SELECT * +FROM pg_stats +WHERE schemaname = 'stats_import' +AND tablename = 'test' +AND inherited = false +AND attname = 'id'; + +-- warn: mcelem / mcelem mismatch +SELECT pg_catalog.pg_restore_attribute_stats( + 'relation', 'stats_import.test'::regclass, + 'attname', 'tags'::name, + 'inherited', false::boolean, + 'null_frac', 0.5::real, + 'avg_width', 2::integer, + 'n_distinct', -0.1::real, + 'most_common_elems', '{one,two}'::text + ); + +SELECT * +FROM pg_stats +WHERE schemaname = 'stats_import' +AND tablename = 'test' +AND inherited = false +AND attname = 'tags'; + +-- warn: mcelem / mcelem null mismatch part 2 +SELECT pg_catalog.pg_restore_attribute_stats( + 'relation', 'stats_import.test'::regclass, + 'attname', 'tags'::name, + 'inherited', false::boolean, + 'null_frac', 0.5::real, + 'avg_width', 2::integer, + 'n_distinct', -0.1::real, + 'most_common_elem_freqs', '{0.3,0.2,0.2,0.3}'::real[] + ); + +-- ok: mcelem +SELECT pg_catalog.pg_restore_attribute_stats( + 'relation', 'stats_import.test'::regclass, + 'attname', 'tags'::name, + 'inherited', false::boolean, + 'null_frac', 0.5::real, + 'avg_width', 2::integer, + 'n_distinct', -0.1::real, + 'most_common_elems', '{one,three}'::text, + 'most_common_elem_freqs', '{0.3,0.2,0.2,0.3,0.0}'::real[] + ); + +SELECT * +FROM pg_stats +WHERE schemaname = 'stats_import' +AND tablename = 'test' +AND inherited = false +AND attname = 'tags'; + +-- warn: scalars can't have elem_count_histogram +SELECT pg_catalog.pg_restore_attribute_stats( + 'relation', 'stats_import.test'::regclass, + 'attname', 'id'::name, + 'inherited', false::boolean, + 'null_frac', 0.5::real, + 'avg_width', 2::integer, + 'n_distinct', -0.1::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[] + ); + +SELECT * +FROM pg_stats +WHERE schemaname = 'stats_import' +AND tablename = 'test' +AND inherited = false +AND attname = 'id'; + -- warn: too many stat kinds SELECT pg_catalog.pg_restore_attribute_stats( 'relation', 'stats_import.test'::regclass, @@ -1069,6 +631,13 @@ SELECT pg_catalog.pg_restore_attribute_stats( 'range_length_histogram', '{399,499,Infinity}'::text, 'range_bounds_histogram', '{"[-1,1)","[0,4)","[1,4)","[1,100)"}'::text); +SELECT * +FROM pg_stats +WHERE schemaname = 'stats_import' +AND tablename = 'test' +AND inherited = false +AND attname = 'arange'; + -- -- Test the ability to exactly copy data from one table to an identical table, -- correctly reconstructing the stakind order as well as the staopN and @@ -1105,173 +674,6 @@ CREATE TABLE stats_import.test_clone ( LIKE stats_import.test ) CREATE INDEX is_odd_clone ON stats_import.test_clone(((comp).a % 2 = 1)); --- --- Copy stats from test to test_clone, and is_odd to is_odd_clone --- -SELECT s.schemaname, s.tablename, s.attname, s.inherited -FROM pg_catalog.pg_stats AS s -CROSS JOIN LATERAL - pg_catalog.pg_set_attribute_stats( - relation => ('stats_import.' || s.tablename || '_clone')::regclass::oid, - attname => s.attname, - inherited => s.inherited, - null_frac => s.null_frac, - avg_width => s.avg_width, - n_distinct => s.n_distinct, - most_common_vals => s.most_common_vals::text, - most_common_freqs => s.most_common_freqs, - histogram_bounds => s.histogram_bounds::text, - correlation => s.correlation, - most_common_elems => s.most_common_elems::text, - most_common_elem_freqs => s.most_common_elem_freqs, - elem_count_histogram => s.elem_count_histogram, - range_bounds_histogram => s.range_bounds_histogram::text, - range_empty_frac => s.range_empty_frac, - range_length_histogram => s.range_length_histogram::text) AS r -WHERE s.schemaname = 'stats_import' -AND s.tablename IN ('test', 'is_odd') -ORDER BY s.tablename, s.attname, s.inherited; - -SELECT c.relname, COUNT(*) AS num_stats -FROM pg_class AS c -JOIN pg_statistic s ON s.starelid = c.oid -WHERE c.relnamespace = 'stats_import'::regnamespace -AND c.relname IN ('test', 'test_clone', 'is_odd', 'is_odd_clone') -GROUP BY c.relname -ORDER BY c.relname; - --- check test minus test_clone -SELECT - a.attname, s.stainherit, s.stanullfrac, s.stawidth, s.stadistinct, - s.stakind1, s.stakind2, s.stakind3, s.stakind4, s.stakind5, - s.staop1, s.staop2, s.staop3, s.staop4, s.staop5, - s.stacoll1, s.stacoll2, s.stacoll3, s.stacoll4, s.stacoll5, - s.stanumbers1, s.stanumbers2, s.stanumbers3, s.stanumbers4, s.stanumbers5, - s.stavalues1::text AS sv1, s.stavalues2::text AS sv2, - s.stavalues3::text AS sv3, s.stavalues4::text AS sv4, - s.stavalues5::text AS sv5, 'test' AS direction -FROM pg_statistic s -JOIN pg_attribute a ON a.attrelid = s.starelid AND a.attnum = s.staattnum -WHERE s.starelid = 'stats_import.test'::regclass -EXCEPT -SELECT - a.attname, s.stainherit, s.stanullfrac, s.stawidth, s.stadistinct, - s.stakind1, s.stakind2, s.stakind3, s.stakind4, s.stakind5, - s.staop1, s.staop2, s.staop3, s.staop4, s.staop5, - s.stacoll1, s.stacoll2, s.stacoll3, s.stacoll4, s.stacoll5, - s.stanumbers1, s.stanumbers2, s.stanumbers3, s.stanumbers4, s.stanumbers5, - s.stavalues1::text AS sv1, s.stavalues2::text AS sv2, - s.stavalues3::text AS sv3, s.stavalues4::text AS sv4, - s.stavalues5::text AS sv5, 'test' AS direction -FROM pg_statistic s -JOIN pg_attribute a ON a.attrelid = s.starelid AND a.attnum = s.staattnum -WHERE s.starelid = 'stats_import.test_clone'::regclass; - --- check test_clone minus test -SELECT - a.attname, s.stainherit, s.stanullfrac, s.stawidth, s.stadistinct, - s.stakind1, s.stakind2, s.stakind3, s.stakind4, s.stakind5, - s.staop1, s.staop2, s.staop3, s.staop4, s.staop5, - s.stacoll1, s.stacoll2, s.stacoll3, s.stacoll4, s.stacoll5, - s.stanumbers1, s.stanumbers2, s.stanumbers3, s.stanumbers4, s.stanumbers5, - s.stavalues1::text AS sv1, s.stavalues2::text AS sv2, - s.stavalues3::text AS sv3, s.stavalues4::text AS sv4, - s.stavalues5::text AS sv5, 'test_clone' AS direction -FROM pg_statistic s -JOIN pg_attribute a ON a.attrelid = s.starelid AND a.attnum = s.staattnum -WHERE s.starelid = 'stats_import.test_clone'::regclass -EXCEPT -SELECT - a.attname, s.stainherit, s.stanullfrac, s.stawidth, s.stadistinct, - s.stakind1, s.stakind2, s.stakind3, s.stakind4, s.stakind5, - s.staop1, s.staop2, s.staop3, s.staop4, s.staop5, - s.stacoll1, s.stacoll2, s.stacoll3, s.stacoll4, s.stacoll5, - s.stanumbers1, s.stanumbers2, s.stanumbers3, s.stanumbers4, s.stanumbers5, - s.stavalues1::text AS sv1, s.stavalues2::text AS sv2, - s.stavalues3::text AS sv3, s.stavalues4::text AS sv4, - s.stavalues5::text AS sv5, 'test_clone' AS direction -FROM pg_statistic s -JOIN pg_attribute a ON a.attrelid = s.starelid AND a.attnum = s.staattnum -WHERE s.starelid = 'stats_import.test'::regclass; - --- check is_odd minus is_odd_clone -SELECT - a.attname, s.stainherit, s.stanullfrac, s.stawidth, s.stadistinct, - s.stakind1, s.stakind2, s.stakind3, s.stakind4, s.stakind5, - s.staop1, s.staop2, s.staop3, s.staop4, s.staop5, - s.stacoll1, s.stacoll2, s.stacoll3, s.stacoll4, s.stacoll5, - s.stanumbers1, s.stanumbers2, s.stanumbers3, s.stanumbers4, s.stanumbers5, - s.stavalues1::text AS sv1, s.stavalues2::text AS sv2, - s.stavalues3::text AS sv3, s.stavalues4::text AS sv4, - s.stavalues5::text AS sv5, 'is_odd' AS direction -FROM pg_statistic s -JOIN pg_attribute a ON a.attrelid = s.starelid AND a.attnum = s.staattnum -WHERE s.starelid = 'stats_import.is_odd'::regclass -EXCEPT -SELECT - a.attname, s.stainherit, s.stanullfrac, s.stawidth, s.stadistinct, - s.stakind1, s.stakind2, s.stakind3, s.stakind4, s.stakind5, - s.staop1, s.staop2, s.staop3, s.staop4, s.staop5, - s.stacoll1, s.stacoll2, s.stacoll3, s.stacoll4, s.stacoll5, - s.stanumbers1, s.stanumbers2, s.stanumbers3, s.stanumbers4, s.stanumbers5, - s.stavalues1::text AS sv1, s.stavalues2::text AS sv2, - s.stavalues3::text AS sv3, s.stavalues4::text AS sv4, - s.stavalues5::text AS sv5, 'is_odd' AS direction -FROM pg_statistic s -JOIN pg_attribute a ON a.attrelid = s.starelid AND a.attnum = s.staattnum -WHERE s.starelid = 'stats_import.is_odd_clone'::regclass; - --- check is_odd_clone minus is_odd -SELECT - a.attname, s.stainherit, s.stanullfrac, s.stawidth, s.stadistinct, - s.stakind1, s.stakind2, s.stakind3, s.stakind4, s.stakind5, - s.staop1, s.staop2, s.staop3, s.staop4, s.staop5, - s.stacoll1, s.stacoll2, s.stacoll3, s.stacoll4, s.stacoll5, - s.stanumbers1, s.stanumbers2, s.stanumbers3, s.stanumbers4, s.stanumbers5, - s.stavalues1::text AS sv1, s.stavalues2::text AS sv2, - s.stavalues3::text AS sv3, s.stavalues4::text AS sv4, - s.stavalues5::text AS sv5, 'is_odd_clone' AS direction -FROM pg_statistic s -JOIN pg_attribute a ON a.attrelid = s.starelid AND a.attnum = s.staattnum -WHERE s.starelid = 'stats_import.is_odd_clone'::regclass -EXCEPT -SELECT - a.attname, s.stainherit, s.stanullfrac, s.stawidth, s.stadistinct, - s.stakind1, s.stakind2, s.stakind3, s.stakind4, s.stakind5, - s.staop1, s.staop2, s.staop3, s.staop4, s.staop5, - s.stacoll1, s.stacoll2, s.stacoll3, s.stacoll4, s.stacoll5, - s.stanumbers1, s.stanumbers2, s.stanumbers3, s.stanumbers4, s.stanumbers5, - s.stavalues1::text AS sv1, s.stavalues2::text AS sv2, - s.stavalues3::text AS sv3, s.stavalues4::text AS sv4, - s.stavalues5::text AS sv5, 'is_odd_clone' AS direction -FROM pg_statistic s -JOIN pg_attribute a ON a.attrelid = s.starelid AND a.attnum = s.staattnum -WHERE s.starelid = 'stats_import.is_odd'::regclass; - --- -SELECT relpages, reltuples, relallvisible -FROM pg_class -WHERE oid = 'stats_import.test'::regclass; - --- --- Clear clone stats to try again with pg_restore_attribute_stats --- -SELECT - pg_catalog.pg_clear_attribute_stats( - ('stats_import.' || s.tablename)::regclass, - s.attname, - s.inherited) -FROM pg_catalog.pg_stats AS s -WHERE s.schemaname = 'stats_import' -AND s.tablename IN ('test_clone', 'is_odd_clone') -ORDER BY s.tablename, s.attname, s.inherited; -SELECT - -SELECT COUNT(*) -FROM pg_catalog.pg_stats AS s -WHERE s.schemaname = 'stats_import' -AND s.tablename IN ('test_clone', 'is_odd_clone'); - -- -- Copy stats from test to test_clone, and is_odd to is_odd_clone -- @@ -1416,4 +818,143 @@ FROM pg_statistic s JOIN pg_attribute a ON a.attrelid = s.starelid AND a.attnum = s.staattnum WHERE s.starelid = 'stats_import.is_odd'::regclass; +-- ok +SELECT pg_catalog.pg_clear_attribute_stats( + relation => 'stats_import.test'::regclass, + attname => 'arange'::name, + inherited => false::boolean); + +-- +-- Negative tests +-- + +--- error: relation is wrong type +SELECT pg_catalog.pg_restore_relation_stats( + 'relation', 0::oid, + 'relpages', 17::integer, + 'reltuples', 400.0::real, + 'relallvisible', 4::integer); + +--- error: relation not found +SELECT pg_catalog.pg_restore_relation_stats( + 'relation', 0::regclass, + 'relpages', 17::integer, + 'reltuples', 400.0::real, + 'relallvisible', 4::integer); + +-- warn and error: unrecognized argument name +SELECT pg_restore_relation_stats( + 'relation', '0'::oid::regclass, + 'version', 150000::integer, + 'relpages', '17'::integer, + 'reltuples', 400::real, + 'nope', 4::integer); + +-- error: argument name is NULL +SELECT pg_restore_relation_stats( + 'relation', '0'::oid::regclass, + 'version', 150000::integer, + NULL, '17'::integer, + 'reltuples', 400::real, + 'relallvisible', 4::integer); + +-- error: argument name is an integer +SELECT pg_restore_relation_stats( + 'relation', '0'::oid::regclass, + 'version', 150000::integer, + 17, '17'::integer, + 'reltuples', 400::real, + 'relallvisible', 4::integer); + +-- error: odd number of variadic arguments cannot be pairs +SELECT pg_restore_relation_stats( + 'relation', '0'::oid::regclass, + 'version', 150000::integer, + 'relpages', '17'::integer, + 'reltuples', 400::real, + 'relallvisible'); + +-- error: object doesn't exist +SELECT pg_restore_relation_stats( + 'relation', '0'::oid::regclass, + 'version', 150000::integer, + 'relpages', '17'::integer, + 'reltuples', 400::real, + 'relallvisible', 4::integer); + +-- error: object does not exist +SELECT pg_catalog.pg_restore_attribute_stats( + 'relation', '0'::oid::regclass, + 'attname', 'id'::name, + 'inherited', false::boolean, + 'version', 150000::integer, + 'null_frac', 0.1::real, + 'avg_width', 2::integer, + 'n_distinct', 0.3::real); + +-- error: relation null +SELECT pg_catalog.pg_restore_attribute_stats( + 'relation', NULL::oid, + 'attname', 'id'::name, + 'inherited', false::boolean, + 'version', 150000::integer, + 'null_frac', 0.1::real, + 'avg_width', 2::integer, + 'n_distinct', 0.3::real); + +-- error: attname null +SELECT pg_catalog.pg_restore_attribute_stats( + 'relation', 'stats_import.test'::regclass, + 'attname', NULL::name, + 'inherited', false::boolean, + 'version', 150000::integer, + 'null_frac', 0.1::real, + 'avg_width', 2::integer, + 'n_distinct', 0.3::real); + +-- error: attname doesn't exist +SELECT pg_catalog.pg_restore_attribute_stats( + 'relation', 'stats_import.test'::regclass, + 'attname', 'nope'::name, + 'inherited', false::boolean, + 'version', 150000::integer, + 'null_frac', 0.1::real, + 'avg_width', 2::integer, + 'n_distinct', 0.3::real); + +-- error: attribute is system column +SELECT pg_catalog.pg_restore_attribute_stats( + 'relation', 'stats_import.test'::regclass, + 'attname', 'xmin'::name, + 'inherited', false::boolean, + 'null_frac', 0.1::real, + 'avg_width', 2::integer, + 'n_distinct', 0.3::real); + +-- error: inherited null +SELECT pg_catalog.pg_restore_attribute_stats( + 'relation', 'stats_import.test'::regclass, + 'attname', 'id'::name, + 'inherited', NULL::boolean, + 'version', 150000::integer, + 'null_frac', 0.1::real, + 'avg_width', 2::integer, + 'n_distinct', 0.3::real); + +-- error: relation not found +SELECT pg_catalog.pg_clear_relation_stats( + relation => 'stats_import.nope'::regclass); + +-- error: attribute is system column +SELECT pg_catalog.pg_clear_attribute_stats( + relation => 'stats_import.test'::regclass, + attname => 'ctid'::name, + inherited => false::boolean); + +-- error: attname doesn't exist +SELECT pg_catalog.pg_clear_attribute_stats( + relation => 'stats_import.test'::regclass, + attname => 'nope'::name, + inherited => false::boolean); + DROP SCHEMA stats_import CASCADE;