diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c index 84220bd4ce..46e0312b99 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 - * $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.98 2007/08/21 01:11:13 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.99 2007/08/27 03:36:08 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -228,7 +228,26 @@ RangeVarGetRelid(const RangeVar *relation, bool failOK) relation->relname))); } - if (relation->schemaname) + /* + * If istemp is set, this is a reference to a temp relation. The parser + * never generates such a RangeVar in simple DML, but it can happen in + * contexts such as "CREATE TEMP TABLE foo (f1 int PRIMARY KEY)". Such a + * command will generate an added CREATE INDEX operation, which must be + * careful to find the temp table, even when pg_temp is not first in the + * search path. + */ + if (relation->istemp) + { + if (relation->schemaname) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("temporary tables cannot specify a schema name"))); + if (OidIsValid(myTempNamespace)) + relId = get_relname_relid(relation->relname, myTempNamespace); + else /* this probably can't happen? */ + relId = InvalidOid; + } + else if (relation->schemaname) { /* use exact schema given */ namespaceId = LookupExplicitNamespace(relation->schemaname); diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c index f8dac12643..a6ef94dcef 100644 --- a/src/backend/commands/view.c +++ b/src/backend/commands/view.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.101 2007/06/23 22:12:50 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.102 2007/08/27 03:36:08 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -260,14 +260,14 @@ checkViewTupleDesc(TupleDesc newdesc, TupleDesc olddesc) } static void -DefineViewRules(const RangeVar *view, Query *viewParse, bool replace) +DefineViewRules(Oid viewOid, Query *viewParse, bool replace) { /* * Set up the ON SELECT rule. Since the query has already been through * parse analysis, we use DefineQueryRewrite() directly. */ DefineQueryRewrite(pstrdup(ViewSelectRuleName), - (RangeVar *) copyObject((RangeVar *) view), + viewOid, NULL, CMD_SELECT, true, @@ -404,7 +404,9 @@ DefineView(ViewStmt *stmt, const char *queryString) /* * If the user didn't explicitly ask for a temporary view, check whether - * we need one implicitly. + * we need one implicitly. We allow TEMP to be inserted automatically + * as long as the CREATE command is consistent with that --- no explicit + * schema name. */ view = stmt->view; if (!view->istemp && isViewOnTempTable(viewParse)) @@ -441,7 +443,7 @@ DefineView(ViewStmt *stmt, const char *queryString) /* * Now create the rules associated with the view. */ - DefineViewRules(view, viewParse, stmt->replace); + DefineViewRules(viewOid, viewParse, stmt->replace); } /* diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index f17ad48021..54e7dfdb16 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -19,7 +19,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/backend/parser/parse_utilcmd.c,v 2.2 2007/07/17 05:02:02 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_utilcmd.c,v 2.3 2007/08/27 03:36:08 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -143,6 +143,20 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString) */ stmt = (CreateStmt *) copyObject(stmt); + /* + * If the target relation name isn't schema-qualified, make it so. This + * prevents some corner cases in which added-on rewritten commands might + * think they should apply to other relations that have the same name + * and are earlier in the search path. "istemp" is equivalent to a + * specification of pg_temp, so no need for anything extra in that case. + */ + if (stmt->relation->schemaname == NULL && !stmt->relation->istemp) + { + Oid namespaceid = RangeVarGetCreationNamespace(stmt->relation); + + stmt->relation->schemaname = get_namespace_name(namespaceid); + } + /* Set up pstate */ pstate = make_parsestate(NULL); pstate->p_sourcetext = queryString; diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c index 540f340368..34c13068f9 100644 --- a/src/backend/rewrite/rewriteDefine.c +++ b/src/backend/rewrite/rewriteDefine.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/rewrite/rewriteDefine.c,v 1.121 2007/06/23 22:12:51 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/rewrite/rewriteDefine.c,v 1.122 2007/08/27 03:36:08 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -17,6 +17,7 @@ #include "access/heapam.h" #include "catalog/dependency.h" #include "catalog/indexing.h" +#include "catalog/namespace.h" #include "catalog/pg_rewrite.h" #include "miscadmin.h" #include "optimizer/clauses.h" @@ -189,13 +190,17 @@ DefineRule(RuleStmt *stmt, const char *queryString) { List *actions; Node *whereClause; + Oid relId; /* Parse analysis ... */ transformRuleStmt(stmt, queryString, &actions, &whereClause); - /* ... and execution */ + /* ... find the relation ... */ + relId = RangeVarGetRelid(stmt->relation, false); + + /* ... and execute */ DefineQueryRewrite(stmt->rulename, - stmt->relation, + relId, whereClause, stmt->event, stmt->instead, @@ -213,7 +218,7 @@ DefineRule(RuleStmt *stmt, const char *queryString) */ void DefineQueryRewrite(char *rulename, - RangeVar *event_obj, + Oid event_relid, Node *event_qual, CmdType event_type, bool is_instead, @@ -221,7 +226,6 @@ DefineQueryRewrite(char *rulename, List *action) { Relation event_relation; - Oid ev_relid; Oid ruleId; int event_attno; ListCell *l; @@ -235,13 +239,12 @@ DefineQueryRewrite(char *rulename, * grab ShareLock to lock out insert/update/delete actions. But for now, * let's just grab AccessExclusiveLock all the time. */ - event_relation = heap_openrv(event_obj, AccessExclusiveLock); - ev_relid = RelationGetRelid(event_relation); + event_relation = heap_open(event_relid, AccessExclusiveLock); /* * Check user has permission to apply rules to this relation. */ - if (!pg_class_ownercheck(ev_relid, GetUserId())) + if (!pg_class_ownercheck(event_relid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, RelationGetRelationName(event_relation)); @@ -352,12 +355,13 @@ DefineQueryRewrite(char *rulename, * truncated. */ if (strncmp(rulename, "_RET", 4) != 0 || - strncmp(rulename + 4, event_obj->relname, + strncmp(rulename + 4, RelationGetRelationName(event_relation), NAMEDATALEN - 4 - 4) != 0) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("view rule for \"%s\" must be named \"%s\"", - event_obj->relname, ViewSelectRuleName))); + RelationGetRelationName(event_relation), + ViewSelectRuleName))); rulename = pstrdup(ViewSelectRuleName); } @@ -377,27 +381,27 @@ DefineQueryRewrite(char *rulename, ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("could not convert table \"%s\" to a view because it is not empty", - event_obj->relname))); + RelationGetRelationName(event_relation)))); heap_endscan(scanDesc); if (event_relation->rd_rel->reltriggers != 0) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("could not convert table \"%s\" to a view because it has triggers", - event_obj->relname), + RelationGetRelationName(event_relation)), errhint("In particular, the table cannot be involved in any foreign key relationships."))); if (event_relation->rd_rel->relhasindex) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("could not convert table \"%s\" to a view because it has indexes", - event_obj->relname))); + RelationGetRelationName(event_relation)))); if (event_relation->rd_rel->relhassubclass) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("could not convert table \"%s\" to a view because it has child tables", - event_obj->relname))); + RelationGetRelationName(event_relation)))); RelisBecomingView = true; } @@ -449,7 +453,7 @@ DefineQueryRewrite(char *rulename, { ruleId = InsertRule(rulename, event_type, - ev_relid, + event_relid, event_attno, is_instead, event_qual, @@ -465,7 +469,7 @@ DefineQueryRewrite(char *rulename, * backends (including me!) to update relcache entries with the new * rule. */ - SetRelationRuleStatus(ev_relid, true, RelisBecomingView); + SetRelationRuleStatus(event_relid, true, RelisBecomingView); } /* @@ -701,7 +705,7 @@ EnableDisableRule(Relation rel, const char *rulename, /* * Rename an existing rewrite rule. * - * This is unused code at the moment. + * This is unused code at the moment. Note that it lacks a permissions check. */ #ifdef NOT_USED void diff --git a/src/include/rewrite/rewriteDefine.h b/src/include/rewrite/rewriteDefine.h index 5b21cf8e79..f4469349c8 100644 --- a/src/include/rewrite/rewriteDefine.h +++ b/src/include/rewrite/rewriteDefine.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/rewrite/rewriteDefine.h,v 1.25 2007/03/19 23:38:32 wieck Exp $ + * $PostgreSQL: pgsql/src/include/rewrite/rewriteDefine.h,v 1.26 2007/08/27 03:36:08 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -24,7 +24,7 @@ extern void DefineRule(RuleStmt *stmt, const char *queryString); extern void DefineQueryRewrite(char *rulename, - RangeVar *event_obj, + Oid event_relid, Node *event_qual, CmdType event_type, bool is_instead,