* view.c
* use rewrite rules to construct views
*
- * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.118 2009/10/13 00:53:07 tgl Exp $
+ * src/backend/commands/view.c
*
*-------------------------------------------------------------------------
*/
if (rte->rtekind == RTE_RELATION)
{
Relation rel = heap_open(rte->relid, AccessShareLock);
- bool istemp = rel->rd_istemp;
+ char relpersistence = rel->rd_rel->relpersistence;
heap_close(rel, AccessShareLock);
- if (istemp)
+ if (relpersistence == RELPERSISTENCE_TEMP)
return true;
}
}
*---------------------------------------------------------------------
*/
static Oid
-DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace)
+DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace,
+ Oid namespaceId)
{
- Oid viewOid,
- namespaceId;
+ Oid viewOid;
CreateStmt *createStmt = makeNode(CreateStmt);
List *attrList;
ListCell *t;
def->inhcount = 0;
def->is_local = true;
def->is_not_null = false;
+ def->is_from_type = false;
def->storage = 0;
def->raw_default = NULL;
def->cooked_default = NULL;
+ def->collClause = NULL;
+ def->collOid = exprCollation((Node *) tle->expr);
+
+ /*
+ * It's possible that the column is of a collatable type but the
+ * collation could not be resolved, so double-check.
+ */
+ if (type_is_collatable(exprType((Node *) tle->expr)))
+ {
+ if (!OidIsValid(def->collOid))
+ ereport(ERROR,
+ (errcode(ERRCODE_INDETERMINATE_COLLATION),
+ errmsg("could not determine which collation to use for view column \"%s\"",
+ def->colname),
+ errhint("Use the COLLATE clause to set the collation explicitly.")));
+ }
+ else
+ Assert(!OidIsValid(def->collOid));
def->constraints = NIL;
attrList = lappend(attrList, def);
/*
* Check to see if we want to replace an existing view.
*/
- namespaceId = RangeVarGetCreationNamespace(relation);
viewOid = get_relname_relid(relation->relname, namespaceId);
if (OidIsValid(viewOid) && replace)
/*
* Due to the namespace visibility rules for temporary objects, we
* should only end up replacing a temporary view with another
- * temporary view, and vice versa.
+ * temporary view, and similarly for permanent views.
*/
- Assert(relation->istemp == rel->rd_istemp);
+ Assert(relation->relpersistence == rel->rd_rel->relpersistence);
/*
* Create a tuple descriptor to compare against the existing view, and
}
else
{
+ Oid relid;
+
/*
* now set the parameters for keys/inheritance etc. All of these are
* uninteresting for views...
createStmt->options = list_make1(defWithOids(false));
createStmt->oncommit = ONCOMMIT_NOOP;
createStmt->tablespacename = NULL;
+ createStmt->if_not_exists = false;
/*
* finally create the relation (this will error out if there's an
* existing view, so we don't need more code to complain if "replace"
* is false).
*/
- return DefineRelation(createStmt, RELKIND_VIEW);
+ relid = DefineRelation(createStmt, RELKIND_VIEW, InvalidOid);
+ Assert(relid != InvalidOid);
+ return relid;
}
}
* OLD first, then NEW....
*/
rt_entry1 = addRangeTableEntryForRelation(NULL, viewRel,
- makeAlias("*OLD*", NIL),
+ makeAlias("old", NIL),
false, false);
rt_entry2 = addRangeTableEntryForRelation(NULL, viewRel,
- makeAlias("*NEW*", NIL),
+ makeAlias("new", NIL),
false, false);
/* Must override addRangeTableEntry's default access-check flags */
rt_entry1->requiredPerms = 0;
{
Query *viewParse;
Oid viewOid;
+ Oid namespaceId;
RangeVar *view;
/*
elog(ERROR, "unexpected parse analysis result");
/*
+ * Check for unsupported cases. These tests are redundant with ones in
+ * DefineQueryRewrite(), but that function will complain about a bogus ON
+ * SELECT rule, and we'd rather the message complain about a view.
+ */
+ if (viewParse->intoClause != NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("views must not contain SELECT INTO")));
+ if (viewParse->hasModifyingCTE)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("views must not contain data-modifying statements in WITH")));
+
+ /*
* If a list of column names was given, run through and insert these into
* the actual query tree. - thomas 2000-03-08
*/
"names than columns")));
}
+ /* Unlogged views are not sensible. */
+ if (stmt->view->relpersistence == RELPERSISTENCE_UNLOGGED)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("views cannot be unlogged because they do not have storage")));
+
/*
* If the user didn't explicitly ask for a temporary view, check whether
* 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))
+ view = copyObject(stmt->view); /* don't corrupt original command */
+ if (view->relpersistence == RELPERSISTENCE_PERMANENT
+ && isViewOnTempTable(viewParse))
{
- view = copyObject(view); /* don't corrupt original command */
- view->istemp = true;
+ view->relpersistence = RELPERSISTENCE_TEMP;
ereport(NOTICE,
(errmsg("view \"%s\" will be a temporary view",
view->relname)));
}
+ /* Might also need to make it temporary if placed in temp schema. */
+ namespaceId = RangeVarGetCreationNamespace(view);
+ RangeVarAdjustRelationPersistence(view, namespaceId);
+
/*
* Create the view relation
*
* aborted.
*/
viewOid = DefineVirtualRelation(view, viewParse->targetList,
- stmt->replace);
+ stmt->replace, namespaceId);
/*
* The relation we have just created is not visible to any other commands