diff options
author | Andrew Dunstan | 2005-11-19 17:39:45 +0000 |
---|---|---|
committer | Andrew Dunstan | 2005-11-19 17:39:45 +0000 |
commit | d25188b89c396e354c14c9d71551458ef8b90c3d (patch) | |
tree | a19a044b6017e99dfb123b03c3486d75bafb2ecd | |
parent | a699021b72a75ada179991456eb8b7139c6aad6c (diff) |
DROP objecttype IF EXISTS for the following objects:
table view index sequence schema type domain conversion
22 files changed, 417 insertions, 62 deletions
diff --git a/doc/src/sgml/ref/drop_conversion.sgml b/doc/src/sgml/ref/drop_conversion.sgml index 7b1503046e..2fcfa07aa1 100644 --- a/doc/src/sgml/ref/drop_conversion.sgml +++ b/doc/src/sgml/ref/drop_conversion.sgml @@ -17,7 +17,7 @@ <refsynopsisdiv> <synopsis> -DROP CONVERSION <replaceable>name</replaceable> [ CASCADE | RESTRICT ] +DROP CONVERSION [ IF EXISTS ] <replaceable>name</replaceable> [ CASCADE | RESTRICT ] </synopsis> </refsynopsisdiv> @@ -35,6 +35,16 @@ DROP CONVERSION <replaceable>name</replaceable> [ CASCADE | RESTRICT ] <variablelist> <varlistentry> + <term><literal>IF EXISTS</literal></term> + <listitem> + <para> + Do not throw an error if the conversion does not exist. + A notice is issued in this case. + </para> + </listitem> + </varlistentry> + + <varlistentry> <term><replaceable>name</replaceable></term> <listitem> diff --git a/doc/src/sgml/ref/drop_domain.sgml b/doc/src/sgml/ref/drop_domain.sgml index d6f1a64910..7120bcb3de 100644 --- a/doc/src/sgml/ref/drop_domain.sgml +++ b/doc/src/sgml/ref/drop_domain.sgml @@ -20,7 +20,7 @@ PostgreSQL documentation <refsynopsisdiv> <synopsis> -DROP DOMAIN <replaceable class="PARAMETER">name</replaceable> [, ...] [ CASCADE | RESTRICT ] +DROP DOMAIN [IF EXISTS ] <replaceable class="PARAMETER">name</replaceable> [, ...] [ CASCADE | RESTRICT ] </synopsis> </refsynopsisdiv> @@ -38,6 +38,16 @@ DROP DOMAIN <replaceable class="PARAMETER">name</replaceable> [, ...] [ CASCADE <variablelist> <varlistentry> + <term><literal>IF EXISTS</literal></term> + <listitem> + <para> + Do not throw an error if the domain does not exist. A notice is issued + in this case. + </para> + </listitem> + </varlistentry> + + <varlistentry> <term><replaceable class="PARAMETER">name</replaceable></term> <listitem> <para> @@ -84,7 +94,9 @@ DROP DOMAIN box; <title>Compatibility</title> <para> - This command conforms to the SQL standard. + This command conforms to the SQL standard, except for the + <literal>IF EXISTS</> option, which is a <productname>PostgreSQL</> + extension. </para> </refsect1> diff --git a/doc/src/sgml/ref/drop_index.sgml b/doc/src/sgml/ref/drop_index.sgml index 34f9e74c50..1dfb4be45a 100644 --- a/doc/src/sgml/ref/drop_index.sgml +++ b/doc/src/sgml/ref/drop_index.sgml @@ -20,7 +20,7 @@ PostgreSQL documentation <refsynopsisdiv> <synopsis> -DROP INDEX <replaceable class="PARAMETER">name</replaceable> [, ...] [ CASCADE | RESTRICT ] +DROP INDEX [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceable> [, ...] [ CASCADE | RESTRICT ] </synopsis> </refsynopsisdiv> @@ -39,6 +39,16 @@ DROP INDEX <replaceable class="PARAMETER">name</replaceable> [, ...] [ CASCADE | <variablelist> <varlistentry> + <term><literal>IF EXISTS</literal></term> + <listitem> + <para> + Do not throw an error if the index does not exist. A notice is issued + in this case. + </para> + </listitem> + </varlistentry> + + <varlistentry> <term><replaceable class="PARAMETER">name</replaceable></term> <listitem> <para> diff --git a/doc/src/sgml/ref/drop_schema.sgml b/doc/src/sgml/ref/drop_schema.sgml index 1fbb45d3e8..fed1effeea 100644 --- a/doc/src/sgml/ref/drop_schema.sgml +++ b/doc/src/sgml/ref/drop_schema.sgml @@ -20,7 +20,7 @@ PostgreSQL documentation <refsynopsisdiv> <synopsis> -DROP SCHEMA <replaceable class="PARAMETER">name</replaceable> [, ...] [ CASCADE | RESTRICT ] +DROP SCHEMA [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceable> [, ...] [ CASCADE | RESTRICT ] </synopsis> </refsynopsisdiv> @@ -43,6 +43,16 @@ DROP SCHEMA <replaceable class="PARAMETER">name</replaceable> [, ...] [ CASCADE <variablelist> <varlistentry> + <term><literal>IF EXISTS</literal></term> + <listitem> + <para> + Do not throw an error if the schema does not exist. A notice is issued + in this case. + </para> + </listitem> + </varlistentry> + + <varlistentry> <term><replaceable class="PARAMETER">name</replaceable></term> <listitem> <para> @@ -92,7 +102,9 @@ DROP SCHEMA mystuff CASCADE; <para> <command>DROP SCHEMA</command> is fully conforming with the SQL standard, except that the standard only allows one schema to be - dropped per command. + dropped per command, and apart from the + <literal>IF EXISTS</> option, which is a <productname>PostgreSQL</> + extension. </para> </refsect1> diff --git a/doc/src/sgml/ref/drop_sequence.sgml b/doc/src/sgml/ref/drop_sequence.sgml index f913270c22..e90737ac9e 100644 --- a/doc/src/sgml/ref/drop_sequence.sgml +++ b/doc/src/sgml/ref/drop_sequence.sgml @@ -20,7 +20,7 @@ PostgreSQL documentation <refsynopsisdiv> <synopsis> -DROP SEQUENCE <replaceable class="PARAMETER">name</replaceable> [, ...] [ CASCADE | RESTRICT ] +DROP SEQUENCE [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceable> [, ...] [ CASCADE | RESTRICT ] </synopsis> </refsynopsisdiv> @@ -37,6 +37,16 @@ DROP SEQUENCE <replaceable class="PARAMETER">name</replaceable> [, ...] [ CASCAD <variablelist> <varlistentry> + <term><literal>IF EXISTS</literal></term> + <listitem> + <para> + Do not throw an error if the sequence does not exist. A notice is issued + in this case. + </para> + </listitem> + </varlistentry> + + <varlistentry> <term><replaceable class="PARAMETER">name</replaceable></term> <listitem> <para> @@ -84,7 +94,9 @@ DROP SEQUENCE serial; <para> <command>DROP SEQUENCE</command> conforms to the <acronym>SQL</acronym> standard, except that the standard only allows one - sequence to be dropped per command. + sequence to be dropped per command, and apart from the + <literal>IF EXISTS</> option, which is a <productname>PostgreSQL</> + extension. </para> </refsect1> diff --git a/doc/src/sgml/ref/drop_table.sgml b/doc/src/sgml/ref/drop_table.sgml index 5d93a5302e..b52efe7ff3 100644 --- a/doc/src/sgml/ref/drop_table.sgml +++ b/doc/src/sgml/ref/drop_table.sgml @@ -20,7 +20,7 @@ PostgreSQL documentation <refsynopsisdiv> <synopsis> -DROP TABLE <replaceable class="PARAMETER">name</replaceable> [, ...] [ CASCADE | RESTRICT ] +DROP TABLE [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceable> [, ...] [ CASCADE | RESTRICT ] </synopsis> </refsynopsisdiv> @@ -49,6 +49,16 @@ DROP TABLE <replaceable class="PARAMETER">name</replaceable> [, ...] [ CASCADE | <variablelist> <varlistentry> + <term><literal>IF EXISTS</literal></term> + <listitem> + <para> + Do not throw an error if the table does not exist. A notice is issued + in this case. + </para> + </listitem> + </varlistentry> + + <varlistentry> <term><replaceable class="PARAMETER">name</replaceable></term> <listitem> <para> @@ -97,7 +107,9 @@ DROP TABLE films, distributors; <para> This command conforms to the SQL standard, except that the standard only - allows one table to be dropped per command. + allows one table to be dropped per command, and apart from the + <literal>IF EXISTS</> option, which is a <productname>PostgreSQL</> + extension. </para> </refsect1> diff --git a/doc/src/sgml/ref/drop_type.sgml b/doc/src/sgml/ref/drop_type.sgml index 669a38a594..808c25d7de 100644 --- a/doc/src/sgml/ref/drop_type.sgml +++ b/doc/src/sgml/ref/drop_type.sgml @@ -20,7 +20,7 @@ PostgreSQL documentation <refsynopsisdiv> <synopsis> -DROP TYPE <replaceable class="PARAMETER">name</replaceable> [, ...] [ CASCADE | RESTRICT ] +DROP TYPE [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceable> [, ...] [ CASCADE | RESTRICT ] </synopsis> </refsynopsisdiv> @@ -38,6 +38,16 @@ DROP TYPE <replaceable class="PARAMETER">name</replaceable> [, ...] [ CASCADE | <variablelist> <varlistentry> + <term><literal>IF EXISTS</literal></term> + <listitem> + <para> + Do not throw an error if the type does not exist. A notice is issued + in this case. + </para> + </listitem> + </varlistentry> + + <varlistentry> <term><replaceable class="PARAMETER">name</replaceable></term> <listitem> <para> @@ -84,7 +94,9 @@ DROP TYPE box; <para> This command is similar to the corresponding command in the SQL - standard, but note that the <command>CREATE TYPE</command> command + standard, aapart from the <literal>IF EXISTS</> + option, which is a <productname>PostgreSQL</> extension. + But note that the <command>CREATE TYPE</command> command and the data type extension mechanisms in <productname>PostgreSQL</productname> differ from the SQL standard. </para> diff --git a/doc/src/sgml/ref/drop_view.sgml b/doc/src/sgml/ref/drop_view.sgml index dab40539bc..8aeecd25a1 100644 --- a/doc/src/sgml/ref/drop_view.sgml +++ b/doc/src/sgml/ref/drop_view.sgml @@ -20,7 +20,7 @@ PostgreSQL documentation <refsynopsisdiv> <synopsis> -DROP VIEW <replaceable class="PARAMETER">name</replaceable> [, ...] [ CASCADE | RESTRICT ] +DROP VIEW [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceable> [, ...] [ CASCADE | RESTRICT ] </synopsis> </refsynopsisdiv> @@ -38,6 +38,16 @@ DROP VIEW <replaceable class="PARAMETER">name</replaceable> [, ...] [ CASCADE | <variablelist> <varlistentry> + <term><literal>IF EXISTS</literal></term> + <listitem> + <para> + Do not throw an error if the view does not exist. A notice is issued + in this case. + </para> + </listitem> + </varlistentry> + + <varlistentry> <term><replaceable class="PARAMETER">name</replaceable></term> <listitem> <para> @@ -84,7 +94,9 @@ DROP VIEW kinds; <para> This command conforms to the SQL standard, except that the standard only - allows one view to be dropped per command. + allows one view to be dropped per command, and apart from the + <literal>IF EXISTS</> option, which is a <productname>PostgreSQL</> + extension. </para> </refsect1> diff --git a/src/backend/commands/conversioncmds.c b/src/backend/commands/conversioncmds.c index de42788a91..69307277d2 100644 --- a/src/backend/commands/conversioncmds.c +++ b/src/backend/commands/conversioncmds.c @@ -98,16 +98,29 @@ CreateConversionCommand(CreateConversionStmt *stmt) * DROP CONVERSION */ void -DropConversionCommand(List *name, DropBehavior behavior) +DropConversionCommand(List *name, DropBehavior behavior, bool missing_ok) { Oid conversionOid; conversionOid = FindConversionByName(name); if (!OidIsValid(conversionOid)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("conversion \"%s\" does not exist", - NameListToString(name)))); + { + if (! missing_ok) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("conversion \"%s\" does not exist", + NameListToString(name)))); + } + else + { + ereport(NOTICE, + (errmsg("conversion \"%s\" does not exist, skipping", + NameListToString(name)))); + } + + return; + } ConversionDrop(conversionOid, behavior); } diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c index 25e914e838..5c87c15a9f 100644 --- a/src/backend/commands/schemacmds.c +++ b/src/backend/commands/schemacmds.c @@ -147,7 +147,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt) * Removes a schema. */ void -RemoveSchema(List *names, DropBehavior behavior) +RemoveSchema(List *names, DropBehavior behavior, bool missing_ok) { char *namespaceName; Oid namespaceId; @@ -163,9 +163,22 @@ RemoveSchema(List *names, DropBehavior behavior) CStringGetDatum(namespaceName), 0, 0, 0); if (!OidIsValid(namespaceId)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_SCHEMA), - errmsg("schema \"%s\" does not exist", namespaceName))); + { + if (!missing_ok) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_SCHEMA), + errmsg("schema \"%s\" does not exist", namespaceName))); + } + else + { + ereport(NOTICE, + (errmsg("schema \"%s\" does not exist, skipping", + namespaceName))); + } + + return; + } /* Permission check */ if (!pg_namespace_ownercheck(namespaceId, GetUserId())) diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index dc43babaad..90b22bf4a4 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -398,7 +398,7 @@ DefineType(List *names, List *parameters) * Removes a datatype. */ void -RemoveType(List *names, DropBehavior behavior) +RemoveType(List *names, DropBehavior behavior, bool missing_ok) { TypeName *typename; Oid typeoid; @@ -414,10 +414,23 @@ RemoveType(List *names, DropBehavior behavior) /* Use LookupTypeName here so that shell types can be removed. */ typeoid = LookupTypeName(typename); if (!OidIsValid(typeoid)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("type \"%s\" does not exist", - TypeNameToString(typename)))); + { + if (!missing_ok) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("type \"%s\" does not exist", + TypeNameToString(typename)))); + } + else + { + ereport(NOTICE, + (errmsg("type \"%s\" does not exist, skipping", + TypeNameToString(typename)))); + } + + return; + } tup = SearchSysCache(TYPEOID, ObjectIdGetDatum(typeoid), @@ -779,7 +792,7 @@ DefineDomain(CreateDomainStmt *stmt) * This is identical to RemoveType except we insist it be a domain. */ void -RemoveDomain(List *names, DropBehavior behavior) +RemoveDomain(List *names, DropBehavior behavior, bool missing_ok) { TypeName *typename; Oid typeoid; @@ -796,10 +809,23 @@ RemoveDomain(List *names, DropBehavior behavior) /* Use LookupTypeName here so that shell types can be removed. */ typeoid = LookupTypeName(typename); if (!OidIsValid(typeoid)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("type \"%s\" does not exist", - TypeNameToString(typename)))); + { + if (!missing_ok) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("type \"%s\" does not exist", + TypeNameToString(typename)))); + } + else + { + ereport(NOTICE, + (errmsg("type \"%s\" does not exist, skipping", + TypeNameToString(typename)))); + } + + return; + } tup = SearchSysCache(TYPEOID, ObjectIdGetDatum(typeoid), diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 27f2fc7765..11d3a4bfd5 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -173,7 +173,7 @@ static void doNegateFloat(Value *v); %type <ival> opt_lock lock_type cast_context %type <boolean> opt_force opt_or_replace opt_grant_grant_option opt_grant_admin_option - opt_nowait + opt_nowait %type <boolean> like_including_defaults @@ -362,7 +362,7 @@ static void doNegateFloat(Value *v); HANDLER HAVING HEADER HOLD HOUR_P - ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IN_P INCLUDING INCREMENT + IF_P ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IN_P INCLUDING INCREMENT INDEX INHERIT INHERITS INITIALLY INNER_P INOUT INPUT_P INSENSITIVE INSERT INSTEAD INT_P INTEGER INTERSECT INTERVAL INTO INVOKER IS ISNULL ISOLATION @@ -2818,20 +2818,32 @@ DropOpClassStmt: * * QUERY: * - * DROP itemtype itemname [, itemname ...] [ RESTRICT | CASCADE ] + * DROP itemtype [ IF EXISTS ] itemname [, itemname ...] + * [ RESTRICT | CASCADE ] * *****************************************************************************/ -DropStmt: DROP drop_type any_name_list opt_drop_behavior +DropStmt: DROP drop_type IF_P EXISTS any_name_list opt_drop_behavior { DropStmt *n = makeNode(DropStmt); n->removeType = $2; + n->missing_ok = TRUE; + n->objects = $5; + n->behavior = $6; + $$ = (Node *)n; + } + | DROP drop_type any_name_list opt_drop_behavior + { + DropStmt *n = makeNode(DropStmt); + n->removeType = $2; + n->missing_ok = FALSE; n->objects = $3; n->behavior = $4; $$ = (Node *)n; } ; + drop_type: TABLE { $$ = OBJECT_TABLE; } | SEQUENCE { $$ = OBJECT_SEQUENCE; } | VIEW { $$ = OBJECT_VIEW; } @@ -8159,6 +8171,7 @@ unreserved_keyword: | HEADER | HOLD | HOUR_P + | IF_P | IMMEDIATE | IMMUTABLE | IMPLICIT_P diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c index 95274cce2e..f2a060a3c7 100644 --- a/src/backend/parser/keywords.c +++ b/src/backend/parser/keywords.c @@ -160,6 +160,7 @@ static const ScanKeyword ScanKeywords[] = { {"header", HEADER}, {"hold", HOLD}, {"hour", HOUR_P}, + {"if",IF_P}, {"ilike", ILIKE}, {"immediate", IMMEDIATE}, {"immutable", IMMUTABLE}, diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 6a6bc6db95..790f3d0e67 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -67,6 +67,7 @@ struct msgstrings char kind; int nonexistent_code; const char *nonexistent_msg; + const char *skipping_msg; const char *nota_msg; const char *drophint_msg; }; @@ -75,26 +76,31 @@ static const struct msgstrings msgstringarray[] = { {RELKIND_RELATION, ERRCODE_UNDEFINED_TABLE, gettext_noop("table \"%s\" does not exist"), + gettext_noop("table \"%s\" does not exist, skipping"), gettext_noop("\"%s\" is not a table"), gettext_noop("Use DROP TABLE to remove a table.")}, {RELKIND_SEQUENCE, ERRCODE_UNDEFINED_TABLE, gettext_noop("sequence \"%s\" does not exist"), + gettext_noop("sequence \"%s\" does not exist, skipping"), gettext_noop("\"%s\" is not a sequence"), gettext_noop("Use DROP SEQUENCE to remove a sequence.")}, {RELKIND_VIEW, ERRCODE_UNDEFINED_TABLE, gettext_noop("view \"%s\" does not exist"), + gettext_noop("view \"%s\" does not exist, skipping"), gettext_noop("\"%s\" is not a view"), gettext_noop("Use DROP VIEW to remove a view.")}, {RELKIND_INDEX, ERRCODE_UNDEFINED_OBJECT, gettext_noop("index \"%s\" does not exist"), + gettext_noop("index \"%s\" does not exist, skipping"), gettext_noop("\"%s\" is not an index"), gettext_noop("Use DROP INDEX to remove an index.")}, {RELKIND_COMPOSITE_TYPE, ERRCODE_UNDEFINED_OBJECT, gettext_noop("type \"%s\" does not exist"), + gettext_noop("type \"%s\" does not exist, skipping"), gettext_noop("\"%s\" is not a type"), gettext_noop("Use DROP TYPE to remove a type.")}, {'\0', 0, NULL, NULL, NULL} @@ -132,23 +138,40 @@ DropErrorMsgWrongType(char *relname, char wrongkind, char rightkind) * non-existent relation */ static void -DropErrorMsgNonExistent(RangeVar *rel, char rightkind) +DropErrorMsgNonExistent(RangeVar *rel, char rightkind, bool missing_ok) { const struct msgstrings *rentry; for (rentry = msgstringarray; rentry->kind != '\0'; rentry++) { if (rentry->kind == rightkind) - ereport(ERROR, - (errcode(rentry->nonexistent_code), - errmsg(rentry->nonexistent_msg, rel->relname))); + { + if (! missing_ok) + { + ereport(ERROR, + (errcode(rentry->nonexistent_code), + errmsg(rentry->nonexistent_msg, rel->relname))); + } + else + { + ereport(NOTICE, (errmsg(rentry->skipping_msg, rel->relname))); + break; + } + } } - Assert(false); /* Should be impossible */ + Assert(rentry->kind != '\0'); /* Should be impossible */ } -static void -CheckDropPermissions(RangeVar *rel, char rightkind) +/* + * returns false if missing_ok is true and the object does not exist, + * true if object exists and permissions are OK, + * errors otherwise + * + */ + +static bool +CheckDropPermissions(RangeVar *rel, char rightkind, bool missing_ok) { Oid relOid; HeapTuple tuple; @@ -156,7 +179,10 @@ CheckDropPermissions(RangeVar *rel, char rightkind) relOid = RangeVarGetRelid(rel, true); if (!OidIsValid(relOid)) - DropErrorMsgNonExistent(rel, rightkind); + { + DropErrorMsgNonExistent(rel, rightkind, missing_ok); + return false; + } tuple = SearchSysCache(RELOID, ObjectIdGetDatum(relOid), @@ -183,6 +209,8 @@ CheckDropPermissions(RangeVar *rel, char rightkind) rel->relname))); ReleaseSysCache(tuple); + + return true; } /* @@ -528,31 +556,36 @@ ProcessUtility(Node *parsetree, { case OBJECT_TABLE: rel = makeRangeVarFromNameList(names); - CheckDropPermissions(rel, RELKIND_RELATION); - RemoveRelation(rel, stmt->behavior); + if (CheckDropPermissions(rel, RELKIND_RELATION, + stmt->missing_ok)) + RemoveRelation(rel, stmt->behavior); break; case OBJECT_SEQUENCE: rel = makeRangeVarFromNameList(names); - CheckDropPermissions(rel, RELKIND_SEQUENCE); - RemoveRelation(rel, stmt->behavior); + if (CheckDropPermissions(rel, RELKIND_SEQUENCE, + stmt->missing_ok)) + RemoveRelation(rel, stmt->behavior); break; case OBJECT_VIEW: rel = makeRangeVarFromNameList(names); - CheckDropPermissions(rel, RELKIND_VIEW); - RemoveView(rel, stmt->behavior); + if (CheckDropPermissions(rel, RELKIND_VIEW, + stmt->missing_ok)) + RemoveView(rel, stmt->behavior); break; case OBJECT_INDEX: rel = makeRangeVarFromNameList(names); - CheckDropPermissions(rel, RELKIND_INDEX); - RemoveIndex(rel, stmt->behavior); + if (CheckDropPermissions(rel, RELKIND_INDEX, + stmt->missing_ok)) + RemoveIndex(rel, stmt->behavior); break; case OBJECT_TYPE: /* RemoveType does its own permissions checks */ - RemoveType(names, stmt->behavior); + RemoveType(names, stmt->behavior, + stmt->missing_ok); break; case OBJECT_DOMAIN: @@ -560,11 +593,13 @@ ProcessUtility(Node *parsetree, /* * RemoveDomain does its own permissions checks */ - RemoveDomain(names, stmt->behavior); + RemoveDomain(names, stmt->behavior, + stmt->missing_ok); break; case OBJECT_CONVERSION: - DropConversionCommand(names, stmt->behavior); + DropConversionCommand(names, stmt->behavior, + stmt->missing_ok); break; case OBJECT_SCHEMA: @@ -572,7 +607,8 @@ ProcessUtility(Node *parsetree, /* * RemoveSchema does its own permissions checks */ - RemoveSchema(names, stmt->behavior); + RemoveSchema(names, stmt->behavior, + stmt->missing_ok); break; default: diff --git a/src/include/commands/conversioncmds.h b/src/include/commands/conversioncmds.h index 9ad0f839a3..be04ae2cc2 100644 --- a/src/include/commands/conversioncmds.h +++ b/src/include/commands/conversioncmds.h @@ -18,7 +18,8 @@ #include "nodes/parsenodes.h" extern void CreateConversionCommand(CreateConversionStmt *parsetree); -extern void DropConversionCommand(List *conversion_name, DropBehavior behavior); +extern void DropConversionCommand(List *conversion_name, + DropBehavior behavior, bool missing_ok); extern void RenameConversion(List *name, const char *newname); extern void AlterConversionOwner(List *name, Oid newOwnerId); diff --git a/src/include/commands/schemacmds.h b/src/include/commands/schemacmds.h index d35193d62c..96162a72a8 100644 --- a/src/include/commands/schemacmds.h +++ b/src/include/commands/schemacmds.h @@ -19,7 +19,7 @@ extern void CreateSchemaCommand(CreateSchemaStmt *parsetree); -extern void RemoveSchema(List *names, DropBehavior behavior); +extern void RemoveSchema(List *names, DropBehavior behavior, bool missing_ok); extern void RemoveSchemaById(Oid schemaOid); extern void RenameSchema(const char *oldname, const char *newname); diff --git a/src/include/commands/typecmds.h b/src/include/commands/typecmds.h index db3afc3269..a74b6f4c12 100644 --- a/src/include/commands/typecmds.h +++ b/src/include/commands/typecmds.h @@ -20,10 +20,10 @@ #define DEFAULT_TYPDELIM ',' extern void DefineType(List *names, List *parameters); -extern void RemoveType(List *names, DropBehavior behavior); +extern void RemoveType(List *names, DropBehavior behavior, bool missing_ok); extern void RemoveTypeById(Oid typeOid); extern void DefineDomain(CreateDomainStmt *stmt); -extern void RemoveDomain(List *names, DropBehavior behavior); +extern void RemoveDomain(List *names, DropBehavior behavior, bool missing_ok); extern Oid DefineCompositeType(const RangeVar *typevar, List *coldeflist); extern void AlterDomainDefault(List *names, Node *defaultRaw); diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 16fa572541..ed6f282150 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -1278,6 +1278,7 @@ typedef struct DropStmt List *objects; /* list of sublists of names (as Values) */ ObjectType removeType; /* object type */ DropBehavior behavior; /* RESTRICT or CASCADE behavior */ + bool missing_ok; /* skip error if object is missing? */ } DropStmt; /* ---------------------- diff --git a/src/test/regress/expected/drop_if_exists.out b/src/test/regress/expected/drop_if_exists.out new file mode 100644 index 0000000000..10feb3f986 --- /dev/null +++ b/src/test/regress/expected/drop_if_exists.out @@ -0,0 +1,67 @@ +-- +-- IF EXISTS tests +-- +-- table (will be really dropped at the end) +DROP TABLE test_exists; +ERROR: table "test_exists" does not exist +DROP TABLE IF EXISTS test_exists; +NOTICE: table "test_exists" does not exist, skipping +CREATE TABLE test_exists (a int, b text); +-- view +DROP VIEW test_view_exists; +ERROR: view "test_view_exists" does not exist +DROP VIEW IF EXISTS test_view_exists; +NOTICE: view "test_view_exists" does not exist, skipping +CREATE VIEW test_view_exists AS select * from test_exists; +DROP VIEW IF EXISTS test_view_exists; +DROP VIEW test_view_exists; +ERROR: view "test_view_exists" does not exist +-- index +DROP INDEX test_index_exists; +ERROR: index "test_index_exists" does not exist +DROP INDEX IF EXISTS test_index_exists; +NOTICE: index "test_index_exists" does not exist, skipping +CREATE INDEX test_index_exists on test_exists(a); +DROP INDEX IF EXISTS test_index_exists; +DROP INDEX test_index_exists; +ERROR: index "test_index_exists" does not exist +-- sequence +DROP SEQUENCE test_sequence_exists; +ERROR: sequence "test_sequence_exists" does not exist +DROP SEQUENCE IF EXISTS test_sequence_exists; +NOTICE: sequence "test_sequence_exists" does not exist, skipping +CREATE SEQUENCE test_sequence_exists; +DROP SEQUENCE IF EXISTS test_sequence_exists; +DROP SEQUENCE test_sequence_exists; +ERROR: sequence "test_sequence_exists" does not exist +-- schema +DROP SCHEMA test_schema_exists; +ERROR: schema "test_schema_exists" does not exist +DROP SCHEMA IF EXISTS test_schema_exists; +NOTICE: schema "test_schema_exists" does not exist, skipping +CREATE SCHEMA test_schema_exists; +DROP SCHEMA IF EXISTS test_schema_exists; +DROP SCHEMA test_schema_exists; +ERROR: schema "test_schema_exists" does not exist +-- type +DROP TYPE test_type_exists; +ERROR: type "test_type_exists" does not exist +DROP TYPE IF EXISTS test_type_exists; +NOTICE: type "test_type_exists" does not exist, skipping +CREATE type test_type_exists as (a int, b text); +DROP TYPE IF EXISTS test_type_exists; +DROP TYPE test_type_exists; +ERROR: type "test_type_exists" does not exist +-- domain +DROP DOMAIN test_domain_exists; +ERROR: type "test_domain_exists" does not exist +DROP DOMAIN IF EXISTS test_domain_exists; +NOTICE: type "test_domain_exists" does not exist, skipping +CREATE domain test_domain_exists as int not null check (value > 0); +DROP DOMAIN IF EXISTS test_domain_exists; +DROP DOMAIN test_domain_exists; +ERROR: type "test_domain_exists" does not exist +-- drop the table +DROP TABLE IF EXISTS test_exists; +DROP TABLE test_exists; +ERROR: table "test_exists" does not exist diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule index 3e52f6f558..d5777794bf 100644 --- a/src/test/regress/parallel_schedule +++ b/src/test/regress/parallel_schedule @@ -38,7 +38,7 @@ test: copy # ---------- # The third group of parallel test # ---------- -test: constraints triggers create_misc create_aggregate create_operator inherit vacuum +test: constraints triggers create_misc create_aggregate create_operator inherit vacuum drop_if_exists # Depends on the above test: create_index create_view diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule index ee90a1120f..95efa9dfe3 100644 --- a/src/test/regress/serial_schedule +++ b/src/test/regress/serial_schedule @@ -49,6 +49,7 @@ test: create_misc test: create_aggregate test: create_operator test: create_index +test: drop_if_exists test: inherit test: vacuum test: create_view diff --git a/src/test/regress/sql/drop_if_exists.sql b/src/test/regress/sql/drop_if_exists.sql new file mode 100644 index 0000000000..7addedaa73 --- /dev/null +++ b/src/test/regress/sql/drop_if_exists.sql @@ -0,0 +1,91 @@ +-- +-- IF EXISTS tests +-- + +-- table (will be really dropped at the end) + +DROP TABLE test_exists; + +DROP TABLE IF EXISTS test_exists; + +CREATE TABLE test_exists (a int, b text); + +-- view + +DROP VIEW test_view_exists; + +DROP VIEW IF EXISTS test_view_exists; + +CREATE VIEW test_view_exists AS select * from test_exists; + +DROP VIEW IF EXISTS test_view_exists; + +DROP VIEW test_view_exists; + +-- index + +DROP INDEX test_index_exists; + +DROP INDEX IF EXISTS test_index_exists; + +CREATE INDEX test_index_exists on test_exists(a); + +DROP INDEX IF EXISTS test_index_exists; + +DROP INDEX test_index_exists; + +-- sequence + +DROP SEQUENCE test_sequence_exists; + +DROP SEQUENCE IF EXISTS test_sequence_exists; + +CREATE SEQUENCE test_sequence_exists; + +DROP SEQUENCE IF EXISTS test_sequence_exists; + +DROP SEQUENCE test_sequence_exists; + +-- schema + +DROP SCHEMA test_schema_exists; + +DROP SCHEMA IF EXISTS test_schema_exists; + +CREATE SCHEMA test_schema_exists; + +DROP SCHEMA IF EXISTS test_schema_exists; + +DROP SCHEMA test_schema_exists; + +-- type + +DROP TYPE test_type_exists; + +DROP TYPE IF EXISTS test_type_exists; + +CREATE type test_type_exists as (a int, b text); + +DROP TYPE IF EXISTS test_type_exists; + +DROP TYPE test_type_exists; + +-- domain + +DROP DOMAIN test_domain_exists; + +DROP DOMAIN IF EXISTS test_domain_exists; + +CREATE domain test_domain_exists as int not null check (value > 0); + +DROP DOMAIN IF EXISTS test_domain_exists; + +DROP DOMAIN test_domain_exists; + +-- drop the table + + +DROP TABLE IF EXISTS test_exists; + +DROP TABLE test_exists; + |