1
0
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:
Robert Haas
2011-04-25 16:55:11 -04:00
parent be90032e0d
commit 68ef051f5c
11 changed files with 73 additions and 79 deletions

View File

@ -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);