aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_utilcmd.c
diff options
context:
space:
mode:
authorRobert Haas <rhaas@postgresql.org>2011-04-25 16:55:11 -0400
committerRobert Haas <rhaas@postgresql.org>2011-04-25 16:55:11 -0400
commit68ef051f5cf16f82a5368067a40ffba3c340b0d3 (patch)
tree6b8158651e981c35d3653f59114ef33ec9946a2f /src/backend/parser/parse_utilcmd.c
parentbe90032e0d1cf473bdd99aee94218218f59f29f1 (diff)
downloadpostgresql-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.c32
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);