+ /*
+ * 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.
+ */
+ namespace = form->prsnamespace;
+ if (namespace != PG_CATALOG_NAMESPACE &&
+ !list_member_oid(activeSearchPath, namespace))
+ visible = false;
+ else
+ {
+ /*
+ * If it is in the path, it might still not be visible; it could be
+ * hidden by another parser of the same name earlier in the path. So
+ * we must do a slow check for conflicting parsers.
+ */
+ char *name = NameStr(form->prsname);
+ ListCell *l;
+
+ visible = false;
+ foreach(l, activeSearchPath)
+ {
+ Oid namespaceId = lfirst_oid(l);
+
+ if (namespaceId == myTempNamespace)
+ continue; /* do not look in temp namespace */
+
+ if (namespaceId == namespace)
+ {
+ /* Found it first in path */
+ visible = true;
+ break;
+ }
+ if (SearchSysCacheExists2(TSPARSERNAMENSP,
+ PointerGetDatum(name),
+ ObjectIdGetDatum(namespaceId)))
+ {
+ /* Found something else first in path */
+ break;
+ }
+ }
+ }
+
+ ReleaseSysCache(tup);
+
+ return visible;
+}
+
+/*
+ * get_ts_dict_oid - find a TS dictionary by possibly qualified name
+ *
+ * If not found, returns InvalidOid if failOK, else throws error
+ */
+Oid
+get_ts_dict_oid(List *names, bool missing_ok)
+{
+ char *schemaname;
+ char *dict_name;
+ Oid namespaceId;
+ Oid dictoid = InvalidOid;
+ ListCell *l;
+
+ /* deconstruct the name list */
+ DeconstructQualifiedName(names, &schemaname, &dict_name);
+
+ if (schemaname)
+ {
+ /* use exact schema given */
+ namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
+ if (missing_ok && !OidIsValid(namespaceId))
+ dictoid = InvalidOid;
+ else
+ dictoid = GetSysCacheOid2(TSDICTNAMENSP,
+ PointerGetDatum(dict_name),
+ ObjectIdGetDatum(namespaceId));
+ }
+ else
+ {
+ /* search for it in search path */
+ recomputeNamespacePath();
+
+ foreach(l, activeSearchPath)
+ {
+ namespaceId = lfirst_oid(l);
+
+ if (namespaceId == myTempNamespace)
+ continue; /* do not look in temp namespace */
+
+ dictoid = GetSysCacheOid2(TSDICTNAMENSP,
+ PointerGetDatum(dict_name),
+ ObjectIdGetDatum(namespaceId));
+ if (OidIsValid(dictoid))
+ break;
+ }
+ }
+
+ if (!OidIsValid(dictoid) && !missing_ok)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("text search dictionary \"%s\" does not exist",
+ NameListToString(names))));
+
+ return dictoid;
+}
+
+/*
+ * TSDictionaryIsVisible
+ * Determine whether a dictionary (identified by OID) is visible in the
+ * current search path. Visible means "would be found by searching
+ * for the unqualified dictionary name".
+ */
+bool
+TSDictionaryIsVisible(Oid dictId)
+{
+ HeapTuple tup;
+ Form_pg_ts_dict form;
+ Oid namespace;
+ bool visible;
+
+ tup = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictId));
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for text search dictionary %u",
+ dictId);
+ form = (Form_pg_ts_dict) GETSTRUCT(tup);
+
+ 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.
+ */
+ namespace = form->dictnamespace;
+ if (namespace != PG_CATALOG_NAMESPACE &&
+ !list_member_oid(activeSearchPath, namespace))
+ visible = false;
+ else
+ {
+ /*
+ * If it is in the path, it might still not be visible; it could be
+ * hidden by another dictionary of the same name earlier in the path.
+ * So we must do a slow check for conflicting dictionaries.
+ */
+ char *name = NameStr(form->dictname);
+ ListCell *l;
+
+ visible = false;
+ foreach(l, activeSearchPath)
+ {
+ Oid namespaceId = lfirst_oid(l);
+
+ if (namespaceId == myTempNamespace)
+ continue; /* do not look in temp namespace */
+
+ if (namespaceId == namespace)
+ {
+ /* Found it first in path */
+ visible = true;
+ break;
+ }
+ if (SearchSysCacheExists2(TSDICTNAMENSP,
+ PointerGetDatum(name),
+ ObjectIdGetDatum(namespaceId)))
+ {
+ /* Found something else first in path */
+ break;
+ }
+ }
+ }
+
+ ReleaseSysCache(tup);
+
+ return visible;
+}
+
+/*
+ * get_ts_template_oid - find a TS template by possibly qualified name
+ *
+ * If not found, returns InvalidOid if missing_ok, else throws error
+ */
+Oid
+get_ts_template_oid(List *names, bool missing_ok)
+{
+ char *schemaname;
+ char *template_name;
+ Oid namespaceId;
+ Oid tmploid = InvalidOid;
+ ListCell *l;
+
+ /* deconstruct the name list */
+ DeconstructQualifiedName(names, &schemaname, &template_name);
+
+ if (schemaname)
+ {
+ /* use exact schema given */
+ namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
+ if (missing_ok && !OidIsValid(namespaceId))
+ tmploid = InvalidOid;
+ else
+ tmploid = GetSysCacheOid2(TSTEMPLATENAMENSP,
+ PointerGetDatum(template_name),
+ ObjectIdGetDatum(namespaceId));
+ }
+ else
+ {
+ /* search for it in search path */
+ recomputeNamespacePath();
+
+ foreach(l, activeSearchPath)
+ {
+ namespaceId = lfirst_oid(l);
+
+ if (namespaceId == myTempNamespace)
+ continue; /* do not look in temp namespace */
+
+ tmploid = GetSysCacheOid2(TSTEMPLATENAMENSP,
+ PointerGetDatum(template_name),
+ ObjectIdGetDatum(namespaceId));
+ if (OidIsValid(tmploid))
+ break;
+ }
+ }
+
+ if (!OidIsValid(tmploid) && !missing_ok)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("text search template \"%s\" does not exist",
+ NameListToString(names))));
+
+ return tmploid;
+}
+
+/*
+ * TSTemplateIsVisible
+ * Determine whether a template (identified by OID) is visible in the
+ * current search path. Visible means "would be found by searching
+ * for the unqualified template name".
+ */
+bool
+TSTemplateIsVisible(Oid tmplId)
+{
+ HeapTuple tup;
+ Form_pg_ts_template form;
+ Oid namespace;
+ bool visible;
+
+ tup = SearchSysCache1(TSTEMPLATEOID, ObjectIdGetDatum(tmplId));
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for text search template %u", tmplId);
+ form = (Form_pg_ts_template) GETSTRUCT(tup);
+
+ 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.
+ */
+ namespace = form->tmplnamespace;
+ if (namespace != PG_CATALOG_NAMESPACE &&
+ !list_member_oid(activeSearchPath, namespace))
+ visible = false;
+ else
+ {
+ /*
+ * If it is in the path, it might still not be visible; it could be
+ * hidden by another template of the same name earlier in the path. So
+ * we must do a slow check for conflicting templates.
+ */
+ char *name = NameStr(form->tmplname);
+ ListCell *l;
+
+ visible = false;
+ foreach(l, activeSearchPath)
+ {
+ Oid namespaceId = lfirst_oid(l);
+
+ if (namespaceId == myTempNamespace)
+ continue; /* do not look in temp namespace */
+
+ if (namespaceId == namespace)
+ {
+ /* Found it first in path */
+ visible = true;
+ break;
+ }
+ if (SearchSysCacheExists2(TSTEMPLATENAMENSP,
+ PointerGetDatum(name),
+ ObjectIdGetDatum(namespaceId)))
+ {
+ /* Found something else first in path */
+ break;
+ }
+ }
+ }
+
+ ReleaseSysCache(tup);
+
+ return visible;
+}
+
+/*
+ * get_ts_config_oid - find a TS config by possibly qualified name
+ *
+ * If not found, returns InvalidOid if missing_ok, else throws error
+ */
+Oid
+get_ts_config_oid(List *names, bool missing_ok)
+{
+ char *schemaname;
+ char *config_name;
+ Oid namespaceId;
+ Oid cfgoid = InvalidOid;
+ ListCell *l;
+
+ /* deconstruct the name list */
+ DeconstructQualifiedName(names, &schemaname, &config_name);
+
+ if (schemaname)
+ {
+ /* use exact schema given */
+ namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
+ if (missing_ok && !OidIsValid(namespaceId))
+ cfgoid = InvalidOid;
+ else
+ cfgoid = GetSysCacheOid2(TSCONFIGNAMENSP,
+ PointerGetDatum(config_name),
+ ObjectIdGetDatum(namespaceId));
+ }
+ else
+ {
+ /* search for it in search path */
+ recomputeNamespacePath();
+
+ foreach(l, activeSearchPath)
+ {
+ namespaceId = lfirst_oid(l);
+
+ if (namespaceId == myTempNamespace)
+ continue; /* do not look in temp namespace */
+
+ cfgoid = GetSysCacheOid2(TSCONFIGNAMENSP,
+ PointerGetDatum(config_name),
+ ObjectIdGetDatum(namespaceId));
+ if (OidIsValid(cfgoid))
+ break;
+ }
+ }
+
+ if (!OidIsValid(cfgoid) && !missing_ok)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("text search configuration \"%s\" does not exist",
+ NameListToString(names))));
+
+ return cfgoid;
+}
+
+/*
+ * TSConfigIsVisible
+ * Determine whether a text search configuration (identified by OID)
+ * is visible in the current search path. Visible means "would be found
+ * by searching for the unqualified text search configuration name".
+ */
+bool
+TSConfigIsVisible(Oid cfgid)
+{
+ HeapTuple tup;
+ Form_pg_ts_config form;
+ Oid namespace;
+ bool visible;
+
+ tup = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfgid));
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for text search configuration %u",
+ cfgid);
+ form = (Form_pg_ts_config) GETSTRUCT(tup);
+
+ 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.
+ */
+ namespace = form->cfgnamespace;
+ if (namespace != PG_CATALOG_NAMESPACE &&
+ !list_member_oid(activeSearchPath, namespace))
+ visible = false;
+ else
+ {
+ /*
+ * If it is in the path, it might still not be visible; it could be
+ * hidden by another configuration of the same name earlier in the
+ * path. So we must do a slow check for conflicting configurations.
+ */
+ char *name = NameStr(form->cfgname);
+ ListCell *l;
+
+ visible = false;
+ foreach(l, activeSearchPath)
+ {
+ Oid namespaceId = lfirst_oid(l);
+
+ if (namespaceId == myTempNamespace)
+ continue; /* do not look in temp namespace */
+
+ if (namespaceId == namespace)
+ {
+ /* Found it first in path */
+ visible = true;
+ break;
+ }
+ if (SearchSysCacheExists2(TSCONFIGNAMENSP,
+ PointerGetDatum(name),
+ ObjectIdGetDatum(namespaceId)))
+ {
+ /* Found something else first in path */
+ break;
+ }
+ }
+ }
+
+ ReleaseSysCache(tup);
+
+ return visible;
+}
+
+
+/*
+ * DeconstructQualifiedName
+ * Given a possibly-qualified name expressed as a list of String nodes,
+ * extract the schema name and object name.
+ *
+ * *nspname_p is set to NULL if there is no explicit schema name.
+ */
+void
+DeconstructQualifiedName(List *names,
+ char **nspname_p,
+ char **objname_p)
+{
+ char *catalogname;
+ char *schemaname = NULL;
+ char *objname = NULL;
+
+ switch (list_length(names))
+ {
+ case 1:
+ objname = strVal(linitial(names));
+ break;
+ case 2:
+ schemaname = strVal(linitial(names));
+ objname = strVal(lsecond(names));
+ break;
+ case 3:
+ catalogname = strVal(linitial(names));
+ schemaname = strVal(lsecond(names));
+ objname = strVal(lthird(names));
+
+ /*
+ * We check the catalog name and then ignore it.
+ */
+ if (strcmp(catalogname, get_database_name(MyDatabaseId)) != 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cross-database references are not implemented: %s",
+ NameListToString(names))));
+ break;
+ default:
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("improper qualified name (too many dotted names): %s",
+ NameListToString(names))));
+ break;
+ }
+
+ *nspname_p = schemaname;
+ *objname_p = objname;
+}
+
+/*
+ * LookupNamespaceNoError
+ * Look up a schema name.
+ *
+ * Returns the namespace OID, or InvalidOid if not found.
+ *
+ * Note this does NOT perform any permissions check --- callers are
+ * responsible for being sure that an appropriate check is made.
+ * In the majority of cases LookupExplicitNamespace is preferable.
+ */
+Oid
+LookupNamespaceNoError(const char *nspname)
+{
+ /* check for pg_temp alias */
+ if (strcmp(nspname, "pg_temp") == 0)
+ {
+ if (OidIsValid(myTempNamespace))
+ {
+ InvokeNamespaceSearchHook(myTempNamespace, true);
+ return myTempNamespace;
+ }
+
+ /*
+ * Since this is used only for looking up existing objects, there is
+ * no point in trying to initialize the temp namespace here; and doing
+ * so might create problems for some callers. Just report "not found".
+ */
+ return InvalidOid;
+ }
+
+ return get_namespace_oid(nspname, true);
+}
+
+/*
+ * LookupExplicitNamespace
+ * Process an explicitly-specified schema name: look up the schema
+ * and verify we have USAGE (lookup) rights in it.
+ *
+ * Returns the namespace OID
+ */
+Oid
+LookupExplicitNamespace(const char *nspname, bool missing_ok)
+{
+ Oid namespaceId;
+ AclResult aclresult;
+
+ /* check for pg_temp alias */
+ if (strcmp(nspname, "pg_temp") == 0)
+ {
+ if (OidIsValid(myTempNamespace))
+ return myTempNamespace;
+
+ /*
+ * Since this is used only for looking up existing objects, there is
+ * no point in trying to initialize the temp namespace here; and doing
+ * so might create problems for some callers --- just fall through.
+ */
+ }
+
+ namespaceId = get_namespace_oid(nspname, missing_ok);
+ if (missing_ok && !OidIsValid(namespaceId))
+ return InvalidOid;
+
+ aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_USAGE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+ nspname);
+ /* Schema search hook for this lookup */
+ InvokeNamespaceSearchHook(namespaceId, true);
+
+ return namespaceId;
+}
+
+/*
+ * LookupCreationNamespace
+ * Look up the schema and verify we have CREATE rights on it.
+ *
+ * This is just like LookupExplicitNamespace except for the different
+ * permission check, and that we are willing to create pg_temp if needed.
+ *
+ * Note: calling this may result in a CommandCounterIncrement operation,
+ * if we have to create or clean out the temp namespace.
+ */
+Oid
+LookupCreationNamespace(const char *nspname)
+{
+ Oid namespaceId;
+ AclResult aclresult;
+
+ /* check for pg_temp alias */
+ if (strcmp(nspname, "pg_temp") == 0)
+ {
+ /* Initialize temp namespace if first time through */
+ if (!OidIsValid(myTempNamespace))
+ InitTempTableNamespace();
+ return myTempNamespace;
+ }
+
+ namespaceId = get_namespace_oid(nspname, false);
+
+ aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+ nspname);
+
+ return namespaceId;
+}
+
+/*
+ * Common checks on switching namespaces.
+ *
+ * We complain if either the old or new namespaces is a temporary schema
+ * (or temporary toast schema), or if either the old or new namespaces is the
+ * TOAST schema.
+ */
+void
+CheckSetNamespace(Oid oldNspOid, Oid nspOid)
+{
+ /* disallow renaming into or out of temp schemas */
+ if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot move objects into or out of temporary schemas")));
+
+ /* same for TOAST schema */
+ if (nspOid == PG_TOAST_NAMESPACE || oldNspOid == PG_TOAST_NAMESPACE)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot move objects into or out of TOAST schema")));