diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/catalog/pg_enum.c | 18 | ||||
-rw-r--r-- | src/backend/commands/typecmds.c | 3 | ||||
-rw-r--r-- | src/backend/nodes/copyfuncs.c | 1 | ||||
-rw-r--r-- | src/backend/nodes/equalfuncs.c | 1 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 25 | ||||
-rw-r--r-- | src/include/catalog/pg_enum.h | 3 | ||||
-rw-r--r-- | src/include/nodes/parsenodes.h | 1 | ||||
-rw-r--r-- | src/test/regress/expected/enum.out | 22 | ||||
-rw-r--r-- | src/test/regress/sql/enum.sql | 20 |
9 files changed, 82 insertions, 12 deletions
diff --git a/src/backend/catalog/pg_enum.c b/src/backend/catalog/pg_enum.c index 8ddb376bc16..f3161efb20b 100644 --- a/src/backend/catalog/pg_enum.c +++ b/src/backend/catalog/pg_enum.c @@ -179,7 +179,8 @@ void AddEnumLabel(Oid enumTypeOid, const char *newVal, const char *neighbor, - bool newValIsAfter) + bool newValIsAfter, + bool skipIfExists) { Relation pg_enum; Oid newOid; @@ -211,6 +212,21 @@ AddEnumLabel(Oid enumTypeOid, */ LockDatabaseObject(TypeRelationId, enumTypeOid, 0, ExclusiveLock); + /* Do the "IF NOT EXISTS" test if specified */ + if (skipIfExists) + { + HeapTuple tup; + + tup = SearchSysCache2(ENUMTYPOIDNAME, + ObjectIdGetDatum(enumTypeOid), + CStringGetDatum(newVal)); + if (HeapTupleIsValid(tup)) + { + ReleaseSysCache(tup); + return; + } + } + pg_enum = heap_open(EnumRelationId, RowExclusiveLock); /* If we have to renumber the existing members, we restart from here */ diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index 4c9d00386cb..6cb6fd56fd9 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -1188,7 +1188,8 @@ AlterEnum(AlterEnumStmt *stmt) /* Add the new label */ AddEnumLabel(enum_type_oid, stmt->newVal, - stmt->newValNeighbor, stmt->newValIsAfter); + stmt->newValNeighbor, stmt->newValIsAfter, + stmt->skipIfExists); ReleaseSysCache(tup); } diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index f34f7049e43..34d4f40fe23 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -3055,6 +3055,7 @@ _copyAlterEnumStmt(const AlterEnumStmt *from) COPY_STRING_FIELD(newVal); COPY_STRING_FIELD(newValNeighbor); COPY_SCALAR_FIELD(newValIsAfter); + COPY_SCALAR_FIELD(skipIfExists); return newnode; } diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index b4b1c223363..f63f4973db5 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -1439,6 +1439,7 @@ _equalAlterEnumStmt(const AlterEnumStmt *a, const AlterEnumStmt *b) COMPARE_STRING_FIELD(newVal); COMPARE_STRING_FIELD(newValNeighbor); COMPARE_SCALAR_FIELD(newValIsAfter); + COMPARE_SCALAR_FIELD(skipIfExists); return true; } diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 5894cb0885c..ec88b710769 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -470,7 +470,7 @@ static void processCASbits(int cas_bits, int location, const char *constrType, %type <windef> window_definition over_clause window_specification opt_frame_clause frame_extent frame_bound %type <str> opt_existing_window_name - +%type <boolean> opt_if_not_exists /* * Non-keyword token types. These are hard-wired into the "flex" lexer. @@ -4618,35 +4618,42 @@ enum_val_list: Sconst *****************************************************************************/ AlterEnumStmt: - ALTER TYPE_P any_name ADD_P VALUE_P Sconst + ALTER TYPE_P any_name ADD_P VALUE_P opt_if_not_exists Sconst { AlterEnumStmt *n = makeNode(AlterEnumStmt); n->typeName = $3; - n->newVal = $6; + n->newVal = $7; n->newValNeighbor = NULL; n->newValIsAfter = true; + n->skipIfExists = $6; $$ = (Node *) n; } - | ALTER TYPE_P any_name ADD_P VALUE_P Sconst BEFORE Sconst + | ALTER TYPE_P any_name ADD_P VALUE_P opt_if_not_exists Sconst BEFORE Sconst { AlterEnumStmt *n = makeNode(AlterEnumStmt); n->typeName = $3; - n->newVal = $6; - n->newValNeighbor = $8; + n->newVal = $7; + n->newValNeighbor = $9; n->newValIsAfter = false; + n->skipIfExists = $6; $$ = (Node *) n; } - | ALTER TYPE_P any_name ADD_P VALUE_P Sconst AFTER Sconst + | ALTER TYPE_P any_name ADD_P VALUE_P opt_if_not_exists Sconst AFTER Sconst { AlterEnumStmt *n = makeNode(AlterEnumStmt); n->typeName = $3; - n->newVal = $6; - n->newValNeighbor = $8; + n->newVal = $7; + n->newValNeighbor = $9; n->newValIsAfter = true; + n->skipIfExists = $6; $$ = (Node *) n; } ; +opt_if_not_exists: IF_P NOT EXISTS { $$ = true; } + | /* empty */ { $$ = false; } + ; + /***************************************************************************** * diff --git a/src/include/catalog/pg_enum.h b/src/include/catalog/pg_enum.h index 91c1ab1de7d..8842a8706b5 100644 --- a/src/include/catalog/pg_enum.h +++ b/src/include/catalog/pg_enum.h @@ -65,6 +65,7 @@ typedef FormData_pg_enum *Form_pg_enum; extern void EnumValuesCreate(Oid enumTypeOid, List *vals); extern void EnumValuesDelete(Oid enumTypeOid); extern void AddEnumLabel(Oid enumTypeOid, const char *newVal, - const char *neighbor, bool newValIsAfter); + const char *neighbor, bool newValIsAfter, + bool skipIfExists); #endif /* PG_ENUM_H */ diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 19178b55512..98fe850c927 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -2306,6 +2306,7 @@ typedef struct AlterEnumStmt char *newVal; /* new enum value's name */ char *newValNeighbor; /* neighboring enum value, if specified */ bool newValIsAfter; /* place new enum value after neighbor? */ + bool skipIfExists; /* ignore statement if label already exists */ } AlterEnumStmt; /* ---------------------- diff --git a/src/test/regress/expected/enum.out b/src/test/regress/expected/enum.out index bf94af5ef6e..a14097297a1 100644 --- a/src/test/regress/expected/enum.out +++ b/src/test/regress/expected/enum.out @@ -95,6 +95,28 @@ ERROR: invalid enum label "plutoplutoplutoplutoplutoplutoplutoplutoplutoplutopl DETAIL: Labels must be 63 characters or less. ALTER TYPE planets ADD VALUE 'pluto' AFTER 'zeus'; ERROR: "zeus" is not an existing enum label +-- if not exists tests +-- existing value gives error +-- We can't do this test because the error contains the +-- offending Oid value, which is unpredictable. +-- ALTER TYPE planets ADD VALUE 'mercury'; +-- unless IF NOT EXISTS is specified +ALTER TYPE planets ADD VALUE IF NOT EXISTS 'mercury'; +-- should be neptune, not mercury +SELECT enum_last(NULL::planets); + enum_last +----------- + neptune +(1 row) + +ALTER TYPE planets ADD VALUE IF NOT EXISTS 'pluto'; +-- should be pluto, i.e. the new value +SELECT enum_last(NULL::planets); + enum_last +----------- + pluto +(1 row) + -- -- Test inserting so many values that we have to renumber -- diff --git a/src/test/regress/sql/enum.sql b/src/test/regress/sql/enum.sql index 7ca62483096..db7bf44b408 100644 --- a/src/test/regress/sql/enum.sql +++ b/src/test/regress/sql/enum.sql @@ -54,6 +54,26 @@ ALTER TYPE planets ADD VALUE ALTER TYPE planets ADD VALUE 'pluto' AFTER 'zeus'; +-- if not exists tests + +-- existing value gives error + +-- We can't do this test because the error contains the +-- offending Oid value, which is unpredictable. +-- ALTER TYPE planets ADD VALUE 'mercury'; + +-- unless IF NOT EXISTS is specified +ALTER TYPE planets ADD VALUE IF NOT EXISTS 'mercury'; + +-- should be neptune, not mercury +SELECT enum_last(NULL::planets); + +ALTER TYPE planets ADD VALUE IF NOT EXISTS 'pluto'; + +-- should be pluto, i.e. the new value +SELECT enum_last(NULL::planets); + + -- -- Test inserting so many values that we have to renumber -- |