1 /*-------------------------------------------------------------------------
4 * code to support accessing and searching namespaces
6 * This is separate from pg_namespace.c, which contains the routines that
7 * directly manipulate the pg_namespace system catalog. This module
8 * provides routines associated with defining a "namespace search path"
9 * and implementing search-path-controlled searches.
12 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
13 * Portions Copyright (c) 1994, Regents of the University of California
16 * $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.19 2002/05/12 20:10:01 tgl Exp $
18 *-------------------------------------------------------------------------
22 #include "access/heapam.h"
23 #include "access/xact.h"
24 #include "catalog/catalog.h"
25 #include "catalog/catname.h"
26 #include "catalog/heap.h"
27 #include "catalog/namespace.h"
28 #include "catalog/pg_inherits.h"
29 #include "catalog/pg_namespace.h"
30 #include "catalog/pg_opclass.h"
31 #include "catalog/pg_operator.h"
32 #include "catalog/pg_proc.h"
33 #include "catalog/pg_shadow.h"
34 #include "catalog/pg_type.h"
35 #include "lib/stringinfo.h"
36 #include "miscadmin.h"
37 #include "nodes/makefuncs.h"
38 #include "storage/backendid.h"
39 #include "storage/ipc.h"
40 #include "utils/acl.h"
41 #include "utils/builtins.h"
42 #include "utils/catcache.h"
43 #include "utils/fmgroids.h"
44 #include "utils/guc.h"
45 #include "utils/inval.h"
46 #include "utils/lsyscache.h"
47 #include "utils/syscache.h"
51 * The namespace search path is a possibly-empty list of namespace OIDs.
52 * In addition to the explicit list, the TEMP table namespace is always
53 * implicitly searched first (if it's been initialized). Also, the system
54 * catalog namespace is always searched. If the system namespace is
55 * explicitly present in the path then it will be searched in the specified
56 * order; otherwise it will be searched after TEMP tables and *before* the
57 * explicit list. (It might seem that the system namespace should be
58 * implicitly last, but this behavior appears to be required by SQL99.
59 * Also, this provides a way to search the system namespace first without
60 * thereby making it the default creation target namespace.)
62 * The default creation target namespace is kept equal to the first element
63 * of the (explicit) list. If the list is empty, there is no default target.
65 * In bootstrap mode, the search path is set equal to 'pg_catalog', so that
66 * the system namespace is the only one searched or inserted into.
67 * The initdb script is also careful to set search_path to 'pg_catalog' for
68 * its post-bootstrap standalone backend runs. Otherwise the default search
69 * path is determined by GUC. The factory default path contains the PUBLIC
70 * namespace (if it exists), preceded by the user's personal namespace
73 * If namespaceSearchPathValid is false, then namespaceSearchPath (and the
74 * derived variables) need to be recomputed from namespace_search_path.
75 * We mark it invalid upon an assignment to namespace_search_path or receipt
76 * of a syscache invalidation event for pg_namespace. The recomputation
77 * is done during the next lookup attempt.
79 * Any namespaces mentioned in namespace_search_path that are not readable
80 * by the current user ID are simply left out of namespaceSearchPath; so
81 * we have to be willing to recompute the path when current userid changes.
82 * namespaceUser is the userid the path has been computed for.
85 static List *namespaceSearchPath = NIL;
87 static bool namespaceSearchPathValid = true;
89 static Oid namespaceUser = InvalidOid;
91 /* this flag must be updated correctly when namespaceSearchPath is changed */
92 static bool pathContainsSystemNamespace = false;
94 /* default place to create stuff; if InvalidOid, no default */
95 static Oid defaultCreationNamespace = InvalidOid;
98 * myTempNamespace is InvalidOid until and unless a TEMP namespace is set up
99 * in a particular backend session (this happens when a CREATE TEMP TABLE
100 * command is first executed). Thereafter it's the OID of the temp namespace.
102 static Oid myTempNamespace = InvalidOid;
105 * This is the text equivalent of the search path --- it's the value
106 * of the GUC variable 'search_path'.
108 char *namespace_search_path = NULL;
112 * Deletion ordering constraint item.
114 typedef struct DelConstraint
116 Oid referencer; /* table to delete first */
117 Oid referencee; /* table to delete second */
118 int pred; /* workspace for TopoSortRels */
119 struct DelConstraint *link; /* workspace for TopoSortRels */
123 /* Local functions */
124 static void recomputeNamespacePath(void);
125 static Oid GetTempTableNamespace(void);
126 static void RemoveTempRelations(Oid tempNamespaceId);
127 static List *FindTempRelations(Oid tempNamespaceId);
128 static List *FindDeletionConstraints(List *relOids);
129 static List *TopoSortRels(List *relOids, List *constraintList);
130 static void RemoveTempRelationsCallback(void);
131 static void NamespaceCallback(Datum arg, Oid relid);
136 * Given a RangeVar describing an existing relation,
137 * select the proper namespace and look up the relation OID.
139 * If the relation is not found, return InvalidOid if failOK = true,
140 * otherwise raise an error.
143 RangeVarGetRelid(const RangeVar *relation, bool failOK)
149 * We check the catalog name and then ignore it.
151 if (relation->catalogname)
153 if (strcmp(relation->catalogname, DatabaseName) != 0)
154 elog(ERROR, "Cross-database references are not implemented");
157 if (relation->schemaname)
159 /* use exact schema given */
162 namespaceId = GetSysCacheOid(NAMESPACENAME,
163 CStringGetDatum(relation->schemaname),
165 if (!OidIsValid(namespaceId))
166 elog(ERROR, "Namespace \"%s\" does not exist",
167 relation->schemaname);
168 aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_USAGE);
169 if (aclresult != ACLCHECK_OK)
170 aclcheck_error(aclresult, relation->schemaname);
172 relId = get_relname_relid(relation->relname, namespaceId);
176 /* search the namespace path */
177 relId = RelnameGetRelid(relation->relname);
180 if (!OidIsValid(relId) && !failOK)
182 if (relation->schemaname)
183 elog(ERROR, "Relation \"%s\".\"%s\" does not exist",
184 relation->schemaname, relation->relname);
186 elog(ERROR, "Relation \"%s\" does not exist",
193 * RangeVarGetCreationNamespace
194 * Given a RangeVar describing a to-be-created relation,
195 * choose which namespace to create it in.
197 * Note: calling this may result in a CommandCounterIncrement operation.
198 * That will happen on the first request for a temp table in any particular
199 * backend run; we will need to either create or clean out the temp schema.
202 RangeVarGetCreationNamespace(const RangeVar *newRelation)
207 * We check the catalog name and then ignore it.
209 if (newRelation->catalogname)
211 if (strcmp(newRelation->catalogname, DatabaseName) != 0)
212 elog(ERROR, "Cross-database references are not implemented");
215 if (newRelation->istemp)
217 /* TEMP tables are created in our backend-local temp namespace */
218 if (newRelation->schemaname)
219 elog(ERROR, "TEMP tables may not specify a namespace");
220 /* Initialize temp namespace if first time through */
221 if (!OidIsValid(myTempNamespace))
222 myTempNamespace = GetTempTableNamespace();
223 return myTempNamespace;
226 if (newRelation->schemaname)
228 /* use exact schema given */
229 namespaceId = GetSysCacheOid(NAMESPACENAME,
230 CStringGetDatum(newRelation->schemaname),
232 if (!OidIsValid(namespaceId))
233 elog(ERROR, "Namespace \"%s\" does not exist",
234 newRelation->schemaname);
238 /* use the default creation namespace */
239 recomputeNamespacePath();
240 namespaceId = defaultCreationNamespace;
241 if (!OidIsValid(namespaceId))
242 elog(ERROR, "No namespace has been selected to create in");
245 /* Note: callers will check for CREATE rights when appropriate */
252 * Try to resolve an unqualified relation name.
253 * Returns OID if relation found in search path, else InvalidOid.
256 RelnameGetRelid(const char *relname)
261 recomputeNamespacePath();
264 * If a TEMP-table namespace has been set up, it is implicitly first
265 * in the search path. We do not need to check USAGE permission.
267 if (OidIsValid(myTempNamespace))
269 relid = get_relname_relid(relname, myTempNamespace);
270 if (OidIsValid(relid))
275 * If system namespace is not in path, implicitly search it before path.
276 * We do not check USAGE permission.
278 if (!pathContainsSystemNamespace)
280 relid = get_relname_relid(relname, PG_CATALOG_NAMESPACE);
281 if (OidIsValid(relid))
286 * Else search the path
288 foreach(lptr, namespaceSearchPath)
290 Oid namespaceId = (Oid) lfirsti(lptr);
292 relid = get_relname_relid(relname, namespaceId);
293 if (OidIsValid(relid))
297 /* Not found in path */
303 * Determine whether a relation (identified by OID) is visible in the
304 * current search path. Visible means "would be found by searching
305 * for the unqualified relation name".
308 RelationIsVisible(Oid relid)
311 Form_pg_class relform;
315 recomputeNamespacePath();
317 reltup = SearchSysCache(RELOID,
318 ObjectIdGetDatum(relid),
320 if (!HeapTupleIsValid(reltup))
321 elog(ERROR, "Cache lookup failed for relation %u", relid);
322 relform = (Form_pg_class) GETSTRUCT(reltup);
325 * Quick check: if it ain't in the path at all, it ain't visible.
327 relnamespace = relform->relnamespace;
328 if (relnamespace != myTempNamespace &&
329 relnamespace != PG_CATALOG_NAMESPACE &&
330 !intMember(relnamespace, namespaceSearchPath))
335 * If it is in the path, it might still not be visible; it could be
336 * hidden by another relation of the same name earlier in the path.
337 * So we must do a slow check to see if this rel would be found by
340 char *relname = NameStr(relform->relname);
342 visible = (RelnameGetRelid(relname) == relid);
345 ReleaseSysCache(reltup);
353 * Try to resolve an unqualified datatype name.
354 * Returns OID if type found in search path, else InvalidOid.
356 * This is essentially the same as RelnameGetRelid, but we never search
357 * the TEMP table namespace --- there is no reason to refer to the types
358 * of temp tables, AFAICS.
361 TypenameGetTypid(const char *typname)
366 recomputeNamespacePath();
369 * If system namespace is not in path, implicitly search it before path
371 if (!pathContainsSystemNamespace)
373 typid = GetSysCacheOid(TYPENAMENSP,
374 PointerGetDatum(typname),
375 ObjectIdGetDatum(PG_CATALOG_NAMESPACE),
377 if (OidIsValid(typid))
382 * Else search the path
384 foreach(lptr, namespaceSearchPath)
386 Oid namespaceId = (Oid) lfirsti(lptr);
388 typid = GetSysCacheOid(TYPENAMENSP,
389 PointerGetDatum(typname),
390 ObjectIdGetDatum(namespaceId),
392 if (OidIsValid(typid))
396 /* Not found in path */
402 * Determine whether a type (identified by OID) is visible in the
403 * current search path. Visible means "would be found by searching
404 * for the unqualified type name".
407 TypeIsVisible(Oid typid)
410 Form_pg_type typform;
414 recomputeNamespacePath();
416 typtup = SearchSysCache(TYPEOID,
417 ObjectIdGetDatum(typid),
419 if (!HeapTupleIsValid(typtup))
420 elog(ERROR, "Cache lookup failed for type %u", typid);
421 typform = (Form_pg_type) GETSTRUCT(typtup);
424 * Quick check: if it ain't in the path at all, it ain't visible.
426 typnamespace = typform->typnamespace;
427 if (typnamespace != PG_CATALOG_NAMESPACE &&
428 !intMember(typnamespace, namespaceSearchPath))
433 * If it is in the path, it might still not be visible; it could be
434 * hidden by another type of the same name earlier in the path.
435 * So we must do a slow check to see if this type would be found by
438 char *typname = NameStr(typform->typname);
440 visible = (TypenameGetTypid(typname) == typid);
443 ReleaseSysCache(typtup);
450 * FuncnameGetCandidates
451 * Given a possibly-qualified function name and argument count,
452 * retrieve a list of the possible matches.
454 * If nargs is -1, we return all functions matching the given name,
455 * regardless of argument count.
457 * We search a single namespace if the function name is qualified, else
458 * all namespaces in the search path. The return list will never contain
459 * multiple entries with identical argument lists --- in the multiple-
460 * namespace case, we arrange for entries in earlier namespaces to mask
461 * identical entries in later namespaces.
464 FuncnameGetCandidates(List *names, int nargs)
466 FuncCandidateList resultList = NULL;
468 char *schemaname = NULL;
469 char *funcname = NULL;
474 /* deconstruct the name list */
475 switch (length(names))
478 funcname = strVal(lfirst(names));
481 schemaname = strVal(lfirst(names));
482 funcname = strVal(lsecond(names));
485 catalogname = strVal(lfirst(names));
486 schemaname = strVal(lsecond(names));
487 funcname = strVal(lfirst(lnext(lnext(names))));
489 * We check the catalog name and then ignore it.
491 if (strcmp(catalogname, DatabaseName) != 0)
492 elog(ERROR, "Cross-database references are not implemented");
495 elog(ERROR, "Improper qualified name (too many dotted names): %s",
496 NameListToString(names));
502 /* use exact schema given */
505 namespaceId = GetSysCacheOid(NAMESPACENAME,
506 CStringGetDatum(schemaname),
508 if (!OidIsValid(namespaceId))
509 elog(ERROR, "Namespace \"%s\" does not exist",
511 aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_USAGE);
512 if (aclresult != ACLCHECK_OK)
513 aclcheck_error(aclresult, schemaname);
517 /* flag to indicate we need namespace search */
518 namespaceId = InvalidOid;
519 recomputeNamespacePath();
522 /* Search syscache by name and (optionally) nargs only */
524 catlist = SearchSysCacheList(PROCNAMENSP, 2,
525 CStringGetDatum(funcname),
526 Int16GetDatum(nargs),
529 catlist = SearchSysCacheList(PROCNAMENSP, 1,
530 CStringGetDatum(funcname),
533 for (i = 0; i < catlist->n_members; i++)
535 HeapTuple proctup = &catlist->members[i]->tuple;
536 Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
538 FuncCandidateList newResult;
540 nargs = procform->pronargs;
542 if (OidIsValid(namespaceId))
544 /* Consider only procs in specified namespace */
545 if (procform->pronamespace != namespaceId)
547 /* No need to check args, they must all be different */
551 /* Consider only procs that are in the search path */
552 if (pathContainsSystemNamespace ||
553 !IsSystemNamespace(procform->pronamespace))
557 foreach(nsp, namespaceSearchPath)
560 if (procform->pronamespace == (Oid) lfirsti(nsp))
564 continue; /* proc is not in search path */
568 * Okay, it's in the search path, but does it have the same
569 * arguments as something we already accepted? If so, keep
570 * only the one that appears earlier in the search path.
572 * If we have an ordered list from SearchSysCacheList (the
573 * normal case), then any conflicting proc must immediately
574 * adjoin this one in the list, so we only need to look at
575 * the newest result item. If we have an unordered list,
576 * we have to scan the whole result list.
580 FuncCandidateList prevResult;
582 if (catlist->ordered)
584 if (nargs == resultList->nargs &&
585 memcmp(procform->proargtypes, resultList->args,
586 nargs * sizeof(Oid)) == 0)
587 prevResult = resultList;
593 for (prevResult = resultList;
595 prevResult = prevResult->next)
597 if (nargs == prevResult->nargs &&
598 memcmp(procform->proargtypes, prevResult->args,
599 nargs * sizeof(Oid)) == 0)
605 /* We have a match with a previous result */
606 Assert(pathpos != prevResult->pathpos);
607 if (pathpos > prevResult->pathpos)
608 continue; /* keep previous result */
609 /* replace previous result */
610 prevResult->pathpos = pathpos;
611 prevResult->oid = proctup->t_data->t_oid;
612 continue; /* args are same, of course */
618 * Okay to add it to result list
620 newResult = (FuncCandidateList)
621 palloc(sizeof(struct _FuncCandidateList) - sizeof(Oid)
622 + nargs * sizeof(Oid));
623 newResult->pathpos = pathpos;
624 newResult->oid = proctup->t_data->t_oid;
625 newResult->nargs = nargs;
626 memcpy(newResult->args, procform->proargtypes, nargs * sizeof(Oid));
628 newResult->next = resultList;
629 resultList = newResult;
632 ReleaseSysCacheList(catlist);
639 * Determine whether a function (identified by OID) is visible in the
640 * current search path. Visible means "would be found by searching
641 * for the unqualified function name with exact argument matches".
644 FunctionIsVisible(Oid funcid)
647 Form_pg_proc procform;
651 recomputeNamespacePath();
653 proctup = SearchSysCache(PROCOID,
654 ObjectIdGetDatum(funcid),
656 if (!HeapTupleIsValid(proctup))
657 elog(ERROR, "Cache lookup failed for procedure %u", funcid);
658 procform = (Form_pg_proc) GETSTRUCT(proctup);
661 * Quick check: if it ain't in the path at all, it ain't visible.
663 pronamespace = procform->pronamespace;
664 if (pronamespace != PG_CATALOG_NAMESPACE &&
665 !intMember(pronamespace, namespaceSearchPath))
670 * If it is in the path, it might still not be visible; it could be
671 * hidden by another proc of the same name and arguments earlier
672 * in the path. So we must do a slow check to see if this is the
673 * same proc that would be found by FuncnameGetCandidates.
675 char *proname = NameStr(procform->proname);
676 int nargs = procform->pronargs;
677 FuncCandidateList clist;
681 clist = FuncnameGetCandidates(makeList1(makeString(proname)), nargs);
683 for (; clist; clist = clist->next)
685 if (memcmp(clist->args, procform->proargtypes,
686 nargs * sizeof(Oid)) == 0)
688 /* Found the expected entry; is it the right proc? */
689 visible = (clist->oid == funcid);
695 ReleaseSysCache(proctup);
702 * OpernameGetCandidates
703 * Given a possibly-qualified operator name and operator kind,
704 * retrieve a list of the possible matches.
706 * If oprkind is '\0', we return all operators matching the given name,
707 * regardless of arguments.
709 * We search a single namespace if the operator name is qualified, else
710 * all namespaces in the search path. The return list will never contain
711 * multiple entries with identical argument lists --- in the multiple-
712 * namespace case, we arrange for entries in earlier namespaces to mask
713 * identical entries in later namespaces.
715 * The returned items always have two args[] entries --- one or the other
716 * will be InvalidOid for a prefix or postfix oprkind. nargs is 2, too.
719 OpernameGetCandidates(List *names, char oprkind)
721 FuncCandidateList resultList = NULL;
723 char *schemaname = NULL;
724 char *opername = NULL;
729 /* deconstruct the name list */
730 switch (length(names))
733 opername = strVal(lfirst(names));
736 schemaname = strVal(lfirst(names));
737 opername = strVal(lsecond(names));
740 catalogname = strVal(lfirst(names));
741 schemaname = strVal(lsecond(names));
742 opername = strVal(lfirst(lnext(lnext(names))));
744 * We check the catalog name and then ignore it.
746 if (strcmp(catalogname, DatabaseName) != 0)
747 elog(ERROR, "Cross-database references are not implemented");
750 elog(ERROR, "Improper qualified name (too many dotted names): %s",
751 NameListToString(names));
757 /* use exact schema given */
760 namespaceId = GetSysCacheOid(NAMESPACENAME,
761 CStringGetDatum(schemaname),
763 if (!OidIsValid(namespaceId))
764 elog(ERROR, "Namespace \"%s\" does not exist",
766 aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_USAGE);
767 if (aclresult != ACLCHECK_OK)
768 aclcheck_error(aclresult, schemaname);
772 /* flag to indicate we need namespace search */
773 namespaceId = InvalidOid;
774 recomputeNamespacePath();
777 /* Search syscache by name only */
778 catlist = SearchSysCacheList(OPERNAMENSP, 1,
779 CStringGetDatum(opername),
782 for (i = 0; i < catlist->n_members; i++)
784 HeapTuple opertup = &catlist->members[i]->tuple;
785 Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
787 FuncCandidateList newResult;
789 /* Ignore operators of wrong kind, if specific kind requested */
790 if (oprkind && operform->oprkind != oprkind)
793 if (OidIsValid(namespaceId))
795 /* Consider only opers in specified namespace */
796 if (operform->oprnamespace != namespaceId)
798 /* No need to check args, they must all be different */
802 /* Consider only opers that are in the search path */
803 if (pathContainsSystemNamespace ||
804 !IsSystemNamespace(operform->oprnamespace))
808 foreach(nsp, namespaceSearchPath)
811 if (operform->oprnamespace == (Oid) lfirsti(nsp))
815 continue; /* oper is not in search path */
819 * Okay, it's in the search path, but does it have the same
820 * arguments as something we already accepted? If so, keep
821 * only the one that appears earlier in the search path.
823 * If we have an ordered list from SearchSysCacheList (the
824 * normal case), then any conflicting oper must immediately
825 * adjoin this one in the list, so we only need to look at
826 * the newest result item. If we have an unordered list,
827 * we have to scan the whole result list.
831 FuncCandidateList prevResult;
833 if (catlist->ordered)
835 if (operform->oprleft == resultList->args[0] &&
836 operform->oprright == resultList->args[1])
837 prevResult = resultList;
843 for (prevResult = resultList;
845 prevResult = prevResult->next)
847 if (operform->oprleft == prevResult->args[0] &&
848 operform->oprright == prevResult->args[1])
854 /* We have a match with a previous result */
855 Assert(pathpos != prevResult->pathpos);
856 if (pathpos > prevResult->pathpos)
857 continue; /* keep previous result */
858 /* replace previous result */
859 prevResult->pathpos = pathpos;
860 prevResult->oid = opertup->t_data->t_oid;
861 continue; /* args are same, of course */
867 * Okay to add it to result list
869 newResult = (FuncCandidateList)
870 palloc(sizeof(struct _FuncCandidateList) + sizeof(Oid));
871 newResult->pathpos = pathpos;
872 newResult->oid = opertup->t_data->t_oid;
873 newResult->nargs = 2;
874 newResult->args[0] = operform->oprleft;
875 newResult->args[1] = operform->oprright;
876 newResult->next = resultList;
877 resultList = newResult;
880 ReleaseSysCacheList(catlist);
887 * Determine whether an operator (identified by OID) is visible in the
888 * current search path. Visible means "would be found by searching
889 * for the unqualified operator name with exact argument matches".
892 OperatorIsVisible(Oid oprid)
895 Form_pg_operator oprform;
899 recomputeNamespacePath();
901 oprtup = SearchSysCache(OPEROID,
902 ObjectIdGetDatum(oprid),
904 if (!HeapTupleIsValid(oprtup))
905 elog(ERROR, "Cache lookup failed for operator %u", oprid);
906 oprform = (Form_pg_operator) GETSTRUCT(oprtup);
909 * Quick check: if it ain't in the path at all, it ain't visible.
911 oprnamespace = oprform->oprnamespace;
912 if (oprnamespace != PG_CATALOG_NAMESPACE &&
913 !intMember(oprnamespace, namespaceSearchPath))
918 * If it is in the path, it might still not be visible; it could be
919 * hidden by another operator of the same name and arguments earlier
920 * in the path. So we must do a slow check to see if this is the
921 * same operator that would be found by OpernameGetCandidates.
923 char *oprname = NameStr(oprform->oprname);
924 FuncCandidateList clist;
928 clist = OpernameGetCandidates(makeList1(makeString(oprname)),
931 for (; clist; clist = clist->next)
933 if (clist->args[0] == oprform->oprleft &&
934 clist->args[1] == oprform->oprright)
936 /* Found the expected entry; is it the right op? */
937 visible = (clist->oid == oprid);
943 ReleaseSysCache(oprtup);
950 * OpclassGetCandidates
951 * Given an index access method OID, retrieve a list of all the
952 * opclasses for that AM that are visible in the search path.
954 * NOTE: the opcname_tmp field in the returned structs should not be used
955 * by callers, because it points at syscache entries that we release at
956 * the end of this routine. If any callers needed the name information,
957 * we could pstrdup() the names ... but at present it'd be wasteful.
960 OpclassGetCandidates(Oid amid)
962 OpclassCandidateList resultList = NULL;
966 recomputeNamespacePath();
968 /* Search syscache by AM OID only */
969 catlist = SearchSysCacheList(CLAAMNAMENSP, 1,
970 ObjectIdGetDatum(amid),
973 for (i = 0; i < catlist->n_members; i++)
975 HeapTuple opctup = &catlist->members[i]->tuple;
976 Form_pg_opclass opcform = (Form_pg_opclass) GETSTRUCT(opctup);
978 OpclassCandidateList newResult;
980 /* Consider only opclasses that are in the search path */
981 if (pathContainsSystemNamespace ||
982 !IsSystemNamespace(opcform->opcnamespace))
986 foreach(nsp, namespaceSearchPath)
989 if (opcform->opcnamespace == (Oid) lfirsti(nsp))
993 continue; /* opclass is not in search path */
997 * Okay, it's in the search path, but does it have the same name
998 * as something we already accepted? If so, keep
999 * only the one that appears earlier in the search path.
1001 * If we have an ordered list from SearchSysCacheList (the
1002 * normal case), then any conflicting opclass must immediately
1003 * adjoin this one in the list, so we only need to look at
1004 * the newest result item. If we have an unordered list,
1005 * we have to scan the whole result list.
1009 OpclassCandidateList prevResult;
1011 if (catlist->ordered)
1013 if (strcmp(NameStr(opcform->opcname),
1014 resultList->opcname_tmp) == 0)
1015 prevResult = resultList;
1021 for (prevResult = resultList;
1023 prevResult = prevResult->next)
1025 if (strcmp(NameStr(opcform->opcname),
1026 prevResult->opcname_tmp) == 0)
1032 /* We have a match with a previous result */
1033 Assert(pathpos != prevResult->pathpos);
1034 if (pathpos > prevResult->pathpos)
1035 continue; /* keep previous result */
1036 /* replace previous result */
1037 prevResult->opcname_tmp = NameStr(opcform->opcname);
1038 prevResult->pathpos = pathpos;
1039 prevResult->oid = opctup->t_data->t_oid;
1040 prevResult->opcintype = opcform->opcintype;
1041 prevResult->opcdefault = opcform->opcdefault;
1042 prevResult->opckeytype = opcform->opckeytype;
1048 * Okay to add it to result list
1050 newResult = (OpclassCandidateList)
1051 palloc(sizeof(struct _OpclassCandidateList));
1052 newResult->opcname_tmp = NameStr(opcform->opcname);
1053 newResult->pathpos = pathpos;
1054 newResult->oid = opctup->t_data->t_oid;
1055 newResult->opcintype = opcform->opcintype;
1056 newResult->opcdefault = opcform->opcdefault;
1057 newResult->opckeytype = opcform->opckeytype;
1058 newResult->next = resultList;
1059 resultList = newResult;
1062 ReleaseSysCacheList(catlist);
1068 * OpclassnameGetOpcid
1069 * Try to resolve an unqualified index opclass name.
1070 * Returns OID if opclass found in search path, else InvalidOid.
1072 * This is essentially the same as TypenameGetTypid, but we have to have
1073 * an extra argument for the index AM OID.
1076 OpclassnameGetOpcid(Oid amid, const char *opcname)
1081 recomputeNamespacePath();
1084 * If system namespace is not in path, implicitly search it before path
1086 if (!pathContainsSystemNamespace)
1088 opcid = GetSysCacheOid(CLAAMNAMENSP,
1089 ObjectIdGetDatum(amid),
1090 PointerGetDatum(opcname),
1091 ObjectIdGetDatum(PG_CATALOG_NAMESPACE),
1093 if (OidIsValid(opcid))
1098 * Else search the path
1100 foreach(lptr, namespaceSearchPath)
1102 Oid namespaceId = (Oid) lfirsti(lptr);
1104 opcid = GetSysCacheOid(CLAAMNAMENSP,
1105 ObjectIdGetDatum(amid),
1106 PointerGetDatum(opcname),
1107 ObjectIdGetDatum(namespaceId),
1109 if (OidIsValid(opcid))
1113 /* Not found in path */
1119 * Determine whether an opclass (identified by OID) is visible in the
1120 * current search path. Visible means "would be found by searching
1121 * for the unqualified opclass name".
1124 OpclassIsVisible(Oid opcid)
1127 Form_pg_opclass opcform;
1131 recomputeNamespacePath();
1133 opctup = SearchSysCache(CLAOID,
1134 ObjectIdGetDatum(opcid),
1136 if (!HeapTupleIsValid(opctup))
1137 elog(ERROR, "Cache lookup failed for opclass %u", opcid);
1138 opcform = (Form_pg_opclass) GETSTRUCT(opctup);
1141 * Quick check: if it ain't in the path at all, it ain't visible.
1143 opcnamespace = opcform->opcnamespace;
1144 if (opcnamespace != PG_CATALOG_NAMESPACE &&
1145 !intMember(opcnamespace, namespaceSearchPath))
1150 * If it is in the path, it might still not be visible; it could be
1151 * hidden by another opclass of the same name earlier in the path.
1152 * So we must do a slow check to see if this opclass would be found by
1153 * OpclassnameGetOpcid.
1155 char *opcname = NameStr(opcform->opcname);
1157 visible = (OpclassnameGetOpcid(opcform->opcamid, opcname) == opcid);
1160 ReleaseSysCache(opctup);
1167 * QualifiedNameGetCreationNamespace
1168 * Given a possibly-qualified name for an object (in List-of-Values
1169 * format), determine what namespace the object should be created in.
1170 * Also extract and return the object name (last component of list).
1172 * This is *not* used for tables. Hence, the TEMP table namespace is
1173 * never selected as the creation target.
1176 QualifiedNameGetCreationNamespace(List *names, char **objname_p)
1179 char *schemaname = NULL;
1180 char *objname = NULL;
1183 /* deconstruct the name list */
1184 switch (length(names))
1187 objname = strVal(lfirst(names));
1190 schemaname = strVal(lfirst(names));
1191 objname = strVal(lsecond(names));
1194 catalogname = strVal(lfirst(names));
1195 schemaname = strVal(lsecond(names));
1196 objname = strVal(lfirst(lnext(lnext(names))));
1198 * We check the catalog name and then ignore it.
1200 if (strcmp(catalogname, DatabaseName) != 0)
1201 elog(ERROR, "Cross-database references are not implemented");
1204 elog(ERROR, "Improper qualified name (too many dotted names): %s",
1205 NameListToString(names));
1211 /* use exact schema given */
1212 namespaceId = GetSysCacheOid(NAMESPACENAME,
1213 CStringGetDatum(schemaname),
1215 if (!OidIsValid(namespaceId))
1216 elog(ERROR, "Namespace \"%s\" does not exist",
1221 /* use the default creation namespace */
1222 recomputeNamespacePath();
1223 namespaceId = defaultCreationNamespace;
1224 if (!OidIsValid(namespaceId))
1225 elog(ERROR, "No namespace has been selected to create in");
1228 /* Note: callers will check for CREATE rights when appropriate */
1230 *objname_p = objname;
1235 * makeRangeVarFromNameList
1236 * Utility routine to convert a qualified-name list into RangeVar form.
1239 makeRangeVarFromNameList(List *names)
1241 RangeVar *rel = makeRangeVar(NULL, NULL);
1243 switch (length(names))
1246 rel->relname = strVal(lfirst(names));
1249 rel->schemaname = strVal(lfirst(names));
1250 rel->relname = strVal(lsecond(names));
1253 rel->catalogname = strVal(lfirst(names));
1254 rel->schemaname = strVal(lsecond(names));
1255 rel->relname = strVal(lfirst(lnext(lnext(names))));
1258 elog(ERROR, "Improper relation name (too many dotted names)");
1267 * Utility routine to convert a qualified-name list into a string.
1268 * Used primarily to form error messages.
1271 NameListToString(List *names)
1273 StringInfoData string;
1276 initStringInfo(&string);
1281 appendStringInfoChar(&string, '.');
1282 appendStringInfo(&string, "%s", strVal(lfirst(l)));
1289 * isTempNamespace - is the given namespace my temporary-table namespace?
1292 isTempNamespace(Oid namespaceId)
1294 if (OidIsValid(myTempNamespace) && myTempNamespace == namespaceId)
1301 * recomputeNamespacePath - recompute path derived variables if needed.
1304 recomputeNamespacePath(void)
1306 Oid userId = GetUserId();
1312 MemoryContext oldcxt;
1315 * Do nothing if path is already valid.
1317 if (namespaceSearchPathValid && namespaceUser == userId)
1320 /* Need a modifiable copy of namespace_search_path string */
1321 rawname = pstrdup(namespace_search_path);
1323 /* Parse string into list of identifiers */
1324 if (!SplitIdentifierString(rawname, ',', &namelist))
1326 /* syntax error in name list */
1327 /* this should not happen if GUC checked check_search_path */
1328 elog(ERROR, "recomputeNamespacePath: invalid list syntax");
1332 * Convert the list of names to a list of OIDs. If any names are not
1333 * recognizable or we don't have read access, just leave them out of
1334 * the list. (We can't raise an error, since the search_path setting
1335 * has already been accepted.)
1338 foreach(l, namelist)
1340 char *curname = (char *) lfirst(l);
1343 if (strcmp(curname, "$user") == 0)
1345 /* $user --- substitute namespace matching user name, if any */
1348 tuple = SearchSysCache(SHADOWSYSID,
1349 ObjectIdGetDatum(userId),
1351 if (HeapTupleIsValid(tuple))
1355 uname = NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename);
1356 namespaceId = GetSysCacheOid(NAMESPACENAME,
1357 CStringGetDatum(uname),
1359 ReleaseSysCache(tuple);
1360 if (OidIsValid(namespaceId) &&
1361 pg_namespace_aclcheck(namespaceId, userId,
1362 ACL_USAGE) == ACLCHECK_OK)
1363 oidlist = lappendi(oidlist, namespaceId);
1368 /* normal namespace reference */
1369 namespaceId = GetSysCacheOid(NAMESPACENAME,
1370 CStringGetDatum(curname),
1372 if (OidIsValid(namespaceId) &&
1373 pg_namespace_aclcheck(namespaceId, userId,
1374 ACL_USAGE) == ACLCHECK_OK)
1375 oidlist = lappendi(oidlist, namespaceId);
1380 * Now that we've successfully built the new list of namespace OIDs,
1381 * save it in permanent storage.
1383 oldcxt = MemoryContextSwitchTo(TopMemoryContext);
1384 newpath = listCopy(oidlist);
1385 MemoryContextSwitchTo(oldcxt);
1387 /* Now safe to assign to state variable. */
1388 freeList(namespaceSearchPath);
1389 namespaceSearchPath = newpath;
1392 * Update info derived from search path.
1394 pathContainsSystemNamespace = intMember(PG_CATALOG_NAMESPACE,
1395 namespaceSearchPath);
1397 if (namespaceSearchPath == NIL)
1398 defaultCreationNamespace = InvalidOid;
1400 defaultCreationNamespace = (Oid) lfirsti(namespaceSearchPath);
1402 /* Mark the path valid. */
1403 namespaceSearchPathValid = true;
1404 namespaceUser = userId;
1413 * GetTempTableNamespace
1414 * Initialize temp table namespace on first use in a particular backend
1417 GetTempTableNamespace(void)
1419 char namespaceName[NAMEDATALEN];
1423 * First, do permission check to see if we are authorized to make
1424 * temp tables. We use a nonstandard error message here since
1425 * "databasename: permission denied" might be a tad cryptic.
1427 * Note we apply the check to the session user, not the currently
1428 * active userid, since we are not going to change our minds about
1429 * temp table availability during the session.
1431 if (pg_database_aclcheck(MyDatabaseId, GetSessionUserId(),
1432 ACL_CREATE_TEMP) != ACLCHECK_OK)
1433 elog(ERROR, "%s: not authorized to create temp tables",
1436 snprintf(namespaceName, NAMEDATALEN, "pg_temp_%d", MyBackendId);
1438 namespaceId = GetSysCacheOid(NAMESPACENAME,
1439 CStringGetDatum(namespaceName),
1441 if (!OidIsValid(namespaceId))
1444 * First use of this temp namespace in this database; create it.
1445 * The temp namespaces are always owned by the superuser. We
1446 * leave their permissions at default --- i.e., no access except to
1447 * superuser --- to ensure that unprivileged users can't peek
1448 * at other backends' temp tables. This works because the places
1449 * that access the temp namespace for my own backend skip permissions
1452 namespaceId = NamespaceCreate(namespaceName, BOOTSTRAP_USESYSID);
1453 /* Advance command counter to make namespace visible */
1454 CommandCounterIncrement();
1459 * If the namespace already exists, clean it out (in case the
1460 * former owner crashed without doing so).
1462 RemoveTempRelations(namespaceId);
1466 * Register exit callback to clean out temp tables at backend shutdown.
1468 on_shmem_exit(RemoveTempRelationsCallback, 0);
1474 * Remove all relations in the specified temp namespace.
1476 * This is called at backend shutdown (if we made any temp relations).
1477 * It is also called when we begin using a pre-existing temp namespace,
1478 * in order to clean out any relations that might have been created by
1479 * a crashed backend.
1482 RemoveTempRelations(Oid tempNamespaceId)
1485 List *constraintList;
1488 /* Get a list of relations to delete */
1489 tempRelList = FindTempRelations(tempNamespaceId);
1491 if (tempRelList == NIL)
1492 return; /* nothing to do */
1494 /* If more than one, sort them to respect any deletion-order constraints */
1495 if (length(tempRelList) > 1)
1497 constraintList = FindDeletionConstraints(tempRelList);
1498 if (constraintList != NIL)
1499 tempRelList = TopoSortRels(tempRelList, constraintList);
1502 /* Scan the list and delete all entries */
1503 foreach(lptr, tempRelList)
1505 Oid reloid = (Oid) lfirsti(lptr);
1507 heap_drop_with_catalog(reloid, true);
1509 * Advance cmd counter to make catalog changes visible, in case
1510 * a later entry depends on this one.
1512 CommandCounterIncrement();
1517 * Find all relations in the specified temp namespace.
1519 * Returns a list of relation OIDs.
1522 FindTempRelations(Oid tempNamespaceId)
1524 List *tempRelList = NIL;
1531 * Scan pg_class to find all the relations in the target namespace.
1532 * Ignore indexes, though, on the assumption that they'll go away
1533 * when their tables are deleted.
1535 ScanKeyEntryInitialize(&key, 0x0,
1536 Anum_pg_class_relnamespace,
1538 ObjectIdGetDatum(tempNamespaceId));
1540 pgclass = heap_openr(RelationRelationName, AccessShareLock);
1541 scan = heap_beginscan(pgclass, false, SnapshotNow, 1, &key);
1543 while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
1545 switch (((Form_pg_class) GETSTRUCT(tuple))->relkind)
1547 case RELKIND_RELATION:
1548 case RELKIND_SEQUENCE:
1550 tempRelList = lconsi(tuple->t_data->t_oid, tempRelList);
1558 heap_close(pgclass, AccessShareLock);
1564 * Find deletion-order constraints involving the given relation OIDs.
1566 * Returns a list of DelConstraint objects.
1569 FindDeletionConstraints(List *relOids)
1571 List *constraintList = NIL;
1572 Relation inheritsrel;
1577 * Scan pg_inherits to find parents and children that are in the list.
1579 inheritsrel = heap_openr(InheritsRelationName, AccessShareLock);
1580 scan = heap_beginscan(inheritsrel, 0, SnapshotNow, 0, NULL);
1582 while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
1584 Oid inhrelid = ((Form_pg_inherits) GETSTRUCT(tuple))->inhrelid;
1585 Oid inhparent = ((Form_pg_inherits) GETSTRUCT(tuple))->inhparent;
1587 if (intMember(inhrelid, relOids) && intMember(inhparent, relOids))
1589 DelConstraint *item;
1591 item = (DelConstraint *) palloc(sizeof(DelConstraint));
1592 item->referencer = inhrelid;
1593 item->referencee = inhparent;
1594 constraintList = lcons(item, constraintList);
1599 heap_close(inheritsrel, AccessShareLock);
1601 return constraintList;
1605 * TopoSortRels -- topological sort of a list of rels to delete
1607 * This is a lot simpler and slower than, for example, the topological sort
1608 * algorithm shown in Knuth's Volume 1. However, we are not likely to be
1609 * working with more than a few constraints, so the apparent slowness of the
1610 * algorithm won't really matter.
1613 TopoSortRels(List *relOids, List *constraintList)
1615 int queue_size = length(relOids);
1617 int *beforeConstraints;
1618 DelConstraint **afterConstraints;
1619 List *resultList = NIL;
1626 /* Allocate workspace */
1627 rels = (Oid *) palloc(queue_size * sizeof(Oid));
1628 beforeConstraints = (int *) palloc(queue_size * sizeof(int));
1629 afterConstraints = (DelConstraint **)
1630 palloc(queue_size * sizeof(DelConstraint*));
1632 /* Build an array of the target relation OIDs */
1634 foreach(lptr, relOids)
1636 rels[i++] = (Oid) lfirsti(lptr);
1640 * Scan the constraints, and for each rel in the array, generate a
1641 * count of the number of constraints that say it must be before
1642 * something else, plus a list of the constraints that say it must be
1643 * after something else. The count for the j'th rel is stored in
1644 * beforeConstraints[j], and the head of its list in
1645 * afterConstraints[j]. Each constraint stores its list link in
1646 * its link field (note any constraint will be in just one list).
1647 * The array index for the before-rel of each constraint is
1648 * remembered in the constraint's pred field.
1650 MemSet(beforeConstraints, 0, queue_size * sizeof(int));
1651 MemSet(afterConstraints, 0, queue_size * sizeof(DelConstraint*));
1652 foreach(lptr, constraintList)
1654 DelConstraint *constraint = (DelConstraint *) lfirst(lptr);
1657 /* Find the referencer rel in the array */
1658 rel = constraint->referencer;
1659 for (j = queue_size; --j >= 0;)
1664 Assert(j >= 0); /* should have found a match */
1665 /* Find the referencee rel in the array */
1666 rel = constraint->referencee;
1667 for (k = queue_size; --k >= 0;)
1672 Assert(k >= 0); /* should have found a match */
1673 beforeConstraints[j]++; /* referencer must come before */
1674 /* add this constraint to list of after-constraints for referencee */
1675 constraint->pred = j;
1676 constraint->link = afterConstraints[k];
1677 afterConstraints[k] = constraint;
1679 /*--------------------
1680 * Now scan the rels array backwards. At each step, output the
1681 * last rel that has no remaining before-constraints, and decrease
1682 * the beforeConstraints count of each of the rels it was constrained
1683 * against. (This is the right order since we are building the result
1684 * list back-to-front.)
1685 * i = counter for number of rels left to output
1686 * j = search index for rels[]
1687 * dc = temp for scanning constraint list for rel j
1688 * last = last valid index in rels (avoid redundant searches)
1689 *--------------------
1691 last = queue_size - 1;
1692 for (i = queue_size; --i >= 0;)
1696 /* Find next candidate to output */
1697 while (rels[last] == InvalidOid)
1699 for (j = last; j >= 0; j--)
1701 if (rels[j] != InvalidOid && beforeConstraints[j] == 0)
1704 /* If no available candidate, topological sort fails */
1706 elog(ERROR, "TopoSortRels: failed to find a workable deletion ordering");
1707 /* Output candidate, and mark it done by zeroing rels[] entry */
1708 resultList = lconsi(rels[j], resultList);
1709 rels[j] = InvalidOid;
1710 /* Update beforeConstraints counts of its predecessors */
1711 for (dc = afterConstraints[j]; dc; dc = dc->link)
1712 beforeConstraints[dc->pred]--;
1720 * Callback to remove temp relations at backend exit.
1723 RemoveTempRelationsCallback(void)
1725 if (OidIsValid(myTempNamespace)) /* should always be true */
1727 /* Need to ensure we have a usable transaction. */
1728 AbortOutOfAnyTransaction();
1729 StartTransactionCommand();
1731 RemoveTempRelations(myTempNamespace);
1733 CommitTransactionCommand();
1739 * Routines for handling the GUC variable 'search_path'.
1742 /* parse_hook: is proposed value valid? */
1744 check_search_path(const char *proposed)
1750 /* Need a modifiable copy of string */
1751 rawname = pstrdup(proposed);
1753 /* Parse string into list of identifiers */
1754 if (!SplitIdentifierString(rawname, ',', &namelist))
1756 /* syntax error in name list */
1763 * If we aren't inside a transaction, we cannot do database access so
1764 * cannot verify the individual names. Must accept the list on faith.
1765 * (This case can happen, for example, when the postmaster reads a
1766 * search_path setting from postgresql.conf.)
1768 if (!IsTransactionState())
1776 * Verify that all the names are either valid namespace names or "$user".
1777 * We do not require $user to correspond to a valid namespace.
1778 * We do not check for USAGE rights, either; should we?
1780 foreach(l, namelist)
1782 char *curname = (char *) lfirst(l);
1784 if (strcmp(curname, "$user") == 0)
1786 if (!SearchSysCacheExists(NAMESPACENAME,
1787 CStringGetDatum(curname),
1802 /* assign_hook: do extra actions needed when assigning to search_path */
1804 assign_search_path(const char *newval)
1807 * We mark the path as needing recomputation, but don't do anything until
1808 * it's needed. This avoids trying to do database access during GUC
1811 namespaceSearchPathValid = false;
1815 * InitializeSearchPath: initialize module during InitPostgres.
1817 * This is called after we are up enough to be able to do catalog lookups.
1820 InitializeSearchPath(void)
1822 if (IsBootstrapProcessingMode())
1825 * In bootstrap mode, the search path must be 'pg_catalog' so that
1826 * tables are created in the proper namespace; ignore the GUC setting.
1828 MemoryContext oldcxt;
1830 oldcxt = MemoryContextSwitchTo(TopMemoryContext);
1831 namespaceSearchPath = makeListi1(PG_CATALOG_NAMESPACE);
1832 MemoryContextSwitchTo(oldcxt);
1833 pathContainsSystemNamespace = true;
1834 defaultCreationNamespace = PG_CATALOG_NAMESPACE;
1835 namespaceSearchPathValid = true;
1836 namespaceUser = GetUserId();
1841 * In normal mode, arrange for a callback on any syscache invalidation
1842 * of pg_namespace rows.
1844 CacheRegisterSyscacheCallback(NAMESPACEOID,
1852 * Syscache inval callback function
1855 NamespaceCallback(Datum arg, Oid relid)
1857 /* Force search path to be recomputed on next use */
1858 namespaceSearchPathValid = false;
1862 * Fetch the active search path, expressed as a List of OIDs.
1864 * NB: caller must treat the list as read-only!
1867 fetch_search_path(void)
1869 recomputeNamespacePath();
1870 return namespaceSearchPath;