Commit 0332d65a authored by Tom Lane's avatar Tom Lane

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.
parent 707cf12f
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.5 2002/04/01 03:34:25 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.6 2002/04/06 06:59:21 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "catalog/namespace.h" #include "catalog/namespace.h"
#include "catalog/pg_inherits.h" #include "catalog/pg_inherits.h"
#include "catalog/pg_namespace.h" #include "catalog/pg_namespace.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_shadow.h" #include "catalog/pg_shadow.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "nodes/makefuncs.h" #include "nodes/makefuncs.h"
...@@ -33,6 +34,7 @@ ...@@ -33,6 +34,7 @@
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/fmgroids.h" #include "utils/fmgroids.h"
#include "utils/guc.h" #include "utils/guc.h"
#include "utils/catcache.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
#include "utils/syscache.h" #include "utils/syscache.h"
...@@ -301,6 +303,174 @@ TypenameGetTypid(const char *typname) ...@@ -301,6 +303,174 @@ TypenameGetTypid(const char *typname)
return InvalidOid; return InvalidOid;
} }
/*
* FuncnameGetCandidates
* Given a possibly-qualified function name and argument count,
* retrieve a list of the possible matches.
*
* We search a single namespace if the function 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.
*/
FuncCandidateList
FuncnameGetCandidates(List *names, int nargs)
{
FuncCandidateList resultList = NULL;
char *catalogname;
char *schemaname = NULL;
char *funcname = NULL;
Oid namespaceId;
CatCList *catlist;
int i;
/* deconstruct the name list */
switch (length(names))
{
case 1:
funcname = strVal(lfirst(names));
break;
case 2:
schemaname = strVal(lfirst(names));
funcname = strVal(lsecond(names));
break;
case 3:
catalogname = strVal(lfirst(names));
schemaname = strVal(lsecond(names));
funcname = 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 and nargs only */
catlist = SearchSysCacheList(PROCNAME, 2,
CStringGetDatum(funcname),
Int16GetDatum(nargs),
0, 0);
for (i = 0; i < catlist->n_members; i++)
{
HeapTuple proctup = &catlist->members[i]->tuple;
Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
int pathpos = 0;
FuncCandidateList newResult;
if (OidIsValid(namespaceId))
{
/* Consider only procs in specified namespace */
if (procform->pronamespace != namespaceId)
continue;
/* No need to check args, they must all be different */
}
else
{
/* Consider only procs that are in the search path */
if (pathContainsSystemNamespace ||
procform->pronamespace != PG_CATALOG_NAMESPACE)
{
List *nsp;
foreach(nsp, namespaceSearchPath)
{
pathpos++;
if (procform->pronamespace == (Oid) lfirsti(nsp))
break;
}
if (nsp == NIL)
continue; /* proc 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 proc 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 (memcmp(procform->proargtypes, resultList->args,
nargs * sizeof(Oid)) == 0)
prevResult = resultList;
else
prevResult = NULL;
}
else
{
for (prevResult = resultList;
prevResult;
prevResult = prevResult->next)
{
if (memcmp(procform->proargtypes, prevResult->args,
nargs * sizeof(Oid)) == 0)
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 = proctup->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)
+ nargs * sizeof(Oid));
newResult->pathpos = pathpos;
newResult->oid = proctup->t_data->t_oid;
memcpy(newResult->args, procform->proargtypes, nargs * sizeof(Oid));
newResult->next = resultList;
resultList = newResult;
}
ReleaseSysCacheList(catlist);
return resultList;
}
/* /*
* QualifiedNameGetCreationNamespace * QualifiedNameGetCreationNamespace
* Given a possibly-qualified name for an object (in List-of-Values * Given a possibly-qualified name for an object (in List-of-Values
......
This diff is collapsed.
This diff is collapsed.
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.73 2002/04/05 00:31:31 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.74 2002/04/06 06:59:23 tgl Exp $
* *
* NOTES * NOTES
* These routines allow the parser/planner/executor to perform * These routines allow the parser/planner/executor to perform
...@@ -626,3 +626,18 @@ SysCacheGetAttr(int cacheId, HeapTuple tup, ...@@ -626,3 +626,18 @@ SysCacheGetAttr(int cacheId, HeapTuple tup,
SysCache[cacheId]->cc_tupdesc, SysCache[cacheId]->cc_tupdesc,
isNull); isNull);
} }
/*
* List-search interface
*/
struct catclist *
SearchSysCacheList(int cacheId, int nkeys,
Datum key1, Datum key2, Datum key3, Datum key4)
{
if (cacheId < 0 || cacheId >= SysCacheSize ||
! PointerIsValid(SysCache[cacheId]))
elog(ERROR, "SearchSysCacheList: Bad cache id %d", cacheId);
return SearchCatCacheList(SysCache[cacheId], nkeys,
key1, key2, key3, key4);
}
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: namespace.h,v 1.5 2002/04/01 03:34:27 tgl Exp $ * $Id: namespace.h,v 1.6 2002/04/06 06:59:24 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -17,6 +17,22 @@ ...@@ -17,6 +17,22 @@
#include "nodes/primnodes.h" #include "nodes/primnodes.h"
/*
* This structure holds a list of possible functions or operators
* found by namespace lookup. Each function/operator is identified
* by OID and by argument types; the list must be pruned by type
* resolution rules that are embodied in the parser, not here.
* The number of arguments is assumed to be known a priori.
*/
typedef struct _FuncCandidateList
{
struct _FuncCandidateList *next;
int pathpos; /* for internal use of namespace lookup */
Oid oid; /* the function or operator's OID */
Oid args[1]; /* arg types --- VARIABLE LENGTH ARRAY */
} *FuncCandidateList; /* VARIABLE LENGTH STRUCT */
extern Oid RangeVarGetRelid(const RangeVar *relation, bool failOK); extern Oid RangeVarGetRelid(const RangeVar *relation, bool failOK);
extern Oid RangeVarGetCreationNamespace(const RangeVar *newRelation); extern Oid RangeVarGetCreationNamespace(const RangeVar *newRelation);
...@@ -25,6 +41,8 @@ extern Oid RelnameGetRelid(const char *relname); ...@@ -25,6 +41,8 @@ extern Oid RelnameGetRelid(const char *relname);
extern Oid TypenameGetTypid(const char *typname); extern Oid TypenameGetTypid(const char *typname);
extern FuncCandidateList FuncnameGetCandidates(List *names, int nargs);
extern Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p); extern Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p);
extern RangeVar *makeRangeVarFromNameList(List *names); extern RangeVar *makeRangeVarFromNameList(List *names);
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: catcache.h,v 1.41 2002/03/26 19:16:56 tgl Exp $ * $Id: catcache.h,v 1.42 2002/04/06 06:59:24 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
/* /*
* struct catctup: individual tuple in the cache. * struct catctup: individual tuple in the cache.
* struct catclist: list of tuples matching a partial key.
* struct catcache: information for managing a cache. * struct catcache: information for managing a cache.
* struct catcacheheader: information for managing all the caches. * struct catcacheheader: information for managing all the caches.
*/ */
...@@ -36,7 +37,7 @@ typedef struct catcache ...@@ -36,7 +37,7 @@ typedef struct catcache
const char *cc_relname; /* name of relation the tuples come from */ const char *cc_relname; /* name of relation the tuples come from */
const char *cc_indname; /* name of index matching cache keys */ const char *cc_indname; /* name of index matching cache keys */
Oid cc_reloid; /* OID of relation the tuples come from */ Oid cc_reloid; /* OID of relation the tuples come from */
bool cc_relisshared; /* is relation shared? */ bool cc_relisshared; /* is relation shared across databases? */
TupleDesc cc_tupdesc; /* tuple descriptor (copied from reldesc) */ TupleDesc cc_tupdesc; /* tuple descriptor (copied from reldesc) */
int cc_reloidattr; /* AttrNumber of relation OID attr, or 0 */ int cc_reloidattr; /* AttrNumber of relation OID attr, or 0 */
int cc_ntup; /* # of tuples currently in this cache */ int cc_ntup; /* # of tuples currently in this cache */
...@@ -46,6 +47,7 @@ typedef struct catcache ...@@ -46,6 +47,7 @@ typedef struct catcache
PGFunction cc_hashfunc[4]; /* hash function to use for each key */ PGFunction cc_hashfunc[4]; /* hash function to use for each key */
ScanKeyData cc_skey[4]; /* precomputed key info for heap scans */ ScanKeyData cc_skey[4]; /* precomputed key info for heap scans */
bool cc_isname[4]; /* flag key columns that are NAMEs */ bool cc_isname[4]; /* flag key columns that are NAMEs */
Dllist cc_lists; /* list of CatCList structs */
#ifdef CATCACHE_STATS #ifdef CATCACHE_STATS
long cc_searches; /* total # searches against this cache */ long cc_searches; /* total # searches against this cache */
long cc_hits; /* # of matches against existing entry */ long cc_hits; /* # of matches against existing entry */
...@@ -57,6 +59,8 @@ typedef struct catcache ...@@ -57,6 +59,8 @@ typedef struct catcache
*/ */
long cc_invals; /* # of entries invalidated from cache */ long cc_invals; /* # of entries invalidated from cache */
long cc_discards; /* # of entries discarded due to overflow */ long cc_discards; /* # of entries discarded due to overflow */
long cc_lsearches; /* total # list-searches */
long cc_lhits; /* # of matches against existing lists */
#endif #endif
Dllist cc_bucket[1]; /* hash buckets --- VARIABLE LENGTH ARRAY */ Dllist cc_bucket[1]; /* hash buckets --- VARIABLE LENGTH ARRAY */
} CatCache; /* VARIABLE LENGTH STRUCT */ } CatCache; /* VARIABLE LENGTH STRUCT */
...@@ -64,15 +68,25 @@ typedef struct catcache ...@@ -64,15 +68,25 @@ typedef struct catcache
typedef struct catctup typedef struct catctup
{ {
int ct_magic; /* for Assert checks */ int ct_magic; /* for identifying CatCTup entries */
#define CT_MAGIC 0x57261502 #define CT_MAGIC 0x57261502
CatCache *my_cache; /* link to owning catcache */ CatCache *my_cache; /* link to owning catcache */
/* /*
* Each tuple in a cache is a member of two lists: one lists all the * Each tuple in a cache is a member of two Dllists: one lists all the
* elements in all the caches in LRU order, and the other lists just * elements in all the caches in LRU order, and the other lists just
* the elements in one hashbucket of one cache, also in LRU order. * the elements in one hashbucket of one cache, also in LRU order.
* *
* The tuple may also be a member of at most one CatCList. (If a single
* catcache is list-searched with varying numbers of keys, we may have
* to make multiple entries for the same tuple because of this
* restriction. Currently, that's not expected to be common, so we
* accept the potential inefficiency.)
*/
Dlelem lrulist_elem; /* list member of global LRU list */
Dlelem cache_elem; /* list member of per-bucket list */
struct catclist *c_list; /* containing catclist, or NULL if none */
/*
* A tuple marked "dead" must not be returned by subsequent searches. * A tuple marked "dead" must not be returned by subsequent searches.
* However, it won't be physically deleted from the cache until its * However, it won't be physically deleted from the cache until its
* refcount goes to zero. * refcount goes to zero.
...@@ -82,8 +96,6 @@ typedef struct catctup ...@@ -82,8 +96,6 @@ typedef struct catctup
* so far as avoiding catalog searches is concerned. Management of * so far as avoiding catalog searches is concerned. Management of
* positive and negative entries is identical. * positive and negative entries is identical.
*/ */
Dlelem lrulist_elem; /* list member of global LRU list */
Dlelem cache_elem; /* list member of per-bucket list */
int refcount; /* number of active references */ int refcount; /* number of active references */
bool dead; /* dead but not yet removed? */ bool dead; /* dead but not yet removed? */
bool negative; /* negative cache entry? */ bool negative; /* negative cache entry? */
...@@ -92,6 +104,47 @@ typedef struct catctup ...@@ -92,6 +104,47 @@ typedef struct catctup
} CatCTup; } CatCTup;
typedef struct catclist
{
int cl_magic; /* for identifying CatCList entries */
#define CL_MAGIC 0x52765103
CatCache *my_cache; /* link to owning catcache */
/*
* A CatCList describes the result of a partial search, ie, a search
* using only the first K key columns of an N-key cache. We form the
* keys used into a tuple (with other attributes NULL) to represent
* the stored key set. The CatCList object contains links to cache
* entries for all the table rows satisfying the partial key. (Note:
* none of these will be negative cache entries.)
*
* A CatCList is only a member of a per-cache list; we do not do
* separate LRU management for CatCLists. Instead, a CatCList is
* dropped from the cache as soon as any one of its member tuples
* ages out due to tuple-level LRU management.
*
* A list marked "dead" must not be returned by subsequent searches.
* However, it won't be physically deleted from the cache until its
* refcount goes to zero. (Its member tuples must have refcounts at
* least as large, so they won't go away either.)
*
* If "ordered" is true then the member tuples appear in the order of
* the cache's underlying index. This will be true in normal operation,
* but might not be true during bootstrap or recovery operations.
* (namespace.c is able to save some cycles when it is true.)
*/
Dlelem cache_elem; /* list member of per-catcache list */
int refcount; /* number of active references */
bool dead; /* dead but not yet removed? */
bool ordered; /* members listed in index order? */
short nkeys; /* number of lookup keys specified */
uint32 hash_value; /* hash value for lookup keys */
HeapTupleData tuple; /* header for tuple holding keys */
int n_members; /* number of member tuples */
CatCTup *members[1]; /* members --- VARIABLE LENGTH ARRAY */
} CatCList; /* VARIABLE LENGTH STRUCT */
typedef struct catcacheheader typedef struct catcacheheader
{ {
CatCache *ch_caches; /* head of list of CatCache structs */ CatCache *ch_caches; /* head of list of CatCache structs */
...@@ -117,6 +170,11 @@ extern HeapTuple SearchCatCache(CatCache *cache, ...@@ -117,6 +170,11 @@ extern HeapTuple SearchCatCache(CatCache *cache,
Datum v3, Datum v4); Datum v3, Datum v4);
extern void ReleaseCatCache(HeapTuple tuple); extern void ReleaseCatCache(HeapTuple tuple);
extern CatCList *SearchCatCacheList(CatCache *cache, int nkeys,
Datum v1, Datum v2,
Datum v3, Datum v4);
extern void ReleaseCatCacheList(CatCList *list);
extern void ResetCatalogCaches(void); extern void ResetCatalogCaches(void);
extern void CatalogCacheFlushRelation(Oid relId); extern void CatalogCacheFlushRelation(Oid relId);
extern void CatalogCacheIdInvalidate(int cacheId, uint32 hashValue, extern void CatalogCacheIdInvalidate(int cacheId, uint32 hashValue,
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: syscache.h,v 1.41 2002/03/29 19:06:26 tgl Exp $ * $Id: syscache.h,v 1.42 2002/04/06 06:59:25 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -79,4 +79,9 @@ extern Oid GetSysCacheOid(int cacheId, ...@@ -79,4 +79,9 @@ extern Oid GetSysCacheOid(int cacheId,
extern Datum SysCacheGetAttr(int cacheId, HeapTuple tup, extern Datum SysCacheGetAttr(int cacheId, HeapTuple tup,
AttrNumber attributeNumber, bool *isNull); AttrNumber attributeNumber, bool *isNull);
/* list-search interface. Users of this must import catcache.h too */
extern struct catclist *SearchSysCacheList(int cacheId, int nkeys,
Datum key1, Datum key2, Datum key3, Datum key4);
#define ReleaseSysCacheList(x) ReleaseCatCacheList(x)
#endif /* SYSCACHE_H */ #endif /* SYSCACHE_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment