mirror of
https://github.com/postgres/postgres.git
synced 2025-06-17 17:02:08 +03:00
Refactor broken CREATE TABLE IF NOT EXISTS support.
Per bug #5988, reported by Marko Tiikkaja, and further analyzed by Tom Lane, the previous coding was broken in several respects: even if the target table already existed, a subsequent CREATE TABLE IF NOT EXISTS might try to add additional constraints or sequences-for-serial specified in the new CREATE TABLE statement. In passing, this also fixes a minor information leak: it's no longer possible to figure out whether a schema to which you don't have CREATE access contains a sequence named like "x_y_seq" by attempting to create a table in that schema called "x" with a serial column called "y". Some more refactoring of this code in the future might be warranted, but that will need to wait for a later major release.
This commit is contained in:
@ -148,6 +148,7 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString)
|
||||
List *result;
|
||||
List *save_alist;
|
||||
ListCell *elements;
|
||||
Oid namespaceid;
|
||||
|
||||
/*
|
||||
* We must not scribble on the passed-in CreateStmt, so copy it. (This is
|
||||
@ -155,6 +156,33 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString)
|
||||
*/
|
||||
stmt = (CreateStmt *) copyObject(stmt);
|
||||
|
||||
/*
|
||||
* Look up the creation namespace. This also checks permissions on the
|
||||
* target namespace, so that we throw any permissions error as early as
|
||||
* possible.
|
||||
*/
|
||||
namespaceid = RangeVarGetAndCheckCreationNamespace(stmt->relation);
|
||||
|
||||
/*
|
||||
* If the relation already exists and the user specified "IF NOT EXISTS",
|
||||
* bail out with a NOTICE.
|
||||
*/
|
||||
if (stmt->if_not_exists)
|
||||
{
|
||||
Oid existing_relid;
|
||||
|
||||
existing_relid = get_relname_relid(stmt->relation->relname,
|
||||
namespaceid);
|
||||
if (existing_relid != InvalidOid)
|
||||
{
|
||||
ereport(NOTICE,
|
||||
(errcode(ERRCODE_DUPLICATE_TABLE),
|
||||
errmsg("relation \"%s\" already exists, skipping",
|
||||
stmt->relation->relname)));
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If the target relation name isn't schema-qualified, make it so. This
|
||||
* prevents some corner cases in which added-on rewritten commands might
|
||||
@ -164,11 +192,7 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString)
|
||||
*/
|
||||
if (stmt->relation->schemaname == NULL
|
||||
&& stmt->relation->relpersistence != RELPERSISTENCE_TEMP)
|
||||
{
|
||||
Oid namespaceid = RangeVarGetCreationNamespace(stmt->relation);
|
||||
|
||||
stmt->relation->schemaname = get_namespace_name(namespaceid);
|
||||
}
|
||||
|
||||
/* Set up pstate and CreateStmtContext */
|
||||
pstate = make_parsestate(NULL);
|
||||
|
Reference in New Issue
Block a user