diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 5f47c59f8a..d55656769b 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -16681,6 +16681,12 @@ SELECT relname FROM pg_class WHERE pg_table_is_visible(oid); is operator family visible in search path + pg_statistic_ext_is_visible(stat_oid) + + boolean + is statistics object visible in search path + + pg_table_is_visible(table_oid) boolean @@ -16739,6 +16745,9 @@ SELECT relname FROM pg_class WHERE pg_table_is_visible(oid); pg_opfamily_is_visible + pg_statistic_ext_is_visible + + pg_table_is_visible diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c index e521bd908a..5b339222af 100644 --- a/src/backend/catalog/namespace.c +++ b/src/backend/catalog/namespace.c @@ -34,6 +34,7 @@ #include "catalog/pg_operator.h" #include "catalog/pg_opfamily.h" #include "catalog/pg_proc.h" +#include "catalog/pg_statistic_ext.h" #include "catalog/pg_ts_config.h" #include "catalog/pg_ts_dict.h" #include "catalog/pg_ts_parser.h" @@ -2142,6 +2143,72 @@ get_statistics_oid(List *names, bool missing_ok) } /* + * StatisticsObjIsVisible + * Determine whether a statistics object (identified by OID) is visible in + * the current search path. Visible means "would be found by searching + * for the unqualified statistics object name". + */ +bool +StatisticsObjIsVisible(Oid relid) +{ + HeapTuple stxtup; + Form_pg_statistic_ext stxform; + Oid stxnamespace; + bool visible; + + stxtup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(relid)); + if (!HeapTupleIsValid(stxtup)) + elog(ERROR, "cache lookup failed for statistics object %u", relid); + stxform = (Form_pg_statistic_ext) GETSTRUCT(stxtup); + + recomputeNamespacePath(); + + /* + * Quick check: if it ain't in the path at all, it ain't visible. Items in + * the system namespace are surely in the path and so we needn't even do + * list_member_oid() for them. + */ + stxnamespace = stxform->stxnamespace; + if (stxnamespace != PG_CATALOG_NAMESPACE && + !list_member_oid(activeSearchPath, stxnamespace)) + visible = false; + else + { + /* + * If it is in the path, it might still not be visible; it could be + * hidden by another statistics object of the same name earlier in the + * path. So we must do a slow check for conflicting objects. + */ + char *stxname = NameStr(stxform->stxname); + ListCell *l; + + visible = false; + foreach(l, activeSearchPath) + { + Oid namespaceId = lfirst_oid(l); + + if (namespaceId == stxnamespace) + { + /* Found it first in path */ + visible = true; + break; + } + if (SearchSysCacheExists2(STATEXTNAMENSP, + PointerGetDatum(stxname), + ObjectIdGetDatum(namespaceId))) + { + /* Found something else first in path */ + break; + } + } + } + + ReleaseSysCache(stxtup); + + return visible; +} + +/* * get_ts_parser_oid - find a TS parser by possibly qualified name * * If not found, returns InvalidOid if missing_ok, else throws error @@ -4236,6 +4303,17 @@ pg_conversion_is_visible(PG_FUNCTION_ARGS) } Datum +pg_statistic_ext_is_visible(PG_FUNCTION_ARGS) +{ + Oid oid = PG_GETARG_OID(0); + + if (!SearchSysCacheExists1(STATEXTOID, ObjectIdGetDatum(oid))) + PG_RETURN_NULL(); + + PG_RETURN_BOOL(StatisticsObjIsVisible(oid)); +} + +Datum pg_ts_parser_is_visible(PG_FUNCTION_ARGS) { Oid oid = PG_GETARG_OID(0); diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index 236d876b1c..720e540276 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -32,6 +32,7 @@ #include "catalog/pg_proc.h" #include "catalog/pg_range.h" #include "catalog/pg_statistic.h" +#include "catalog/pg_statistic_ext.h" #include "catalog/pg_transform.h" #include "catalog/pg_type.h" #include "miscadmin.h" diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index 09fb30f270..ae3730257d 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -622,7 +622,7 @@ static const SchemaQuery Query_for_list_of_statistics = { /* selcondition */ NULL, /* viscondition */ - NULL, + "pg_catalog.pg_statistic_ext_is_visible(s.oid)", /* namespace */ "s.stxnamespace", /* result */ diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h index 35e0e2b089..959ee4c50e 100644 --- a/src/include/catalog/namespace.h +++ b/src/include/catalog/namespace.h @@ -92,6 +92,9 @@ extern bool CollationIsVisible(Oid collid); extern Oid ConversionGetConid(const char *conname); extern bool ConversionIsVisible(Oid conid); +extern Oid get_statistics_oid(List *names, bool missing_ok); +extern bool StatisticsObjIsVisible(Oid stxid); + extern Oid get_ts_parser_oid(List *names, bool missing_ok); extern bool TSParserIsVisible(Oid prsId); @@ -141,7 +144,6 @@ extern Oid get_collation_oid(List *collname, bool missing_ok); extern Oid get_conversion_oid(List *conname, bool missing_ok); extern Oid FindDefaultConversionProc(int32 for_encoding, int32 to_encoding); -extern Oid get_statistics_oid(List *names, bool missing_ok); /* initialization & transaction cleanup code */ extern void InitializeSearchPath(void); diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 77d8ed5184..8d84d9a890 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -3181,6 +3181,8 @@ DATA(insert OID = 3829 ( pg_opfamily_is_visible PGNSP PGUID 12 10 0 0 0 f f f f DESCR("is opfamily visible in search path?"); DATA(insert OID = 2093 ( pg_conversion_is_visible PGNSP PGUID 12 10 0 0 0 f f f f t f s s 1 0 16 "26" _null_ _null_ _null_ _null_ _null_ pg_conversion_is_visible _null_ _null_ _null_ )); DESCR("is conversion visible in search path?"); +DATA(insert OID = 3403 ( pg_statistic_ext_is_visible PGNSP PGUID 12 10 0 0 0 f f f f t f s s 1 0 16 "26" _null_ _null_ _null_ _null_ _null_ pg_statistic_ext_is_visible _null_ _null_ _null_ )); +DESCR("is statistics object visible in search path?"); DATA(insert OID = 3756 ( pg_ts_parser_is_visible PGNSP PGUID 12 10 0 0 0 f f f f t f s s 1 0 16 "26" _null_ _null_ _null_ _null_ _null_ pg_ts_parser_is_visible _null_ _null_ _null_ )); DESCR("is text search parser visible in search path?"); DATA(insert OID = 3757 ( pg_ts_dict_is_visible PGNSP PGUID 12 10 0 0 0 f f f f t f s s 1 0 16 "26" _null_ _null_ _null_ _null_ _null_ pg_ts_dict_is_visible _null_ _null_ _null_ ));