deparse: Support EXTENSION commands
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Fri, 21 Feb 2014 21:11:35 +0000 (18:11 -0300)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Tue, 7 Apr 2015 17:09:36 +0000 (14:09 -0300)
CREATE EXTENSION
ALTER EXTENSION / UPDATE TO
ALTER EXTENSION ADD/DROP

src/backend/tcop/deparse_utility.c

index 44950077dc6f58d220124649f84b5fe38e8a468e..8fe8ae141b178609ece1aac9c9a7c632b239c5ff 100644 (file)
@@ -734,6 +734,147 @@ get_persistence_str(char persistence)
    }
 }
 
+/*
+ * deparse_CreateExtensionStmt
+ *     deparse a CreateExtensionStmt
+ *
+ * Given an extension OID and the parsetree that created it, return the JSON
+ * blob representing the creation command.
+ *
+ * XXX the current representation makes the output command dependant on the
+ * installed versions of the extension.  Is this a problem?
+ */
+static ObjTree *
+deparse_CreateExtensionStmt(Oid objectId, Node *parsetree)
+{
+   CreateExtensionStmt *node = (CreateExtensionStmt *) parsetree;
+   Relation    pg_extension;
+   HeapTuple   extTup;
+   Form_pg_extension extForm;
+   ObjTree    *extStmt;
+   ObjTree    *tmp;
+   List       *list;
+   ListCell   *cell;
+
+   pg_extension = heap_open(ExtensionRelationId, AccessShareLock);
+   extTup = get_catalog_object_by_oid(pg_extension, objectId);
+   if (!HeapTupleIsValid(extTup))
+       elog(ERROR, "cache lookup failed for extension with OID %u",
+            objectId);
+   extForm = (Form_pg_extension) GETSTRUCT(extTup);
+
+   extStmt = new_objtree_VA("CREATE EXTENSION %{if_not_exists}s %{identity}I "
+                            "%{options: }s",
+                            1, "identity", ObjTypeString, node->extname);
+   append_string_object(extStmt, "if_not_exists",
+                        node->if_not_exists ? "IF NOT EXISTS" : "");
+   list = NIL;
+   foreach(cell, node->options)
+   {
+       DefElem *opt = (DefElem *) lfirst(cell);
+
+       if (strcmp(opt->defname, "schema") == 0)
+       {
+           /* skip this one; we add one unconditionally below */
+           continue;
+       }
+       else if (strcmp(opt->defname, "new_version") == 0)
+       {
+           tmp = new_objtree_VA("VERSION %{version}L", 2,
+                                "type", ObjTypeString, "version",
+                                "version", ObjTypeString, defGetString(opt));
+           list = lappend(list, new_object_object(tmp));
+       }
+       else if (strcmp(opt->defname, "old_version") == 0)
+       {
+           tmp = new_objtree_VA("FROM %{version}L", 2,
+                                "type", ObjTypeString, "from",
+                                "version", ObjTypeString, defGetString(opt));
+           list = lappend(list, new_object_object(tmp));
+       }
+       else
+           elog(ERROR, "unsupported option %s", opt->defname);
+   }
+
+   tmp = new_objtree_VA("SCHEMA %{schema}I",
+                        2, "type", ObjTypeString, "schema",
+                        "schema", ObjTypeString,
+                        get_namespace_name(extForm->extnamespace));
+   list = lappend(list, new_object_object(tmp));
+
+   append_array_object(extStmt, "options", list);
+
+   heap_close(pg_extension, AccessShareLock);
+
+   return extStmt;
+}
+
+static ObjTree *
+deparse_AlterExtensionStmt(Oid objectId, Node *parsetree)
+{
+   AlterExtensionStmt *node = (AlterExtensionStmt *) parsetree;
+   Relation    pg_extension;
+   HeapTuple   extTup;
+   Form_pg_extension extForm;
+   ObjTree    *stmt;
+   ObjTree    *tmp;
+   List       *list = NIL;
+   ListCell   *cell;
+
+   pg_extension = heap_open(ExtensionRelationId, AccessShareLock);
+   extTup = get_catalog_object_by_oid(pg_extension, objectId);
+   if (!HeapTupleIsValid(extTup))
+       elog(ERROR, "cache lookup failed for extension with OID %u",
+            objectId);
+   extForm = (Form_pg_extension) GETSTRUCT(extTup);
+
+   stmt = new_objtree_VA("ALTER EXTENSION %{identity}I UPDATE %{options: }s", 1,
+                         "identity", ObjTypeString,
+                         NameStr(extForm->extname));
+
+   foreach(cell, node->options)
+   {
+       DefElem *opt = (DefElem *) lfirst(cell);
+
+       if (strcmp(opt->defname, "new_version") == 0)
+       {
+           tmp = new_objtree_VA("TO %{version}L", 2,
+                                "type", ObjTypeString, "version",
+                                "version", ObjTypeString, defGetString(opt));
+           list = lappend(list, new_object_object(tmp));
+       }
+       else
+           elog(ERROR, "unsupported option %s", opt->defname);
+   }
+
+   append_array_object(stmt, "options", list);
+
+   heap_close(pg_extension, AccessShareLock);
+
+   return stmt;
+}
+
+static ObjTree *
+deparse_AlterExtensionContentsStmt(Oid objectId, Node *parsetree,
+                                  ObjectAddress objectAddress)
+{
+   AlterExtensionContentsStmt *node = (AlterExtensionContentsStmt *) parsetree;
+   ObjTree    *stmt;
+   char       *fmt;
+
+   Assert(node->action == +1 || node->action == -1);
+
+   fmt = psprintf("ALTER EXTENSION %%{extidentity}I %s %s %%{objidentity}s",
+                  node->action == +1 ? "ADD" : "DROP",
+                  stringify_objtype(node->objtype));
+
+   stmt = new_objtree_VA(fmt, 2, "extidentity", ObjTypeString, node->extname,
+                         "objidentity", ObjTypeString,
+                         getObjectIdentity(&objectAddress));
+
+   return stmt;
+}
+
 /*
  * deparse_CreateTrigStmt
  *     Deparse a CreateTrigStmt (CREATE TRIGGER)
@@ -2148,15 +2289,16 @@ deparse_simple_command(StashedCommand *cmd)
            break;
 
        case T_CreateExtensionStmt:
-           elog(ERROR, "unimplemented deparse of %s", CreateCommandTag(parsetree));
+           command = deparse_CreateExtensionStmt(objectId, parsetree);
            break;
 
        case T_AlterExtensionStmt:
-           elog(ERROR, "unimplemented deparse of %s", CreateCommandTag(parsetree));
+           command = deparse_AlterExtensionStmt(objectId, parsetree);
            break;
 
        case T_AlterExtensionContentsStmt:
-           elog(ERROR, "unimplemented deparse of %s", CreateCommandTag(parsetree));
+           command = deparse_AlterExtensionContentsStmt(objectId, parsetree,
+                                                        cmd->d.simple.secondaryObject);
            break;
 
        case T_CreateFdwStmt: