aboutsummaryrefslogtreecommitdiff
path: root/src/backend/catalog/namespace.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/catalog/namespace.c')
-rw-r--r--src/backend/catalog/namespace.c176
1 files changed, 175 insertions, 1 deletions
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 77b6ceb78db..15fdb01ed31 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -13,7 +13,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.9 2002/04/15 22:33:21 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.10 2002/04/16 23:08:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -27,6 +27,7 @@
#include "catalog/namespace.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_namespace.h"
+#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_shadow.h"
#include "lib/stringinfo.h"
@@ -479,6 +480,179 @@ FuncnameGetCandidates(List *names, int nargs)
}
/*
+ * OpernameGetCandidates
+ * Given a possibly-qualified operator name and operator kind,
+ * retrieve a list of the possible matches.
+ *
+ * We search a single namespace if the operator name is qualified, else
+ * all namespaces in the search path. The return list will never contain
+ * multiple entries with identical argument types --- in the multiple-
+ * namespace case, we arrange for entries in earlier namespaces to mask
+ * identical entries in later namespaces.
+ *
+ * The returned items always have two args[] entries --- one or the other
+ * will be InvalidOid for a prefix or postfix oprkind.
+ */
+FuncCandidateList
+OpernameGetCandidates(List *names, char oprkind)
+{
+ FuncCandidateList resultList = NULL;
+ char *catalogname;
+ char *schemaname = NULL;
+ char *opername = NULL;
+ Oid namespaceId;
+ CatCList *catlist;
+ int i;
+
+ /* deconstruct the name list */
+ switch (length(names))
+ {
+ case 1:
+ opername = strVal(lfirst(names));
+ break;
+ case 2:
+ schemaname = strVal(lfirst(names));
+ opername = strVal(lsecond(names));
+ break;
+ case 3:
+ catalogname = strVal(lfirst(names));
+ schemaname = strVal(lsecond(names));
+ opername = strVal(lfirst(lnext(lnext(names))));
+ /*
+ * We check the catalog name and then ignore it.
+ */
+ if (strcmp(catalogname, DatabaseName) != 0)
+ elog(ERROR, "Cross-database references are not implemented");
+ break;
+ default:
+ elog(ERROR, "Improper qualified name (too many dotted names)");
+ break;
+ }
+
+ if (schemaname)
+ {
+ /* use exact schema given */
+ namespaceId = GetSysCacheOid(NAMESPACENAME,
+ CStringGetDatum(schemaname),
+ 0, 0, 0);
+ if (!OidIsValid(namespaceId))
+ elog(ERROR, "Namespace \"%s\" does not exist",
+ schemaname);
+ }
+ else
+ {
+ /* flag to indicate we need namespace search */
+ namespaceId = InvalidOid;
+ }
+
+ /* Search syscache by name only */
+ catlist = SearchSysCacheList(OPERNAMENSP, 1,
+ CStringGetDatum(opername),
+ 0, 0, 0);
+
+ for (i = 0; i < catlist->n_members; i++)
+ {
+ HeapTuple opertup = &catlist->members[i]->tuple;
+ Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
+ int pathpos = 0;
+ FuncCandidateList newResult;
+
+ /* Ignore operators of wrong kind */
+ if (operform->oprkind != oprkind)
+ continue;
+
+ if (OidIsValid(namespaceId))
+ {
+ /* Consider only opers in specified namespace */
+ if (operform->oprnamespace != namespaceId)
+ continue;
+ /* No need to check args, they must all be different */
+ }
+ else
+ {
+ /* Consider only opers that are in the search path */
+ if (pathContainsSystemNamespace ||
+ !IsSystemNamespace(operform->oprnamespace))
+ {
+ List *nsp;
+
+ foreach(nsp, namespaceSearchPath)
+ {
+ pathpos++;
+ if (operform->oprnamespace == (Oid) lfirsti(nsp))
+ break;
+ }
+ if (nsp == NIL)
+ continue; /* oper is not in search path */
+ }
+
+ /*
+ * Okay, it's in the search path, but does it have the same
+ * arguments as something we already accepted? If so, keep
+ * only the one that appears earlier in the search path.
+ *
+ * If we have an ordered list from SearchSysCacheList (the
+ * normal case), then any conflicting oper must immediately
+ * adjoin this one in the list, so we only need to look at
+ * the newest result item. If we have an unordered list,
+ * we have to scan the whole result list.
+ */
+ if (resultList)
+ {
+ FuncCandidateList prevResult;
+
+ if (catlist->ordered)
+ {
+ if (operform->oprleft == resultList->args[0] &&
+ operform->oprright == resultList->args[1])
+ prevResult = resultList;
+ else
+ prevResult = NULL;
+ }
+ else
+ {
+ for (prevResult = resultList;
+ prevResult;
+ prevResult = prevResult->next)
+ {
+ if (operform->oprleft == prevResult->args[0] &&
+ operform->oprright == prevResult->args[1])
+ break;
+ }
+ }
+ if (prevResult)
+ {
+ /* We have a match with a previous result */
+ Assert(pathpos != prevResult->pathpos);
+ if (pathpos > prevResult->pathpos)
+ continue; /* keep previous result */
+ /* replace previous result */
+ prevResult->pathpos = pathpos;
+ prevResult->oid = opertup->t_data->t_oid;
+ continue; /* args are same, of course */
+ }
+ }
+ }
+
+ /*
+ * Okay to add it to result list
+ */
+ newResult = (FuncCandidateList)
+ palloc(sizeof(struct _FuncCandidateList) + sizeof(Oid));
+ newResult->pathpos = pathpos;
+ newResult->oid = opertup->t_data->t_oid;
+ newResult->args[0] = operform->oprleft;
+ newResult->args[1] = operform->oprright;
+ newResult->next = resultList;
+ resultList = newResult;
+ }
+
+ ReleaseSysCacheList(catlist);
+
+ return resultList;
+}
+
+/*
* QualifiedNameGetCreationNamespace
* Given a possibly-qualified name for an object (in List-of-Values
* format), determine what namespace the object should be created in.