>From 616e020966e0cd4bf1d531071b37b08fe5b96635 Mon Sep 17 00:00:00 2001 From: Alvaro Herrera Date: Fri, 21 Feb 2014 18:11:35 -0300 Subject: [PATCH 09/37] deparse: Support EXTENSION commands CREATE EXTENSION ALTER EXTENSION / UPDATE TO ALTER EXTENSION ADD/DROP --- src/backend/tcop/deparse_utility.c | 148 ++++++++++++++++++++++++++++++++++++- 1 file changed, 145 insertions(+), 3 deletions(-) diff --git a/src/backend/tcop/deparse_utility.c b/src/backend/tcop/deparse_utility.c index 4495007..8fe8ae1 100644 --- a/src/backend/tcop/deparse_utility.c +++ b/src/backend/tcop/deparse_utility.c @@ -735,6 +735,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: -- 2.1.4