drop if exists - Mailing list pgsql-patches

From Andrew Dunstan
Subject drop if exists
Date
Msg-id 43789E6D.9040009@dunslane.net
Whole thread Raw
Responses Re: drop if exists  (Michael Glaesemann <grzm@myrealbox.com>)
Re: drop if exists  (Tom Lane <tgl@sss.pgh.pa.us>)
List pgsql-patches
Ther attached patch is for comment. It implements "drop if exists" as
has recently been discussed. Illustration:

andrew=# drop table blurflx;
ERROR:  table "blurflx" does not exist
andrew=# drop table if exists blurflx;
DROP TABLE
andrew=# create table blurflx ( x text);
CREATE TABLE
andrew=# drop table if exists blurflx;
DROP TABLE
andrew=# drop table blurflx;
ERROR:  table "blurflx" does not exist
andrew=#

If the patch is acceptable I will work up some documentation and
regression tests.

cheers

andrew
Index: src/backend/commands/conversioncmds.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/commands/conversioncmds.c,v
retrieving revision 1.23
diff -c -r1.23 conversioncmds.c
*** src/backend/commands/conversioncmds.c    15 Oct 2005 02:49:15 -0000    1.23
--- src/backend/commands/conversioncmds.c    14 Nov 2005 14:09:52 -0000
***************
*** 98,113 ****
   * DROP CONVERSION
   */
  void
! DropConversionCommand(List *name, DropBehavior behavior)
  {
      Oid            conversionOid;

      conversionOid = FindConversionByName(name);
      if (!OidIsValid(conversionOid))
!         ereport(ERROR,
!                 (errcode(ERRCODE_UNDEFINED_OBJECT),
!                  errmsg("conversion \"%s\" does not exist",
!                         NameListToString(name))));

      ConversionDrop(conversionOid, behavior);
  }
--- 98,118 ----
   * DROP CONVERSION
   */
  void
! DropConversionCommand(List *name, DropBehavior behavior, bool missing_ok)
  {
      Oid            conversionOid;

      conversionOid = FindConversionByName(name);
      if (!OidIsValid(conversionOid))
!     {
!         if (missing_ok)
!             return;
!         else
!             ereport(ERROR,
!                     (errcode(ERRCODE_UNDEFINED_OBJECT),
!                      errmsg("conversion \"%s\" does not exist",
!                             NameListToString(name))));
!     }

      ConversionDrop(conversionOid, behavior);
  }
Index: src/backend/commands/schemacmds.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/commands/schemacmds.c,v
retrieving revision 1.35
diff -c -r1.35 schemacmds.c
*** src/backend/commands/schemacmds.c    15 Oct 2005 02:49:15 -0000    1.35
--- src/backend/commands/schemacmds.c    14 Nov 2005 14:09:52 -0000
***************
*** 147,153 ****
   *        Removes a schema.
   */
  void
! RemoveSchema(List *names, DropBehavior behavior)
  {
      char       *namespaceName;
      Oid            namespaceId;
--- 147,153 ----
   *        Removes a schema.
   */
  void
! RemoveSchema(List *names, DropBehavior behavior, bool missing_ok)
  {
      char       *namespaceName;
      Oid            namespaceId;
***************
*** 163,171 ****
                                   CStringGetDatum(namespaceName),
                                   0, 0, 0);
      if (!OidIsValid(namespaceId))
!         ereport(ERROR,
!                 (errcode(ERRCODE_UNDEFINED_SCHEMA),
!                  errmsg("schema \"%s\" does not exist", namespaceName)));

      /* Permission check */
      if (!pg_namespace_ownercheck(namespaceId, GetUserId()))
--- 163,176 ----
                                   CStringGetDatum(namespaceName),
                                   0, 0, 0);
      if (!OidIsValid(namespaceId))
!     {
!         if (missing_ok)
!             return;
!         else
!             ereport(ERROR,
!                     (errcode(ERRCODE_UNDEFINED_SCHEMA),
!                      errmsg("schema \"%s\" does not exist", namespaceName)));
!     }

      /* Permission check */
      if (!pg_namespace_ownercheck(namespaceId, GetUserId()))
Index: src/backend/commands/typecmds.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/commands/typecmds.c,v
retrieving revision 1.82
diff -c -r1.82 typecmds.c
*** src/backend/commands/typecmds.c    18 Oct 2005 01:06:24 -0000    1.82
--- src/backend/commands/typecmds.c    14 Nov 2005 14:09:54 -0000
***************
*** 398,404 ****
   *        Removes a datatype.
   */
  void
! RemoveType(List *names, DropBehavior behavior)
  {
      TypeName   *typename;
      Oid            typeoid;
--- 398,404 ----
   *        Removes a datatype.
   */
  void
! RemoveType(List *names, DropBehavior behavior, bool missing_ok)
  {
      TypeName   *typename;
      Oid            typeoid;
***************
*** 414,423 ****
      /* 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))));

      tup = SearchSysCache(TYPEOID,
                           ObjectIdGetDatum(typeoid),
--- 414,428 ----
      /* Use LookupTypeName here so that shell types can be removed. */
      typeoid = LookupTypeName(typename);
      if (!OidIsValid(typeoid))
!     {
!         if (missing_ok)
!             return;
!         else
!             ereport(ERROR,
!                     (errcode(ERRCODE_UNDEFINED_OBJECT),
!                      errmsg("type \"%s\" does not exist",
!                             TypeNameToString(typename))));
!     }

      tup = SearchSysCache(TYPEOID,
                           ObjectIdGetDatum(typeoid),
***************
*** 779,785 ****
   * This is identical to RemoveType except we insist it be a domain.
   */
  void
! RemoveDomain(List *names, DropBehavior behavior)
  {
      TypeName   *typename;
      Oid            typeoid;
--- 784,790 ----
   * This is identical to RemoveType except we insist it be a domain.
   */
  void
! RemoveDomain(List *names, DropBehavior behavior, bool missing_ok)
  {
      TypeName   *typename;
      Oid            typeoid;
***************
*** 796,805 ****
      /* 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))));

      tup = SearchSysCache(TYPEOID,
                           ObjectIdGetDatum(typeoid),
--- 801,815 ----
      /* Use LookupTypeName here so that shell types can be removed. */
      typeoid = LookupTypeName(typename);
      if (!OidIsValid(typeoid))
!     {
!         if (missing_ok)
!             return;
!         else
!             ereport(ERROR,
!                     (errcode(ERRCODE_UNDEFINED_OBJECT),
!                      errmsg("type \"%s\" does not exist",
!                             TypeNameToString(typename))));
!     }

      tup = SearchSysCache(TYPEOID,
                           ObjectIdGetDatum(typeoid),
Index: src/backend/parser/gram.y
===================================================================
RCS file: /cvsroot/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.511
diff -c -r2.511 gram.y
*** src/backend/parser/gram.y    23 Sep 2005 22:25:25 -0000    2.511
--- src/backend/parser/gram.y    14 Nov 2005 14:10:00 -0000
***************
*** 362,368 ****

      HANDLER HAVING HEADER HOLD HOUR_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
--- 362,368 ----

      HANDLER HAVING HEADER HOLD HOUR_P

!     IF 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
***************
*** 2822,2837 ****
   *
   *****************************************************************************/

! DropStmt:    DROP drop_type any_name_list opt_drop_behavior
                  {
                      DropStmt *n = makeNode(DropStmt);
                      n->removeType = $2;
                      n->objects = $3;
                      n->behavior = $4;
                      $$ = (Node *)n;
                  }
          ;

  drop_type:    TABLE                                    { $$ = OBJECT_TABLE; }
              | SEQUENCE                                { $$ = OBJECT_SEQUENCE; }
              | VIEW                                    { $$ = OBJECT_VIEW; }
--- 2822,2848 ----
   *
   *****************************************************************************/

! DropStmt:    DROP drop_type IF 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; }
***************
*** 8149,8154 ****
--- 8160,8166 ----
              | HEADER
              | HOLD
              | HOUR_P
+             | IF
              | IMMEDIATE
              | IMMUTABLE
              | IMPLICIT_P
Index: src/backend/parser/keywords.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/parser/keywords.c,v
retrieving revision 1.166
diff -c -r1.166 keywords.c
*** src/backend/parser/keywords.c    15 Oct 2005 02:49:22 -0000    1.166
--- src/backend/parser/keywords.c    14 Nov 2005 14:10:00 -0000
***************
*** 160,165 ****
--- 160,166 ----
      {"header", HEADER},
      {"hold", HOLD},
      {"hour", HOUR_P},
+     {"if",IF},
      {"ilike", ILIKE},
      {"immediate", IMMEDIATE},
      {"immutable", IMMUTABLE},
Index: src/backend/tcop/utility.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/tcop/utility.c,v
retrieving revision 1.245
diff -c -r1.245 utility.c
*** src/backend/tcop/utility.c    15 Oct 2005 02:49:27 -0000    1.245
--- src/backend/tcop/utility.c    14 Nov 2005 14:10:00 -0000
***************
*** 147,154 ****
      Assert(false);                /* Should be impossible */
  }

! static void
! CheckDropPermissions(RangeVar *rel, char rightkind)
  {
      Oid            relOid;
      HeapTuple    tuple;
--- 147,161 ----
      Assert(false);                /* Should be impossible */
  }

! /*
!  * 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,162 ****

      relOid = RangeVarGetRelid(rel, true);
      if (!OidIsValid(relOid))
!         DropErrorMsgNonExistent(rel, rightkind);

      tuple = SearchSysCache(RELOID,
                             ObjectIdGetDatum(relOid),
--- 163,174 ----

      relOid = RangeVarGetRelid(rel, true);
      if (!OidIsValid(relOid))
!     {
!         if (!missing_ok)
!             DropErrorMsgNonExistent(rel, rightkind);
!         else
!             return false;
!     }

      tuple = SearchSysCache(RELOID,
                             ObjectIdGetDatum(relOid),
***************
*** 183,188 ****
--- 195,202 ----
                          rel->relname)));

      ReleaseSysCache(tuple);
+
+     return true;
  }

  /*
***************
*** 528,558 ****
                      {
                          case OBJECT_TABLE:
                              rel = makeRangeVarFromNameList(names);
!                             CheckDropPermissions(rel, RELKIND_RELATION);
!                             RemoveRelation(rel, stmt->behavior);
                              break;

                          case OBJECT_SEQUENCE:
                              rel = makeRangeVarFromNameList(names);
!                             CheckDropPermissions(rel, RELKIND_SEQUENCE);
!                             RemoveRelation(rel, stmt->behavior);
                              break;

                          case OBJECT_VIEW:
                              rel = makeRangeVarFromNameList(names);
!                             CheckDropPermissions(rel, RELKIND_VIEW);
!                             RemoveView(rel, stmt->behavior);
                              break;

                          case OBJECT_INDEX:
                              rel = makeRangeVarFromNameList(names);
!                             CheckDropPermissions(rel, RELKIND_INDEX);
!                             RemoveIndex(rel, stmt->behavior);
                              break;

                          case OBJECT_TYPE:
                              /* RemoveType does its own permissions checks */
!                             RemoveType(names, stmt->behavior);
                              break;

                          case OBJECT_DOMAIN:
--- 542,577 ----
                      {
                          case OBJECT_TABLE:
                              rel = makeRangeVarFromNameList(names);
!                             if (CheckDropPermissions(rel, RELKIND_RELATION,
!                                                      stmt->missing_ok))
!                                 RemoveRelation(rel, stmt->behavior);
                              break;

                          case OBJECT_SEQUENCE:
                              rel = makeRangeVarFromNameList(names);
!                             if (CheckDropPermissions(rel, RELKIND_SEQUENCE,
!                                                      stmt->missing_ok))
!                                 RemoveRelation(rel, stmt->behavior);
                              break;

                          case OBJECT_VIEW:
                              rel = makeRangeVarFromNameList(names);
!                             if (CheckDropPermissions(rel, RELKIND_VIEW,
!                                                      stmt->missing_ok))
!                                 RemoveView(rel, stmt->behavior);
                              break;

                          case OBJECT_INDEX:
                              rel = makeRangeVarFromNameList(names);
!                             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,
!                                        stmt->missing_ok);
                              break;

                          case OBJECT_DOMAIN:
***************
*** 560,570 ****
                              /*
                               * RemoveDomain does its own permissions checks
                               */
!                             RemoveDomain(names, stmt->behavior);
                              break;

                          case OBJECT_CONVERSION:
!                             DropConversionCommand(names, stmt->behavior);
                              break;

                          case OBJECT_SCHEMA:
--- 579,591 ----
                              /*
                               * RemoveDomain does its own permissions checks
                               */
!                             RemoveDomain(names, stmt->behavior,
!                                          stmt->missing_ok);
                              break;

                          case OBJECT_CONVERSION:
!                             DropConversionCommand(names, stmt->behavior,
!                                                   stmt->missing_ok);
                              break;

                          case OBJECT_SCHEMA:
***************
*** 572,578 ****
                              /*
                               * RemoveSchema does its own permissions checks
                               */
!                             RemoveSchema(names, stmt->behavior);
                              break;

                          default:
--- 593,600 ----
                              /*
                               * RemoveSchema does its own permissions checks
                               */
!                             RemoveSchema(names, stmt->behavior,
!                                          stmt->missing_ok);
                              break;

                          default:
Index: src/include/commands/conversioncmds.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/commands/conversioncmds.h,v
retrieving revision 1.10
diff -c -r1.10 conversioncmds.h
*** src/include/commands/conversioncmds.h    28 Jun 2005 05:09:12 -0000    1.10
--- src/include/commands/conversioncmds.h    14 Nov 2005 14:10:02 -0000
***************
*** 18,24 ****
  #include "nodes/parsenodes.h"

  extern void CreateConversionCommand(CreateConversionStmt *parsetree);
! extern void DropConversionCommand(List *conversion_name, DropBehavior behavior);
  extern void RenameConversion(List *name, const char *newname);
  extern void AlterConversionOwner(List *name, Oid newOwnerId);

--- 18,25 ----
  #include "nodes/parsenodes.h"

  extern void CreateConversionCommand(CreateConversionStmt *parsetree);
! 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);

Index: src/include/commands/schemacmds.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/commands/schemacmds.h,v
retrieving revision 1.10
diff -c -r1.10 schemacmds.h
*** src/include/commands/schemacmds.h    28 Jun 2005 05:09:12 -0000    1.10
--- src/include/commands/schemacmds.h    14 Nov 2005 14:10:02 -0000
***************
*** 19,25 ****

  extern void CreateSchemaCommand(CreateSchemaStmt *parsetree);

! extern void RemoveSchema(List *names, DropBehavior behavior);
  extern void RemoveSchemaById(Oid schemaOid);

  extern void RenameSchema(const char *oldname, const char *newname);
--- 19,25 ----

  extern void CreateSchemaCommand(CreateSchemaStmt *parsetree);

! extern void RemoveSchema(List *names, DropBehavior behavior, bool missing_ok);
  extern void RemoveSchemaById(Oid schemaOid);

  extern void RenameSchema(const char *oldname, const char *newname);
Index: src/include/commands/typecmds.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/commands/typecmds.h,v
retrieving revision 1.14
diff -c -r1.14 typecmds.h
*** src/include/commands/typecmds.h    15 Oct 2005 02:49:44 -0000    1.14
--- src/include/commands/typecmds.h    14 Nov 2005 14:10:02 -0000
***************
*** 20,29 ****
  #define DEFAULT_TYPDELIM        ','

  extern void DefineType(List *names, List *parameters);
! extern void RemoveType(List *names, DropBehavior behavior);
  extern void RemoveTypeById(Oid typeOid);
  extern void DefineDomain(CreateDomainStmt *stmt);
! extern void RemoveDomain(List *names, DropBehavior behavior);
  extern Oid    DefineCompositeType(const RangeVar *typevar, List *coldeflist);

  extern void AlterDomainDefault(List *names, Node *defaultRaw);
--- 20,29 ----
  #define DEFAULT_TYPDELIM        ','

  extern void DefineType(List *names, List *parameters);
! 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, bool missing_ok);
  extern Oid    DefineCompositeType(const RangeVar *typevar, List *coldeflist);

  extern void AlterDomainDefault(List *names, Node *defaultRaw);
Index: src/include/nodes/parsenodes.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/nodes/parsenodes.h,v
retrieving revision 1.292
diff -c -r1.292 parsenodes.h
*** src/include/nodes/parsenodes.h    26 Oct 2005 19:21:55 -0000    1.292
--- src/include/nodes/parsenodes.h    14 Nov 2005 14:10:04 -0000
***************
*** 1278,1283 ****
--- 1278,1284 ----
      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;

  /* ----------------------

pgsql-patches by date:

Previous
From: "Stephen R. van den Berg"
Date:
Subject: contrib/xinetops for 8.1 "patch"
Next
From: Michael Glaesemann
Date:
Subject: Re: drop if exists