mirror of
https://github.com/postgres/postgres.git
synced 2025-06-10 00:01:28 -04:00
Fix plancache so that any required replanning is done with the same
search_path that was active when the plan was first made. To do this, improve namespace.c to support a stack of "override" search path settings (we must have a stack since nested replan events are entirely possible). This facility replaces the "special namespace" hack formerly used by CREATE SCHEMA, and should be able to support per-function search path settings as well.
This commit is contained in:
parent
4c35ec53a9
commit
547b6e537a
@ -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
|
||||||
* $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.92 2007/02/14 01:58:56 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.93 2007/03/23 19:53:51 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -46,16 +46,15 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* The namespace search path is a possibly-empty list of namespace OIDs.
|
* The namespace search path is a possibly-empty list of namespace OIDs.
|
||||||
* In addition to the explicit list, several implicitly-searched namespaces
|
* In addition to the explicit list, implicitly-searched namespaces
|
||||||
* may be included:
|
* may be included:
|
||||||
*
|
*
|
||||||
* 1. If a "special" namespace has been set by PushSpecialNamespace, it is
|
* 1. If a TEMP table namespace has been initialized in this session, it
|
||||||
* always searched first. (This is a hack for CREATE SCHEMA.)
|
* is implicitly searched first. (The only time this doesn't happen is
|
||||||
|
* when we are obeying an override search path spec that says not to use the
|
||||||
|
* temp namespace, or the temp namespace is included in the explicit list.)
|
||||||
*
|
*
|
||||||
* 2. If a TEMP table namespace has been initialized in this session, it
|
* 2. The system catalog namespace is always searched. If the system
|
||||||
* is always searched just after any special namespace.
|
|
||||||
*
|
|
||||||
* 3. The system catalog namespace is always searched. If the system
|
|
||||||
* namespace is present in the explicit path then it will be searched in
|
* namespace is present in the explicit path then it will be searched in
|
||||||
* the specified order; otherwise it will be searched after TEMP tables and
|
* the specified order; otherwise it will be searched after TEMP tables and
|
||||||
* *before* the explicit list. (It might seem that the system namespace
|
* *before* the explicit list. (It might seem that the system namespace
|
||||||
@ -63,43 +62,67 @@
|
|||||||
* SQL99. Also, this provides a way to search the system namespace first
|
* SQL99. Also, this provides a way to search the system namespace first
|
||||||
* without thereby making it the default creation target namespace.)
|
* without thereby making it the default creation target namespace.)
|
||||||
*
|
*
|
||||||
* The default creation target namespace is normally equal to the first
|
* The default creation target namespace is always the first element of the
|
||||||
* element of the explicit list, but is the "special" namespace when one
|
* explicit list. If the explicit list is empty, there is no default target.
|
||||||
* has been set. If the explicit list is empty and there is no special
|
|
||||||
* namespace, there is no default target.
|
|
||||||
*
|
*
|
||||||
* In bootstrap mode, the search path is set equal to 'pg_catalog', so that
|
* In bootstrap mode, the search path is set equal to 'pg_catalog', so that
|
||||||
* the system namespace is the only one searched or inserted into.
|
* the system namespace is the only one searched or inserted into.
|
||||||
* The initdb script is also careful to set search_path to 'pg_catalog' for
|
* initdb is also careful to set search_path to 'pg_catalog' for its
|
||||||
* its post-bootstrap standalone backend runs. Otherwise the default search
|
* post-bootstrap standalone backend runs. Otherwise the default search
|
||||||
* path is determined by GUC. The factory default path contains the PUBLIC
|
* path is determined by GUC. The factory default path contains the PUBLIC
|
||||||
* namespace (if it exists), preceded by the user's personal namespace
|
* namespace (if it exists), preceded by the user's personal namespace
|
||||||
* (if one exists).
|
* (if one exists).
|
||||||
*
|
*
|
||||||
* If namespaceSearchPathValid is false, then namespaceSearchPath (and other
|
* We support a stack of "override" search path settings for use within
|
||||||
|
* specific sections of backend code. namespace_search_path is ignored
|
||||||
|
* whenever the override stack is nonempty. activeSearchPath is always
|
||||||
|
* the actually active path; it points either to the search list of the
|
||||||
|
* topmost stack entry, or to baseSearchPath which is the list derived
|
||||||
|
* from namespace_search_path.
|
||||||
|
*
|
||||||
|
* If baseSearchPathValid is false, then baseSearchPath (and other
|
||||||
* derived variables) need to be recomputed from namespace_search_path.
|
* derived variables) need to be recomputed from namespace_search_path.
|
||||||
* We mark it invalid upon an assignment to namespace_search_path or receipt
|
* We mark it invalid upon an assignment to namespace_search_path or receipt
|
||||||
* of a syscache invalidation event for pg_namespace. The recomputation
|
* of a syscache invalidation event for pg_namespace. The recomputation
|
||||||
* is done during the next lookup attempt.
|
* is done during the next non-overridden lookup attempt. Note that an
|
||||||
|
* override spec is never subject to recomputation.
|
||||||
*
|
*
|
||||||
* Any namespaces mentioned in namespace_search_path that are not readable
|
* Any namespaces mentioned in namespace_search_path that are not readable
|
||||||
* by the current user ID are simply left out of namespaceSearchPath; so
|
* by the current user ID are simply left out of baseSearchPath; so
|
||||||
* we have to be willing to recompute the path when current userid changes.
|
* we have to be willing to recompute the path when current userid changes.
|
||||||
* namespaceUser is the userid the path has been computed for.
|
* namespaceUser is the userid the path has been computed for.
|
||||||
|
*
|
||||||
|
* Note: all data pointed to by these List variables is in TopMemoryContext.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static List *namespaceSearchPath = NIL;
|
/* These variables define the actually active state: */
|
||||||
|
|
||||||
|
static List *activeSearchPath = NIL;
|
||||||
|
|
||||||
|
/* default place to create stuff; if InvalidOid, no default */
|
||||||
|
static Oid activeCreationNamespace = InvalidOid;
|
||||||
|
|
||||||
|
/* These variables are the values last derived from namespace_search_path: */
|
||||||
|
|
||||||
|
static List *baseSearchPath = NIL;
|
||||||
|
|
||||||
|
static Oid baseCreationNamespace = InvalidOid;
|
||||||
|
|
||||||
static Oid namespaceUser = InvalidOid;
|
static Oid namespaceUser = InvalidOid;
|
||||||
|
|
||||||
/* default place to create stuff; if InvalidOid, no default */
|
/* The above three values are valid only if baseSearchPathValid */
|
||||||
static Oid defaultCreationNamespace = InvalidOid;
|
static bool baseSearchPathValid = true;
|
||||||
|
|
||||||
/* first explicit member of list; usually same as defaultCreationNamespace */
|
/* Override requests are remembered in a stack of OverrideStackEntry structs */
|
||||||
static Oid firstExplicitNamespace = InvalidOid;
|
|
||||||
|
|
||||||
/* The above four values are valid only if namespaceSearchPathValid */
|
typedef struct
|
||||||
static bool namespaceSearchPathValid = true;
|
{
|
||||||
|
List *searchPath; /* the desired search path */
|
||||||
|
Oid creationNamespace; /* the desired creation namespace */
|
||||||
|
int nestLevel; /* subtransaction nesting level */
|
||||||
|
} OverrideStackEntry;
|
||||||
|
|
||||||
|
static List *overrideStack = NIL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* myTempNamespace is InvalidOid until and unless a TEMP namespace is set up
|
* myTempNamespace is InvalidOid until and unless a TEMP namespace is set up
|
||||||
@ -118,13 +141,7 @@ static Oid myTempNamespace = InvalidOid;
|
|||||||
static SubTransactionId myTempNamespaceSubID = InvalidSubTransactionId;
|
static SubTransactionId myTempNamespaceSubID = InvalidSubTransactionId;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* "Special" namespace for CREATE SCHEMA. If set, it's the first search
|
* This is the user's textual search path specification --- it's the value
|
||||||
* path element, and also the default creation namespace.
|
|
||||||
*/
|
|
||||||
static Oid mySpecialNamespace = InvalidOid;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is the text equivalent of the search path --- it's the value
|
|
||||||
* of the GUC variable 'search_path'.
|
* of the GUC variable 'search_path'.
|
||||||
*/
|
*/
|
||||||
char *namespace_search_path = NULL;
|
char *namespace_search_path = NULL;
|
||||||
@ -260,7 +277,7 @@ RangeVarGetCreationNamespace(const RangeVar *newRelation)
|
|||||||
{
|
{
|
||||||
/* use the default creation namespace */
|
/* use the default creation namespace */
|
||||||
recomputeNamespacePath();
|
recomputeNamespacePath();
|
||||||
namespaceId = defaultCreationNamespace;
|
namespaceId = activeCreationNamespace;
|
||||||
if (!OidIsValid(namespaceId))
|
if (!OidIsValid(namespaceId))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_UNDEFINED_SCHEMA),
|
(errcode(ERRCODE_UNDEFINED_SCHEMA),
|
||||||
@ -285,7 +302,7 @@ RelnameGetRelid(const char *relname)
|
|||||||
|
|
||||||
recomputeNamespacePath();
|
recomputeNamespacePath();
|
||||||
|
|
||||||
foreach(l, namespaceSearchPath)
|
foreach(l, activeSearchPath)
|
||||||
{
|
{
|
||||||
Oid namespaceId = lfirst_oid(l);
|
Oid namespaceId = lfirst_oid(l);
|
||||||
|
|
||||||
@ -329,7 +346,7 @@ RelationIsVisible(Oid relid)
|
|||||||
*/
|
*/
|
||||||
relnamespace = relform->relnamespace;
|
relnamespace = relform->relnamespace;
|
||||||
if (relnamespace != PG_CATALOG_NAMESPACE &&
|
if (relnamespace != PG_CATALOG_NAMESPACE &&
|
||||||
!list_member_oid(namespaceSearchPath, relnamespace))
|
!list_member_oid(activeSearchPath, relnamespace))
|
||||||
visible = false;
|
visible = false;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -342,7 +359,7 @@ RelationIsVisible(Oid relid)
|
|||||||
ListCell *l;
|
ListCell *l;
|
||||||
|
|
||||||
visible = false;
|
visible = false;
|
||||||
foreach(l, namespaceSearchPath)
|
foreach(l, activeSearchPath)
|
||||||
{
|
{
|
||||||
Oid namespaceId = lfirst_oid(l);
|
Oid namespaceId = lfirst_oid(l);
|
||||||
|
|
||||||
@ -381,7 +398,7 @@ TypenameGetTypid(const char *typname)
|
|||||||
|
|
||||||
recomputeNamespacePath();
|
recomputeNamespacePath();
|
||||||
|
|
||||||
foreach(l, namespaceSearchPath)
|
foreach(l, activeSearchPath)
|
||||||
{
|
{
|
||||||
Oid namespaceId = lfirst_oid(l);
|
Oid namespaceId = lfirst_oid(l);
|
||||||
|
|
||||||
@ -427,7 +444,7 @@ TypeIsVisible(Oid typid)
|
|||||||
*/
|
*/
|
||||||
typnamespace = typform->typnamespace;
|
typnamespace = typform->typnamespace;
|
||||||
if (typnamespace != PG_CATALOG_NAMESPACE &&
|
if (typnamespace != PG_CATALOG_NAMESPACE &&
|
||||||
!list_member_oid(namespaceSearchPath, typnamespace))
|
!list_member_oid(activeSearchPath, typnamespace))
|
||||||
visible = false;
|
visible = false;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -440,7 +457,7 @@ TypeIsVisible(Oid typid)
|
|||||||
ListCell *l;
|
ListCell *l;
|
||||||
|
|
||||||
visible = false;
|
visible = false;
|
||||||
foreach(l, namespaceSearchPath)
|
foreach(l, activeSearchPath)
|
||||||
{
|
{
|
||||||
Oid namespaceId = lfirst_oid(l);
|
Oid namespaceId = lfirst_oid(l);
|
||||||
|
|
||||||
@ -535,7 +552,7 @@ FuncnameGetCandidates(List *names, int nargs)
|
|||||||
/* Consider only procs that are in the search path */
|
/* Consider only procs that are in the search path */
|
||||||
ListCell *nsp;
|
ListCell *nsp;
|
||||||
|
|
||||||
foreach(nsp, namespaceSearchPath)
|
foreach(nsp, activeSearchPath)
|
||||||
{
|
{
|
||||||
if (procform->pronamespace == lfirst_oid(nsp))
|
if (procform->pronamespace == lfirst_oid(nsp))
|
||||||
break;
|
break;
|
||||||
@ -647,7 +664,7 @@ FunctionIsVisible(Oid funcid)
|
|||||||
*/
|
*/
|
||||||
pronamespace = procform->pronamespace;
|
pronamespace = procform->pronamespace;
|
||||||
if (pronamespace != PG_CATALOG_NAMESPACE &&
|
if (pronamespace != PG_CATALOG_NAMESPACE &&
|
||||||
!list_member_oid(namespaceSearchPath, pronamespace))
|
!list_member_oid(activeSearchPath, pronamespace))
|
||||||
visible = false;
|
visible = false;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -748,7 +765,7 @@ OpernameGetOprid(List *names, Oid oprleft, Oid oprright)
|
|||||||
*/
|
*/
|
||||||
recomputeNamespacePath();
|
recomputeNamespacePath();
|
||||||
|
|
||||||
foreach(l, namespaceSearchPath)
|
foreach(l, activeSearchPath)
|
||||||
{
|
{
|
||||||
Oid namespaceId = lfirst_oid(l);
|
Oid namespaceId = lfirst_oid(l);
|
||||||
int i;
|
int i;
|
||||||
@ -858,7 +875,7 @@ OpernameGetCandidates(List *names, char oprkind)
|
|||||||
/* Consider only opers that are in the search path */
|
/* Consider only opers that are in the search path */
|
||||||
ListCell *nsp;
|
ListCell *nsp;
|
||||||
|
|
||||||
foreach(nsp, namespaceSearchPath)
|
foreach(nsp, activeSearchPath)
|
||||||
{
|
{
|
||||||
if (operform->oprnamespace == lfirst_oid(nsp))
|
if (operform->oprnamespace == lfirst_oid(nsp))
|
||||||
break;
|
break;
|
||||||
@ -965,7 +982,7 @@ OperatorIsVisible(Oid oprid)
|
|||||||
*/
|
*/
|
||||||
oprnamespace = oprform->oprnamespace;
|
oprnamespace = oprform->oprnamespace;
|
||||||
if (oprnamespace != PG_CATALOG_NAMESPACE &&
|
if (oprnamespace != PG_CATALOG_NAMESPACE &&
|
||||||
!list_member_oid(namespaceSearchPath, oprnamespace))
|
!list_member_oid(activeSearchPath, oprnamespace))
|
||||||
visible = false;
|
visible = false;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1004,7 +1021,7 @@ OpclassnameGetOpcid(Oid amid, const char *opcname)
|
|||||||
|
|
||||||
recomputeNamespacePath();
|
recomputeNamespacePath();
|
||||||
|
|
||||||
foreach(l, namespaceSearchPath)
|
foreach(l, activeSearchPath)
|
||||||
{
|
{
|
||||||
Oid namespaceId = lfirst_oid(l);
|
Oid namespaceId = lfirst_oid(l);
|
||||||
|
|
||||||
@ -1051,7 +1068,7 @@ OpclassIsVisible(Oid opcid)
|
|||||||
*/
|
*/
|
||||||
opcnamespace = opcform->opcnamespace;
|
opcnamespace = opcform->opcnamespace;
|
||||||
if (opcnamespace != PG_CATALOG_NAMESPACE &&
|
if (opcnamespace != PG_CATALOG_NAMESPACE &&
|
||||||
!list_member_oid(namespaceSearchPath, opcnamespace))
|
!list_member_oid(activeSearchPath, opcnamespace))
|
||||||
visible = false;
|
visible = false;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1087,7 +1104,7 @@ OpfamilynameGetOpfid(Oid amid, const char *opfname)
|
|||||||
|
|
||||||
recomputeNamespacePath();
|
recomputeNamespacePath();
|
||||||
|
|
||||||
foreach(l, namespaceSearchPath)
|
foreach(l, activeSearchPath)
|
||||||
{
|
{
|
||||||
Oid namespaceId = lfirst_oid(l);
|
Oid namespaceId = lfirst_oid(l);
|
||||||
|
|
||||||
@ -1134,7 +1151,7 @@ OpfamilyIsVisible(Oid opfid)
|
|||||||
*/
|
*/
|
||||||
opfnamespace = opfform->opfnamespace;
|
opfnamespace = opfform->opfnamespace;
|
||||||
if (opfnamespace != PG_CATALOG_NAMESPACE &&
|
if (opfnamespace != PG_CATALOG_NAMESPACE &&
|
||||||
!list_member_oid(namespaceSearchPath, opfnamespace))
|
!list_member_oid(activeSearchPath, opfnamespace))
|
||||||
visible = false;
|
visible = false;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1169,7 +1186,7 @@ ConversionGetConid(const char *conname)
|
|||||||
|
|
||||||
recomputeNamespacePath();
|
recomputeNamespacePath();
|
||||||
|
|
||||||
foreach(l, namespaceSearchPath)
|
foreach(l, activeSearchPath)
|
||||||
{
|
{
|
||||||
Oid namespaceId = lfirst_oid(l);
|
Oid namespaceId = lfirst_oid(l);
|
||||||
|
|
||||||
@ -1215,7 +1232,7 @@ ConversionIsVisible(Oid conid)
|
|||||||
*/
|
*/
|
||||||
connamespace = conform->connamespace;
|
connamespace = conform->connamespace;
|
||||||
if (connamespace != PG_CATALOG_NAMESPACE &&
|
if (connamespace != PG_CATALOG_NAMESPACE &&
|
||||||
!list_member_oid(namespaceSearchPath, connamespace))
|
!list_member_oid(activeSearchPath, connamespace))
|
||||||
visible = false;
|
visible = false;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1381,7 +1398,7 @@ QualifiedNameGetCreationNamespace(List *names, char **objname_p)
|
|||||||
{
|
{
|
||||||
/* use the default creation namespace */
|
/* use the default creation namespace */
|
||||||
recomputeNamespacePath();
|
recomputeNamespacePath();
|
||||||
namespaceId = defaultCreationNamespace;
|
namespaceId = activeCreationNamespace;
|
||||||
if (!OidIsValid(namespaceId))
|
if (!OidIsValid(namespaceId))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_UNDEFINED_SCHEMA),
|
(errcode(ERRCODE_UNDEFINED_SCHEMA),
|
||||||
@ -1520,36 +1537,146 @@ isOtherTempNamespace(Oid namespaceId)
|
|||||||
return isAnyTempNamespace(namespaceId);
|
return isAnyTempNamespace(namespaceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PushSpecialNamespace - push a "special" namespace onto the front of the
|
* GetOverrideSearchPath - fetch current search path definition in form
|
||||||
* search path.
|
* used by PushOverrideSearchPath.
|
||||||
*
|
*
|
||||||
* This is a slightly messy hack intended only for support of CREATE SCHEMA.
|
* The result structure is allocated in the specified memory context
|
||||||
* Although the API is defined to allow a stack of pushed namespaces, we
|
* (which might or might not be equal to CurrentMemoryContext); but any
|
||||||
* presently only support one at a time.
|
* junk created by revalidation calculations will be in CurrentMemoryContext.
|
||||||
*
|
|
||||||
* The pushed namespace will be removed from the search path at end of
|
|
||||||
* transaction, whether commit or abort.
|
|
||||||
*/
|
*/
|
||||||
void
|
OverrideSearchPath *
|
||||||
PushSpecialNamespace(Oid namespaceId)
|
GetOverrideSearchPath(MemoryContext context)
|
||||||
{
|
{
|
||||||
Assert(!OidIsValid(mySpecialNamespace));
|
OverrideSearchPath *result;
|
||||||
mySpecialNamespace = namespaceId;
|
List *schemas;
|
||||||
namespaceSearchPathValid = false;
|
MemoryContext oldcxt;
|
||||||
|
|
||||||
|
recomputeNamespacePath();
|
||||||
|
|
||||||
|
oldcxt = MemoryContextSwitchTo(context);
|
||||||
|
|
||||||
|
result = (OverrideSearchPath *) palloc0(sizeof(OverrideSearchPath));
|
||||||
|
schemas = list_copy(activeSearchPath);
|
||||||
|
while (schemas && linitial_oid(schemas) != activeCreationNamespace)
|
||||||
|
{
|
||||||
|
if (linitial_oid(schemas) == myTempNamespace)
|
||||||
|
result->addTemp = true;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Assert(linitial_oid(schemas) == PG_CATALOG_NAMESPACE);
|
||||||
|
result->addCatalog = true;
|
||||||
|
}
|
||||||
|
schemas = list_delete_first(schemas);
|
||||||
|
}
|
||||||
|
result->schemas = schemas;
|
||||||
|
|
||||||
|
MemoryContextSwitchTo(oldcxt);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PopSpecialNamespace - remove previously pushed special namespace.
|
* PushOverrideSearchPath - temporarily override the search path
|
||||||
|
*
|
||||||
|
* We allow nested overrides, hence the push/pop terminology. The GUC
|
||||||
|
* search_path variable is ignored while an override is active.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
PopSpecialNamespace(Oid namespaceId)
|
PushOverrideSearchPath(OverrideSearchPath *newpath)
|
||||||
{
|
{
|
||||||
Assert(mySpecialNamespace == namespaceId);
|
OverrideStackEntry *entry;
|
||||||
mySpecialNamespace = InvalidOid;
|
List *oidlist;
|
||||||
namespaceSearchPathValid = false;
|
Oid firstNS;
|
||||||
|
MemoryContext oldcxt;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copy the list for safekeeping, and insert implicitly-searched
|
||||||
|
* namespaces as needed. This code should track recomputeNamespacePath.
|
||||||
|
*/
|
||||||
|
oldcxt = MemoryContextSwitchTo(TopMemoryContext);
|
||||||
|
|
||||||
|
oidlist = list_copy(newpath->schemas);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remember the first member of the explicit list.
|
||||||
|
*/
|
||||||
|
if (oidlist == NIL)
|
||||||
|
firstNS = InvalidOid;
|
||||||
|
else
|
||||||
|
firstNS = linitial_oid(oidlist);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add any implicitly-searched namespaces to the list. Note these go on
|
||||||
|
* the front, not the back; also notice that we do not check USAGE
|
||||||
|
* permissions for these.
|
||||||
|
*/
|
||||||
|
if (newpath->addCatalog)
|
||||||
|
oidlist = lcons_oid(PG_CATALOG_NAMESPACE, oidlist);
|
||||||
|
|
||||||
|
if (newpath->addTemp)
|
||||||
|
{
|
||||||
|
Assert(OidIsValid(myTempNamespace));
|
||||||
|
oidlist = lcons_oid(myTempNamespace, oidlist);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Build the new stack entry, then insert it at the head of the list.
|
||||||
|
*/
|
||||||
|
entry = (OverrideStackEntry *) palloc(sizeof(OverrideStackEntry));
|
||||||
|
entry->searchPath = oidlist;
|
||||||
|
entry->creationNamespace = firstNS;
|
||||||
|
entry->nestLevel = GetCurrentTransactionNestLevel();
|
||||||
|
|
||||||
|
overrideStack = lcons(entry, overrideStack);
|
||||||
|
|
||||||
|
/* And make it active. */
|
||||||
|
activeSearchPath = entry->searchPath;
|
||||||
|
activeCreationNamespace = entry->creationNamespace;
|
||||||
|
|
||||||
|
MemoryContextSwitchTo(oldcxt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PopOverrideSearchPath - undo a previous PushOverrideSearchPath
|
||||||
|
*
|
||||||
|
* Any push during a (sub)transaction will be popped automatically at abort.
|
||||||
|
* But it's caller error if a push isn't popped in normal control flow.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
PopOverrideSearchPath(void)
|
||||||
|
{
|
||||||
|
OverrideStackEntry *entry;
|
||||||
|
|
||||||
|
/* Sanity checks. */
|
||||||
|
if (overrideStack == NIL)
|
||||||
|
elog(ERROR, "bogus PopOverrideSearchPath call");
|
||||||
|
entry = (OverrideStackEntry *) linitial(overrideStack);
|
||||||
|
if (entry->nestLevel != GetCurrentTransactionNestLevel())
|
||||||
|
elog(ERROR, "bogus PopOverrideSearchPath call");
|
||||||
|
|
||||||
|
/* Pop the stack and free storage. */
|
||||||
|
overrideStack = list_delete_first(overrideStack);
|
||||||
|
list_free(entry->searchPath);
|
||||||
|
pfree(entry);
|
||||||
|
|
||||||
|
/* Activate the next level down. */
|
||||||
|
if (overrideStack)
|
||||||
|
{
|
||||||
|
entry = (OverrideStackEntry *) linitial(overrideStack);
|
||||||
|
activeSearchPath = entry->searchPath;
|
||||||
|
activeCreationNamespace = entry->creationNamespace;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* If not baseSearchPathValid, this is useless but harmless */
|
||||||
|
activeSearchPath = baseSearchPath;
|
||||||
|
activeCreationNamespace = baseCreationNamespace;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FindConversionByName - find a conversion by possibly qualified name
|
* FindConversionByName - find a conversion by possibly qualified name
|
||||||
*/
|
*/
|
||||||
@ -1576,7 +1703,7 @@ FindConversionByName(List *name)
|
|||||||
/* search for it in search path */
|
/* search for it in search path */
|
||||||
recomputeNamespacePath();
|
recomputeNamespacePath();
|
||||||
|
|
||||||
foreach(l, namespaceSearchPath)
|
foreach(l, activeSearchPath)
|
||||||
{
|
{
|
||||||
namespaceId = lfirst_oid(l);
|
namespaceId = lfirst_oid(l);
|
||||||
conoid = FindConversion(conversion_name, namespaceId);
|
conoid = FindConversion(conversion_name, namespaceId);
|
||||||
@ -1600,7 +1727,7 @@ FindDefaultConversionProc(int4 for_encoding, int4 to_encoding)
|
|||||||
|
|
||||||
recomputeNamespacePath();
|
recomputeNamespacePath();
|
||||||
|
|
||||||
foreach(l, namespaceSearchPath)
|
foreach(l, activeSearchPath)
|
||||||
{
|
{
|
||||||
Oid namespaceId = lfirst_oid(l);
|
Oid namespaceId = lfirst_oid(l);
|
||||||
|
|
||||||
@ -1628,10 +1755,12 @@ recomputeNamespacePath(void)
|
|||||||
Oid firstNS;
|
Oid firstNS;
|
||||||
MemoryContext oldcxt;
|
MemoryContext oldcxt;
|
||||||
|
|
||||||
/*
|
/* Do nothing if an override search spec is active. */
|
||||||
* Do nothing if path is already valid.
|
if (overrideStack)
|
||||||
*/
|
return;
|
||||||
if (namespaceSearchPathValid && namespaceUser == roleid)
|
|
||||||
|
/* Do nothing if path is already valid. */
|
||||||
|
if (baseSearchPathValid && namespaceUser == roleid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Need a modifiable copy of namespace_search_path string */
|
/* Need a modifiable copy of namespace_search_path string */
|
||||||
@ -1715,10 +1844,6 @@ recomputeNamespacePath(void)
|
|||||||
!list_member_oid(oidlist, myTempNamespace))
|
!list_member_oid(oidlist, myTempNamespace))
|
||||||
oidlist = lcons_oid(myTempNamespace, oidlist);
|
oidlist = lcons_oid(myTempNamespace, oidlist);
|
||||||
|
|
||||||
if (OidIsValid(mySpecialNamespace) &&
|
|
||||||
!list_member_oid(oidlist, mySpecialNamespace))
|
|
||||||
oidlist = lcons_oid(mySpecialNamespace, oidlist);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now that we've successfully built the new list of namespace OIDs, save
|
* Now that we've successfully built the new list of namespace OIDs, save
|
||||||
* it in permanent storage.
|
* it in permanent storage.
|
||||||
@ -1727,23 +1852,19 @@ recomputeNamespacePath(void)
|
|||||||
newpath = list_copy(oidlist);
|
newpath = list_copy(oidlist);
|
||||||
MemoryContextSwitchTo(oldcxt);
|
MemoryContextSwitchTo(oldcxt);
|
||||||
|
|
||||||
/* Now safe to assign to state variable. */
|
/* Now safe to assign to state variables. */
|
||||||
list_free(namespaceSearchPath);
|
list_free(baseSearchPath);
|
||||||
namespaceSearchPath = newpath;
|
baseSearchPath = newpath;
|
||||||
|
baseCreationNamespace = firstNS;
|
||||||
/*
|
|
||||||
* Update info derived from search path.
|
|
||||||
*/
|
|
||||||
firstExplicitNamespace = firstNS;
|
|
||||||
if (OidIsValid(mySpecialNamespace))
|
|
||||||
defaultCreationNamespace = mySpecialNamespace;
|
|
||||||
else
|
|
||||||
defaultCreationNamespace = firstNS;
|
|
||||||
|
|
||||||
/* Mark the path valid. */
|
/* Mark the path valid. */
|
||||||
namespaceSearchPathValid = true;
|
baseSearchPathValid = true;
|
||||||
namespaceUser = roleid;
|
namespaceUser = roleid;
|
||||||
|
|
||||||
|
/* And make it active. */
|
||||||
|
activeSearchPath = baseSearchPath;
|
||||||
|
activeCreationNamespace = baseCreationNamespace;
|
||||||
|
|
||||||
/* Clean up. */
|
/* Clean up. */
|
||||||
pfree(rawname);
|
pfree(rawname);
|
||||||
list_free(namelist);
|
list_free(namelist);
|
||||||
@ -1816,7 +1937,7 @@ InitTempTableNamespace(void)
|
|||||||
AssertState(myTempNamespaceSubID == InvalidSubTransactionId);
|
AssertState(myTempNamespaceSubID == InvalidSubTransactionId);
|
||||||
myTempNamespaceSubID = GetCurrentSubTransactionId();
|
myTempNamespaceSubID = GetCurrentSubTransactionId();
|
||||||
|
|
||||||
namespaceSearchPathValid = false; /* need to rebuild list */
|
baseSearchPathValid = false; /* need to rebuild list */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1840,18 +1961,30 @@ AtEOXact_Namespace(bool isCommit)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
myTempNamespace = InvalidOid;
|
myTempNamespace = InvalidOid;
|
||||||
namespaceSearchPathValid = false; /* need to rebuild list */
|
baseSearchPathValid = false; /* need to rebuild list */
|
||||||
}
|
}
|
||||||
myTempNamespaceSubID = InvalidSubTransactionId;
|
myTempNamespaceSubID = InvalidSubTransactionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clean up if someone failed to do PopSpecialNamespace
|
* Clean up if someone failed to do PopOverrideSearchPath
|
||||||
*/
|
*/
|
||||||
if (OidIsValid(mySpecialNamespace))
|
if (overrideStack)
|
||||||
{
|
{
|
||||||
mySpecialNamespace = InvalidOid;
|
if (isCommit)
|
||||||
namespaceSearchPathValid = false; /* need to rebuild list */
|
elog(WARNING, "leaked override search path");
|
||||||
|
while (overrideStack)
|
||||||
|
{
|
||||||
|
OverrideStackEntry *entry;
|
||||||
|
|
||||||
|
entry = (OverrideStackEntry *) linitial(overrideStack);
|
||||||
|
overrideStack = list_delete_first(overrideStack);
|
||||||
|
list_free(entry->searchPath);
|
||||||
|
pfree(entry);
|
||||||
|
}
|
||||||
|
/* If not baseSearchPathValid, this is useless but harmless */
|
||||||
|
activeSearchPath = baseSearchPath;
|
||||||
|
activeCreationNamespace = baseCreationNamespace;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1867,6 +2000,8 @@ void
|
|||||||
AtEOSubXact_Namespace(bool isCommit, SubTransactionId mySubid,
|
AtEOSubXact_Namespace(bool isCommit, SubTransactionId mySubid,
|
||||||
SubTransactionId parentSubid)
|
SubTransactionId parentSubid)
|
||||||
{
|
{
|
||||||
|
OverrideStackEntry *entry;
|
||||||
|
|
||||||
if (myTempNamespaceSubID == mySubid)
|
if (myTempNamespaceSubID == mySubid)
|
||||||
{
|
{
|
||||||
if (isCommit)
|
if (isCommit)
|
||||||
@ -1876,9 +2011,38 @@ AtEOSubXact_Namespace(bool isCommit, SubTransactionId mySubid,
|
|||||||
myTempNamespaceSubID = InvalidSubTransactionId;
|
myTempNamespaceSubID = InvalidSubTransactionId;
|
||||||
/* TEMP namespace creation failed, so reset state */
|
/* TEMP namespace creation failed, so reset state */
|
||||||
myTempNamespace = InvalidOid;
|
myTempNamespace = InvalidOid;
|
||||||
namespaceSearchPathValid = false; /* need to rebuild list */
|
baseSearchPathValid = false; /* need to rebuild list */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clean up if someone failed to do PopOverrideSearchPath
|
||||||
|
*/
|
||||||
|
while (overrideStack)
|
||||||
|
{
|
||||||
|
entry = (OverrideStackEntry *) linitial(overrideStack);
|
||||||
|
if (entry->nestLevel < GetCurrentTransactionNestLevel())
|
||||||
|
break;
|
||||||
|
if (isCommit)
|
||||||
|
elog(WARNING, "leaked override search path");
|
||||||
|
overrideStack = list_delete_first(overrideStack);
|
||||||
|
list_free(entry->searchPath);
|
||||||
|
pfree(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Activate the next level down. */
|
||||||
|
if (overrideStack)
|
||||||
|
{
|
||||||
|
entry = (OverrideStackEntry *) linitial(overrideStack);
|
||||||
|
activeSearchPath = entry->searchPath;
|
||||||
|
activeCreationNamespace = entry->creationNamespace;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* If not baseSearchPathValid, this is useless but harmless */
|
||||||
|
activeSearchPath = baseSearchPath;
|
||||||
|
activeCreationNamespace = baseCreationNamespace;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1991,7 +2155,7 @@ assign_search_path(const char *newval, bool doit, GucSource source)
|
|||||||
* initialization.
|
* initialization.
|
||||||
*/
|
*/
|
||||||
if (doit)
|
if (doit)
|
||||||
namespaceSearchPathValid = false;
|
baseSearchPathValid = false;
|
||||||
|
|
||||||
return newval;
|
return newval;
|
||||||
}
|
}
|
||||||
@ -2013,12 +2177,13 @@ InitializeSearchPath(void)
|
|||||||
MemoryContext oldcxt;
|
MemoryContext oldcxt;
|
||||||
|
|
||||||
oldcxt = MemoryContextSwitchTo(TopMemoryContext);
|
oldcxt = MemoryContextSwitchTo(TopMemoryContext);
|
||||||
namespaceSearchPath = list_make1_oid(PG_CATALOG_NAMESPACE);
|
baseSearchPath = list_make1_oid(PG_CATALOG_NAMESPACE);
|
||||||
MemoryContextSwitchTo(oldcxt);
|
MemoryContextSwitchTo(oldcxt);
|
||||||
defaultCreationNamespace = PG_CATALOG_NAMESPACE;
|
baseCreationNamespace = PG_CATALOG_NAMESPACE;
|
||||||
firstExplicitNamespace = PG_CATALOG_NAMESPACE;
|
baseSearchPathValid = true;
|
||||||
namespaceSearchPathValid = true;
|
|
||||||
namespaceUser = GetUserId();
|
namespaceUser = GetUserId();
|
||||||
|
activeSearchPath = baseSearchPath;
|
||||||
|
activeCreationNamespace = baseCreationNamespace;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -2030,7 +2195,7 @@ InitializeSearchPath(void)
|
|||||||
NamespaceCallback,
|
NamespaceCallback,
|
||||||
(Datum) 0);
|
(Datum) 0);
|
||||||
/* Force search path to be recomputed on next use */
|
/* Force search path to be recomputed on next use */
|
||||||
namespaceSearchPathValid = false;
|
baseSearchPathValid = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2042,7 +2207,7 @@ static void
|
|||||||
NamespaceCallback(Datum arg, Oid relid)
|
NamespaceCallback(Datum arg, Oid relid)
|
||||||
{
|
{
|
||||||
/* Force search path to be recomputed on next use */
|
/* Force search path to be recomputed on next use */
|
||||||
namespaceSearchPathValid = false;
|
baseSearchPathValid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2060,10 +2225,10 @@ fetch_search_path(bool includeImplicit)
|
|||||||
|
|
||||||
recomputeNamespacePath();
|
recomputeNamespacePath();
|
||||||
|
|
||||||
result = list_copy(namespaceSearchPath);
|
result = list_copy(activeSearchPath);
|
||||||
if (!includeImplicit)
|
if (!includeImplicit)
|
||||||
{
|
{
|
||||||
while (result && linitial_oid(result) != firstExplicitNamespace)
|
while (result && linitial_oid(result) != activeCreationNamespace)
|
||||||
result = list_delete_first(result);
|
result = list_delete_first(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/commands/schemacmds.c,v 1.44 2007/03/13 00:33:39 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/commands/schemacmds.c,v 1.45 2007/03/23 19:53:51 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -43,6 +43,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString)
|
|||||||
const char *schemaName = stmt->schemaname;
|
const char *schemaName = stmt->schemaname;
|
||||||
const char *authId = stmt->authid;
|
const char *authId = stmt->authid;
|
||||||
Oid namespaceId;
|
Oid namespaceId;
|
||||||
|
OverrideSearchPath *overridePath;
|
||||||
List *parsetree_list;
|
List *parsetree_list;
|
||||||
ListCell *parsetree_item;
|
ListCell *parsetree_item;
|
||||||
Oid owner_uid;
|
Oid owner_uid;
|
||||||
@ -102,7 +103,10 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString)
|
|||||||
* well as the default creation target namespace. This will be undone at
|
* well as the default creation target namespace. This will be undone at
|
||||||
* the end of this routine, or upon error.
|
* the end of this routine, or upon error.
|
||||||
*/
|
*/
|
||||||
PushSpecialNamespace(namespaceId);
|
overridePath = GetOverrideSearchPath(CurrentMemoryContext);
|
||||||
|
overridePath->schemas = lcons_oid(namespaceId, overridePath->schemas);
|
||||||
|
/* XXX should we clear overridePath->useTemp? */
|
||||||
|
PushOverrideSearchPath(overridePath);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Examine the list of commands embedded in the CREATE SCHEMA command, and
|
* Examine the list of commands embedded in the CREATE SCHEMA command, and
|
||||||
@ -143,7 +147,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Reset search path to normal state */
|
/* Reset search path to normal state */
|
||||||
PopSpecialNamespace(namespaceId);
|
PopOverrideSearchPath();
|
||||||
|
|
||||||
/* Reset current user */
|
/* Reset current user */
|
||||||
SetUserId(saved_uid);
|
SetUserId(saved_uid);
|
||||||
|
28
src/backend/utils/cache/plancache.c
vendored
28
src/backend/utils/cache/plancache.c
vendored
@ -33,13 +33,14 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/cache/plancache.c,v 1.3 2007/03/19 23:38:29 wieck Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/cache/plancache.c,v 1.4 2007/03/23 19:53:51 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "utils/plancache.h"
|
#include "utils/plancache.h"
|
||||||
|
#include "catalog/namespace.h"
|
||||||
#include "executor/executor.h"
|
#include "executor/executor.h"
|
||||||
#include "optimizer/clauses.h"
|
#include "optimizer/clauses.h"
|
||||||
#include "storage/lmgr.h"
|
#include "storage/lmgr.h"
|
||||||
@ -120,6 +121,7 @@ CreateCachedPlan(Node *raw_parse_tree,
|
|||||||
bool fixed_result)
|
bool fixed_result)
|
||||||
{
|
{
|
||||||
CachedPlanSource *plansource;
|
CachedPlanSource *plansource;
|
||||||
|
OverrideSearchPath *search_path;
|
||||||
MemoryContext source_context;
|
MemoryContext source_context;
|
||||||
MemoryContext oldcxt;
|
MemoryContext oldcxt;
|
||||||
|
|
||||||
@ -133,6 +135,12 @@ CreateCachedPlan(Node *raw_parse_tree,
|
|||||||
ALLOCSET_SMALL_INITSIZE,
|
ALLOCSET_SMALL_INITSIZE,
|
||||||
ALLOCSET_SMALL_MAXSIZE);
|
ALLOCSET_SMALL_MAXSIZE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fetch current search_path into new context, but do any recalculation
|
||||||
|
* work required in caller's context.
|
||||||
|
*/
|
||||||
|
search_path = GetOverrideSearchPath(source_context);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create and fill the CachedPlanSource struct within the new context.
|
* Create and fill the CachedPlanSource struct within the new context.
|
||||||
*/
|
*/
|
||||||
@ -151,6 +159,7 @@ CreateCachedPlan(Node *raw_parse_tree,
|
|||||||
plansource->num_params = num_params;
|
plansource->num_params = num_params;
|
||||||
plansource->fully_planned = fully_planned;
|
plansource->fully_planned = fully_planned;
|
||||||
plansource->fixed_result = fixed_result;
|
plansource->fixed_result = fixed_result;
|
||||||
|
plansource->search_path = search_path;
|
||||||
plansource->generation = 0; /* StoreCachedPlan will increment */
|
plansource->generation = 0; /* StoreCachedPlan will increment */
|
||||||
plansource->resultDesc = PlanCacheComputeResultDesc(stmt_list);
|
plansource->resultDesc = PlanCacheComputeResultDesc(stmt_list);
|
||||||
plansource->plan = NULL;
|
plansource->plan = NULL;
|
||||||
@ -209,8 +218,15 @@ FastCreateCachedPlan(Node *raw_parse_tree,
|
|||||||
MemoryContext context)
|
MemoryContext context)
|
||||||
{
|
{
|
||||||
CachedPlanSource *plansource;
|
CachedPlanSource *plansource;
|
||||||
|
OverrideSearchPath *search_path;
|
||||||
MemoryContext oldcxt;
|
MemoryContext oldcxt;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fetch current search_path into given context, but do any recalculation
|
||||||
|
* work required in caller's context.
|
||||||
|
*/
|
||||||
|
search_path = GetOverrideSearchPath(context);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create and fill the CachedPlanSource struct within the given context.
|
* Create and fill the CachedPlanSource struct within the given context.
|
||||||
*/
|
*/
|
||||||
@ -223,6 +239,7 @@ FastCreateCachedPlan(Node *raw_parse_tree,
|
|||||||
plansource->num_params = num_params;
|
plansource->num_params = num_params;
|
||||||
plansource->fully_planned = fully_planned;
|
plansource->fully_planned = fully_planned;
|
||||||
plansource->fixed_result = fixed_result;
|
plansource->fixed_result = fixed_result;
|
||||||
|
plansource->search_path = search_path;
|
||||||
plansource->generation = 0; /* StoreCachedPlan will increment */
|
plansource->generation = 0; /* StoreCachedPlan will increment */
|
||||||
plansource->resultDesc = PlanCacheComputeResultDesc(stmt_list);
|
plansource->resultDesc = PlanCacheComputeResultDesc(stmt_list);
|
||||||
plansource->plan = NULL;
|
plansource->plan = NULL;
|
||||||
@ -420,6 +437,12 @@ RevalidateCachedPlan(CachedPlanSource *plansource, bool useResOwner)
|
|||||||
List *slist;
|
List *slist;
|
||||||
TupleDesc resultDesc;
|
TupleDesc resultDesc;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Restore the search_path that was in use when the plan was made.
|
||||||
|
* (XXX is there anything else we really need to restore?)
|
||||||
|
*/
|
||||||
|
PushOverrideSearchPath(plansource->search_path);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Run parse analysis and rule rewriting. The parser tends to
|
* Run parse analysis and rule rewriting. The parser tends to
|
||||||
* scribble on its input, so we must copy the raw parse tree to
|
* scribble on its input, so we must copy the raw parse tree to
|
||||||
@ -469,6 +492,9 @@ RevalidateCachedPlan(CachedPlanSource *plansource, bool useResOwner)
|
|||||||
MemoryContextSwitchTo(oldcxt);
|
MemoryContextSwitchTo(oldcxt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Now we can restore current search path */
|
||||||
|
PopOverrideSearchPath();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Store the plans into the plancache entry, advancing the generation
|
* Store the plans into the plancache entry, advancing the generation
|
||||||
* count.
|
* count.
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/namespace.h,v 1.44 2007/01/05 22:19:52 momjian Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/namespace.h,v 1.45 2007/03/23 19:53:52 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -32,6 +32,16 @@ typedef struct _FuncCandidateList
|
|||||||
Oid args[1]; /* arg types --- VARIABLE LENGTH ARRAY */
|
Oid args[1]; /* arg types --- VARIABLE LENGTH ARRAY */
|
||||||
} *FuncCandidateList; /* VARIABLE LENGTH STRUCT */
|
} *FuncCandidateList; /* VARIABLE LENGTH STRUCT */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure for xxxOverrideSearchPath functions
|
||||||
|
*/
|
||||||
|
typedef struct OverrideSearchPath
|
||||||
|
{
|
||||||
|
List *schemas; /* OIDs of explicitly named schemas */
|
||||||
|
bool addCatalog; /* implicitly prepend pg_catalog? */
|
||||||
|
bool addTemp; /* implicitly prepend temp schema? */
|
||||||
|
} OverrideSearchPath;
|
||||||
|
|
||||||
|
|
||||||
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);
|
||||||
@ -72,8 +82,9 @@ extern bool isTempNamespace(Oid namespaceId);
|
|||||||
extern bool isAnyTempNamespace(Oid namespaceId);
|
extern bool isAnyTempNamespace(Oid namespaceId);
|
||||||
extern bool isOtherTempNamespace(Oid namespaceId);
|
extern bool isOtherTempNamespace(Oid namespaceId);
|
||||||
|
|
||||||
extern void PushSpecialNamespace(Oid namespaceId);
|
extern OverrideSearchPath *GetOverrideSearchPath(MemoryContext context);
|
||||||
extern void PopSpecialNamespace(Oid namespaceId);
|
extern void PushOverrideSearchPath(OverrideSearchPath *newpath);
|
||||||
|
extern void PopOverrideSearchPath(void);
|
||||||
|
|
||||||
extern Oid FindConversionByName(List *conname);
|
extern Oid FindConversionByName(List *conname);
|
||||||
extern Oid FindDefaultConversionProc(int4 for_encoding, int4 to_encoding);
|
extern Oid FindDefaultConversionProc(int4 for_encoding, int4 to_encoding);
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/utils/plancache.h,v 1.3 2007/03/19 23:38:32 wieck Exp $
|
* $PostgreSQL: pgsql/src/include/utils/plancache.h,v 1.4 2007/03/23 19:53:52 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -53,6 +53,7 @@ typedef struct CachedPlanSource
|
|||||||
int num_params; /* length of param_types array */
|
int num_params; /* length of param_types array */
|
||||||
bool fully_planned; /* do we cache planner or rewriter output? */
|
bool fully_planned; /* do we cache planner or rewriter output? */
|
||||||
bool fixed_result; /* disallow change in result tupdesc? */
|
bool fixed_result; /* disallow change in result tupdesc? */
|
||||||
|
struct OverrideSearchPath *search_path; /* saved search_path */
|
||||||
int generation; /* counter, starting at 1, for replans */
|
int generation; /* counter, starting at 1, for replans */
|
||||||
TupleDesc resultDesc; /* result type; NULL = doesn't return tuples */
|
TupleDesc resultDesc; /* result type; NULL = doesn't return tuples */
|
||||||
struct CachedPlan *plan; /* link to plan, or NULL if not valid */
|
struct CachedPlan *plan; /* link to plan, or NULL if not valid */
|
||||||
|
@ -163,3 +163,42 @@ select cache_test_2();
|
|||||||
10007
|
10007
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
--- Check that change of search_path is ignored by replans
|
||||||
|
create schema s1
|
||||||
|
create table abc (f1 int);
|
||||||
|
create schema s2
|
||||||
|
create table abc (f1 int);
|
||||||
|
insert into s1.abc values(123);
|
||||||
|
insert into s2.abc values(456);
|
||||||
|
set search_path = s1;
|
||||||
|
prepare p1 as select f1 from abc;
|
||||||
|
execute p1;
|
||||||
|
f1
|
||||||
|
-----
|
||||||
|
123
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
set search_path = s2;
|
||||||
|
select f1 from abc;
|
||||||
|
f1
|
||||||
|
-----
|
||||||
|
456
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
execute p1;
|
||||||
|
f1
|
||||||
|
-----
|
||||||
|
123
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
alter table s1.abc add column f2 float8; -- force replan
|
||||||
|
execute p1;
|
||||||
|
f1
|
||||||
|
-----
|
||||||
|
123
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
drop schema s1 cascade;
|
||||||
|
NOTICE: drop cascades to table s1.abc
|
||||||
|
drop schema s2 cascade;
|
||||||
|
NOTICE: drop cascades to table abc
|
||||||
|
@ -93,3 +93,33 @@ select cache_test_2();
|
|||||||
create or replace temp view v1 as
|
create or replace temp view v1 as
|
||||||
select 2+2+4+(select max(unique1) from tenk1) as f1;
|
select 2+2+4+(select max(unique1) from tenk1) as f1;
|
||||||
select cache_test_2();
|
select cache_test_2();
|
||||||
|
|
||||||
|
--- Check that change of search_path is ignored by replans
|
||||||
|
|
||||||
|
create schema s1
|
||||||
|
create table abc (f1 int);
|
||||||
|
|
||||||
|
create schema s2
|
||||||
|
create table abc (f1 int);
|
||||||
|
|
||||||
|
insert into s1.abc values(123);
|
||||||
|
insert into s2.abc values(456);
|
||||||
|
|
||||||
|
set search_path = s1;
|
||||||
|
|
||||||
|
prepare p1 as select f1 from abc;
|
||||||
|
|
||||||
|
execute p1;
|
||||||
|
|
||||||
|
set search_path = s2;
|
||||||
|
|
||||||
|
select f1 from abc;
|
||||||
|
|
||||||
|
execute p1;
|
||||||
|
|
||||||
|
alter table s1.abc add column f2 float8; -- force replan
|
||||||
|
|
||||||
|
execute p1;
|
||||||
|
|
||||||
|
drop schema s1 cascade;
|
||||||
|
drop schema s2 cascade;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user