Commit 547b6e53 authored by Tom Lane's avatar Tom Lane

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.
parent 4c35ec53
This diff is collapsed.
...@@ -8,7 +8,7 @@ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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);
......
...@@ -33,13 +33,14 @@ ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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 @@ ...@@ -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 ...@@ -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); ...@@ -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 @@ ...@@ -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 ...@@ -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(); ...@@ -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(); ...@@ -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;
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