diff options
author | Robert Haas <rhaas@postgresql.org> | 2011-04-25 16:55:11 -0400 |
---|---|---|
committer | Robert Haas <rhaas@postgresql.org> | 2011-04-25 16:55:11 -0400 |
commit | 68ef051f5cf16f82a5368067a40ffba3c340b0d3 (patch) | |
tree | 6b8158651e981c35d3653f59114ef33ec9946a2f /src/backend/parser/parse_utilcmd.c | |
parent | be90032e0d1cf473bdd99aee94218218f59f29f1 (diff) | |
download | postgresql-68ef051f5cf16f82a5368067a40ffba3c340b0d3.tar.gz postgresql-68ef051f5cf16f82a5368067a40ffba3c340b0d3.zip |
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.
Diffstat (limited to 'src/backend/parser/parse_utilcmd.c')
-rw-r--r-- | src/backend/parser/parse_utilcmd.c | 32 |
1 files changed, 28 insertions, 4 deletions
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index 0078814905d..5588cfac0bd 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -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 @@ -156,6 +157,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 * think they should apply to other relations that have the same name and @@ -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); |