Skip to content

Commit 0332d65

Browse files
committed
Implement partial-key searching of syscaches, per recent suggestion
to pghackers. Use this to do searching for ambiguous functions --- it will get more uses soon.
1 parent 707cf12 commit 0332d65

File tree

7 files changed

+891
-341
lines changed

7 files changed

+891
-341
lines changed

src/backend/catalog/namespace.c

Lines changed: 171 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* Portions Copyright (c) 1994, Regents of the University of California
1414
*
1515
* IDENTIFICATION
16-
* $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.5 2002/04/01 03:34:25 tgl Exp $
16+
* $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.6 2002/04/06 06:59:21 tgl Exp $
1717
*
1818
*-------------------------------------------------------------------------
1919
*/
@@ -26,13 +26,15 @@
2626
#include "catalog/namespace.h"
2727
#include "catalog/pg_inherits.h"
2828
#include "catalog/pg_namespace.h"
29+
#include "catalog/pg_proc.h"
2930
#include "catalog/pg_shadow.h"
3031
#include "miscadmin.h"
3132
#include "nodes/makefuncs.h"
3233
#include "storage/backendid.h"
3334
#include "utils/builtins.h"
3435
#include "utils/fmgroids.h"
3536
#include "utils/guc.h"
37+
#include "utils/catcache.h"
3638
#include "utils/lsyscache.h"
3739
#include "utils/syscache.h"
3840

@@ -301,6 +303,174 @@ TypenameGetTypid(const char *typname)
301303
return InvalidOid;
302304
}
303305

306+
/*
307+
* FuncnameGetCandidates
308+
* Given a possibly-qualified function name and argument count,
309+
* retrieve a list of the possible matches.
310+
*
311+
* We search a single namespace if the function name is qualified, else
312+
* all namespaces in the search path. The return list will never contain
313+
* multiple entries with identical argument types --- in the multiple-
314+
* namespace case, we arrange for entries in earlier namespaces to mask
315+
* identical entries in later namespaces.
316+
*/
317+
FuncCandidateList
318+
FuncnameGetCandidates(List *names, int nargs)
319+
{
320+
FuncCandidateList resultList = NULL;
321+
char *catalogname;
322+
char *schemaname = NULL;
323+
char *funcname = NULL;
324+
Oid namespaceId;
325+
CatCList *catlist;
326+
int i;
327+
328+
/* deconstruct the name list */
329+
switch (length(names))
330+
{
331+
case 1:
332+
funcname = strVal(lfirst(names));
333+
break;
334+
case 2:
335+
schemaname = strVal(lfirst(names));
336+
funcname = strVal(lsecond(names));
337+
break;
338+
case 3:
339+
catalogname = strVal(lfirst(names));
340+
schemaname = strVal(lsecond(names));
341+
funcname = strVal(lfirst(lnext(lnext(names))));
342+
/*
343+
* We check the catalog name and then ignore it.
344+
*/
345+
if (strcmp(catalogname, DatabaseName) != 0)
346+
elog(ERROR, "Cross-database references are not implemented");
347+
break;
348+
default:
349+
elog(ERROR, "Improper qualified name (too many dotted names)");
350+
break;
351+
}
352+
353+
if (schemaname)
354+
{
355+
/* use exact schema given */
356+
namespaceId = GetSysCacheOid(NAMESPACENAME,
357+
CStringGetDatum(schemaname),
358+
0, 0, 0);
359+
if (!OidIsValid(namespaceId))
360+
elog(ERROR, "Namespace \"%s\" does not exist",
361+
schemaname);
362+
}
363+
else
364+
{
365+
/* flag to indicate we need namespace search */
366+
namespaceId = InvalidOid;
367+
}
368+
369+
/* Search syscache by name and nargs only */
370+
catlist = SearchSysCacheList(PROCNAME, 2,
371+
CStringGetDatum(funcname),
372+
Int16GetDatum(nargs),
373+
0, 0);
374+
375+
for (i = 0; i < catlist->n_members; i++)
376+
{
377+
HeapTuple proctup = &catlist->members[i]->tuple;
378+
Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
379+
int pathpos = 0;
380+
FuncCandidateList newResult;
381+
382+
if (OidIsValid(namespaceId))
383+
{
384+
/* Consider only procs in specified namespace */
385+
if (procform->pronamespace != namespaceId)
386+
continue;
387+
/* No need to check args, they must all be different */
388+
}
389+
else
390+
{
391+
/* Consider only procs that are in the search path */
392+
if (pathContainsSystemNamespace ||
393+
procform->pronamespace != PG_CATALOG_NAMESPACE)
394+
{
395+
List *nsp;
396+
397+
foreach(nsp, namespaceSearchPath)
398+
{
399+
pathpos++;
400+
if (procform->pronamespace == (Oid) lfirsti(nsp))
401+
break;
402+
}
403+
if (nsp == NIL)
404+
continue; /* proc is not in search path */
405+
}
406+
407+
/*
408+
* Okay, it's in the search path, but does it have the same
409+
* arguments as something we already accepted? If so, keep
410+
* only the one that appears earlier in the search path.
411+
*
412+
* If we have an ordered list from SearchSysCacheList (the
413+
* normal case), then any conflicting proc must immediately
414+
* adjoin this one in the list, so we only need to look at
415+
* the newest result item. If we have an unordered list,
416+
* we have to scan the whole result list.
417+
*/
418+
if (resultList)
419+
{
420+
FuncCandidateList prevResult;
421+
422+
if (catlist->ordered)
423+
{
424+
if (memcmp(procform->proargtypes, resultList->args,
425+
nargs * sizeof(Oid)) == 0)
426+
prevResult = resultList;
427+
else
428+
prevResult = NULL;
429+
}
430+
else
431+
{
432+
for (prevResult = resultList;
433+
prevResult;
434+
prevResult = prevResult->next)
435+
{
436+
if (memcmp(procform->proargtypes, prevResult->args,
437+
nargs * sizeof(Oid)) == 0)
438+
break;
439+
}
440+
}
441+
if (prevResult)
442+
{
443+
/* We have a match with a previous result */
444+
Assert(pathpos != prevResult->pathpos);
445+
if (pathpos > prevResult->pathpos)
446+
continue; /* keep previous result */
447+
/* replace previous result */
448+
prevResult->pathpos = pathpos;
449+
prevResult->oid = proctup->t_data->t_oid;
450+
continue; /* args are same, of course */
451+
}
452+
}
453+
}
454+
455+
/*
456+
* Okay to add it to result list
457+
*/
458+
newResult = (FuncCandidateList)
459+
palloc(sizeof(struct _FuncCandidateList) - sizeof(Oid)
460+
+ nargs * sizeof(Oid));
461+
newResult->pathpos = pathpos;
462+
newResult->oid = proctup->t_data->t_oid;
463+
memcpy(newResult->args, procform->proargtypes, nargs * sizeof(Oid));
464+
465+
newResult->next = resultList;
466+
resultList = newResult;
467+
}
468+
469+
ReleaseSysCacheList(catlist);
470+
471+
return resultList;
472+
}
473+
304474
/*
305475
* QualifiedNameGetCreationNamespace
306476
* Given a possibly-qualified name for an object (in List-of-Values

0 commit comments

Comments
 (0)