From 04bc7f99433cf05c197f95b695f187f9242ac2f6 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Tue, 27 Jun 2023 14:25:26 +0530
Subject: [PATCH 3/5] Code restructuring for supporting autogeneration code for
 create/alter and drop commands.

Code restructuring for supporting autogeneration code for create/alter
and drop commands.
---
 src/backend/commands/ddldeparse.c   | 1623 +-------------------------
 src/backend/nodes/Makefile          |    1 +
 src/backend/nodes/ddldeparsefuncs.c | 1636 +++++++++++++++++++++++++++
 src/backend/nodes/meson.build       |    1 +
 src/include/tcop/ddldeparse.h       |   42 +-
 5 files changed, 1697 insertions(+), 1606 deletions(-)
 create mode 100644 src/backend/nodes/ddldeparsefuncs.c

diff --git a/src/backend/commands/ddldeparse.c b/src/backend/commands/ddldeparse.c
index faaf0de3f9..3b1fe36a02 100644
--- a/src/backend/commands/ddldeparse.c
+++ b/src/backend/commands/ddldeparse.c
@@ -69,7 +69,7 @@
 /*
  * Return the string representation of the given RELPERSISTENCE value.
  */
-static char *
+char *
 get_persistence_str(char persistence)
 {
 	switch (persistence)
@@ -93,7 +93,7 @@ get_persistence_str(char persistence)
  * Caller must have set a correct deparse context and must ensure that the
  * passed attribute has a default value.
  */
-static char *
+char *
 RelationGetColumnDefault(Relation rel, AttrNumber attno, List *dpcontext)
 {
 	Node	   *defval;
@@ -110,7 +110,7 @@ RelationGetColumnDefault(Relation rel, AttrNumber attno, List *dpcontext)
 /*
  * Obtain the deparsed partition bound expression for the given table.
  */
-static char *
+char *
 RelationGetPartitionBound(Oid relid)
 {
 	Datum		deparsed;
@@ -138,7 +138,7 @@ RelationGetPartitionBound(Oid relid)
 /*
  * Insert JsonbValue key to the output parse state.
  */
-static void
+void
 insert_jsonb_key(JsonbParseState *state, char *name)
 {
 	JsonbValue	key;
@@ -170,7 +170,7 @@ insert_jsonb_key(JsonbParseState *state, char *name)
  * b) The caller need to carefully pass sets of arguments, we don't have the
  * luxury of sprintf-like compiler warnings for malformed argument lists.
  */
-static void
+void
 new_jsonb_VA(JsonbParseState *state, int numobjs,...)
 {
 	va_list		args;
@@ -241,7 +241,7 @@ new_jsonb_VA(JsonbParseState *state, int numobjs,...)
 /*
  * A helper routine to insert jsonb for typId to the output parse state.
  */
-static void
+void
 new_jsonb_for_type(JsonbParseState *state, char *parentKey,
 				   Oid typId, int32 typmod)
 {
@@ -311,7 +311,7 @@ new_jsonb_for_qualname(JsonbParseState *state, Oid nspid, char *objName,
  * A helper routine to set up name: 'schemaname, objname' where the object is
  * specified by classId and objId.
  */
-static void
+void
 new_jsonb_for_qualname_id(JsonbParseState *state, Oid classId, Oid objectId,
 						  char *keyName, bool createObject)
 {
@@ -353,7 +353,7 @@ new_jsonb_for_qualname_id(JsonbParseState *state, Oid classId, Oid objectId,
  * A helper routine to insert key:value where value is array of qualname to
  * the output parse state.
  */
-static void
+void
 new_jsonbArray_for_qualname_id(JsonbParseState *state,
 							   char *keyname, List *array)
 {
@@ -376,7 +376,7 @@ new_jsonbArray_for_qualname_id(JsonbParseState *state,
  * A helper routine to insert collate object for column
  * definition to the output parse state.
  */
-static void
+void
 insert_collate_object(JsonbParseState *state, char *parentKey, char *fmt,
 					  Oid classId, Oid objectId, char *key)
 {
@@ -400,7 +400,7 @@ insert_collate_object(JsonbParseState *state, char *parentKey, char *fmt,
  * A helper routine to insert identity object for the table definition
  * to the output parse state.
  */
-static void
+void
 insert_identity_object(JsonbParseState *state, Oid nspid, char *relname)
 {
 	new_jsonb_for_qualname(state, nspid, relname, "identity", true);
@@ -687,7 +687,7 @@ deparse_Seq_As_toJsonb(JsonbParseState *state, Form_pg_sequence seqdata)
  * 	OR
  * GENERATED %{option}s AS IDENTITY %{identity_type}s ( %{seq_definition: }s )
  */
-static void
+void
 deparse_ColumnIdentity_toJsonb(JsonbParseState *state, char *parentKey,
 							   Oid seqrelid, char identity, bool alter_table)
 {
@@ -769,7 +769,7 @@ deparse_ColumnIdentity_toJsonb(JsonbParseState *state, char *parentKey,
  * "%{name}I %{coltype}T STORAGE %{colstorage}s %{compression}s %{collation}s
  *  %{not_null}s %{default}s %{identity_column}s %{generated_column}s"
  */
-static void
+void
 deparse_ColumnDef_toJsonb(JsonbParseState *state, Relation relation,
 						  List *dpcontext, bool composite, ColumnDef *coldef,
 						  bool is_alter)
@@ -1267,7 +1267,7 @@ deparse_TableElems_ToJsonb(JsonbParseState *state, Relation relation,
  * Given a table OID, return a schema-qualified table list representing
  * the parent tables.
  */
-static List *
+List *
 deparse_InhRels_ToJsonb(Oid objectId)
 {
 	List	   *parents = NIL;
@@ -1425,7 +1425,7 @@ deparse_Constraints_ToJsonb(JsonbParseState *state, Oid relationId)
  * Insert columns and constraints elements in output JsonbParseState
  * Returns true if elements are inserted
  */
-static bool
+bool
 add_table_elems_if_any(JsonbParseState *state, StringInfo fmtStr,
 					   Relation relation, List *tableElts, List *dpcontext,
 					   Oid objectId, bool typed, bool composite)
@@ -1521,7 +1521,7 @@ deparse_DefElem_ToJsonb(JsonbParseState *state, DefElem *elem, bool is_reset)
  * Verbose syntax
  * ALTER COLUMN %{column}I RESET|SET (%{options:, }s)
  */
-static void
+void
 deparse_ColumnSetOptions_ToJsonb(JsonbParseState *state, AlterTableCmd *subcmd)
 {
 	ListCell   *cell;
@@ -1564,7 +1564,7 @@ deparse_ColumnSetOptions_ToJsonb(JsonbParseState *state, AlterTableCmd *subcmd)
  * Verbose syntax
  * RESET|SET (%{options:, }s)
  */
-static void
+void
 deparse_RelSetOptions_toJsonb(JsonbParseState *state, AlterTableCmd *subcmd)
 {
 	ListCell   *cell;
@@ -1604,7 +1604,7 @@ deparse_RelSetOptions_toJsonb(JsonbParseState *state, AlterTableCmd *subcmd)
 /*
  * Deparse WITH clause, as used by Create Table.
  */
-static void
+void
 deparse_withObj_ToJsonb(JsonbParseState *state, CreateStmt *node)
 {
 	ListCell   *cell;
@@ -1625,1593 +1625,6 @@ deparse_withObj_ToJsonb(JsonbParseState *state, CreateStmt *node)
 	pushJsonbValue(&state, WJB_END_ARRAY, NULL);
 }
 
-/*
- * Deparse a CreateStmt (CREATE TABLE).
- *
- * Given a table OID and the parse tree that created it, return JsonbValue
- * representing the creation command.
- *
- * Verbose syntax
- * CREATE %{persistence}s TABLE %{if_not_exists}s %{identity}D [OF
- * %{of_type}T | PARTITION OF %{parent_identity}D] %{table_elements}s
- * %{inherits}s %{partition_by}s %{access_method}s %{with_clause}s
- * %{tablespace}s
- */
-static Jsonb *
-deparse_CreateStmt(Oid objectId, Node *parsetree)
-{
-	CreateStmt *node = (CreateStmt *) parsetree;
-	Relation	relation = relation_open(objectId, AccessShareLock);
-	Oid			nspid = relation->rd_rel->relnamespace;
-	char	   *relname = RelationGetRelationName(relation);
-	List	   *dpcontext;
-	char	   *perstr;
-	StringInfoData fmtStr;
-	JsonbParseState *state = NULL;
-	JsonbValue *value;
-
-	initStringInfo(&fmtStr);
-
-	/* mark the begin of ROOT object and start adding elements to it. */
-	pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-
-	appendStringInfoString(&fmtStr, "CREATE");
-
-	/* PERSISTENCE */
-	perstr = get_persistence_str(relation->rd_rel->relpersistence);
-	if (perstr)
-	{
-		appendStringInfoString(&fmtStr, " %{persistence}s");
-		new_jsonb_VA(state, 1,
-					 "persistence", jbvString, perstr);
-	}
-
-	appendStringInfoString(&fmtStr, " TABLE");
-
-	/* IF NOT EXISTS */
-	if (node->if_not_exists)
-	{
-		appendStringInfoString(&fmtStr, " %{if_not_exists}s");
-		new_jsonb_VA(state, 1,
-					 "if_not_exists", jbvString, "IF NOT EXISTS");
-	}
-
-	/* IDENTITY */
-	appendStringInfoString(&fmtStr, " %{identity}D");
-	insert_identity_object(state, nspid, relname);
-
-	dpcontext = deparse_context_for(RelationGetRelationName(relation),
-									objectId);
-
-	/*
-	 * TABLE-ELEMENTS array creation
-	 *
-	 * Typed tables and partitions use a slightly different format string: we
-	 * must not put table_elements with parents directly in the fmt string,
-	 * because if there are no options the parentheses must not be emitted;
-	 * and also, typed tables do not allow for inheritance.
-	 */
-	if (node->ofTypename || node->partbound)
-	{
-		/* Insert the "of type" or "partition of" clause whichever present */
-		if (node->ofTypename)
-		{
-			appendStringInfoString(&fmtStr, " OF %{of_type}T");
-			new_jsonb_for_type(state, "of_type",
-							   relation->rd_rel->reloftype, -1);
-		}
-		else
-		{
-			List	   *parents;
-			Oid			objid;
-
-			appendStringInfoString(&fmtStr, " PARTITION OF %{parent_identity}D");
-			parents = deparse_InhRels_ToJsonb(objectId);
-			objid = linitial_oid(parents);
-			Assert(list_length(parents) == 1);
-			new_jsonb_for_qualname_id(state, RelationRelationId,
-									  objid, "parent_identity", true);
-		}
-
-		/*
-		 * We can't put table elements directly in the fmt string as an array
-		 * surrounded by parentheses here, because an empty clause would cause
-		 * a syntax error. Therefore, we first check the presence and then add
-		 * the elements.
-		 */
-		add_table_elems_if_any(state, &fmtStr, relation,
-							   node->tableElts, dpcontext, objectId,
-							   true,	/* typed table */
-							   false);	/* not composite */
-	}
-	else
-	{
-		List	   *inhrelations;
-		bool		telems_present = false;
-
-		/*
-		 * There is no need to process LIKE clauses separately; they have
-		 * already been transformed into columns and constraints.
-		 */
-
-		/* Check if table elements are present, if so, add them. */
-		telems_present = add_table_elems_if_any(state, &fmtStr, relation,
-												node->tableElts, dpcontext, objectId,
-												false,	/* not typed table */
-												false); /* not composite */
-
-		/*
-		 * If no table elements added, then add empty "()" needed for
-		 * 'inherit' create table syntax. Example: CREATE TABLE t1 () INHERITS
-		 * (t0);
-		 */
-		if (!telems_present)
-			appendStringInfoString(&fmtStr, " ()");
-
-		/*
-		 * Add inheritance specification.  We cannot simply scan the list of
-		 * parents from the parser node, because that may lack the actual
-		 * qualified names of the parent relations.  Rather than trying to
-		 * re-resolve them from the information in the parse node, it seems
-		 * more accurate and convenient to grab it from pg_inherits.
-		 */
-		if (node->inhRelations != NIL)
-		{
-			appendStringInfoString(&fmtStr, " %{inherits}s");
-			insert_jsonb_key(state, "inherits");
-
-			pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-
-			new_jsonb_VA(state, 1, "fmt", jbvString, "INHERITS (%{parents:, }D)");
-			inhrelations = deparse_InhRels_ToJsonb(objectId);
-
-			new_jsonbArray_for_qualname_id(state, "parents", inhrelations);
-			pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-		}
-	}
-
-	/* FOR VALUES clause */
-	if (node->partbound)
-	{
-		appendStringInfoString(&fmtStr, " %{partition_bound}s");
-
-		/*
-		 * Get pg_class.relpartbound. We cannot use partbound in the parsetree
-		 * directly as it's the original partbound expression which haven't
-		 * been transformed.
-		 */
-		new_jsonb_VA(state, 1,
-					 "partition_bound", jbvString,
-					 RelationGetPartitionBound(objectId));
-	}
-
-	/* PARTITION BY clause */
-	if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-	{
-		appendStringInfoString(&fmtStr, " %{partition_by}s");
-		insert_jsonb_key(state, "partition_by");
-		pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-
-		new_jsonb_VA(state, 2,
-					 "fmt", jbvString, "PARTITION BY %{definition}s",
-					 "definition", jbvString,
-					 pg_get_partkeydef_string(objectId));
-
-		pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-	}
-
-	/* USING clause */
-	if (node->accessMethod)
-	{
-		appendStringInfoString(&fmtStr, " %{access_method}s");
-		insert_jsonb_key(state, "access_method");
-		pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-
-		new_jsonb_VA(state, 2,
-					 "fmt", jbvString, "USING %{access_method}I",
-					 "access_method", jbvString, node->accessMethod);
-		pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-	}
-
-	/* WITH clause */
-	if (node->options)
-	{
-		appendStringInfoString(&fmtStr, " %{with_clause}s");
-		insert_jsonb_key(state, "with_clause");
-		pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-		new_jsonb_VA(state, 1,
-					 "fmt", jbvString, "WITH (%{with:, }s)");
-
-		deparse_withObj_ToJsonb(state, node);
-
-		pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-
-	}
-
-	/* TABLESPACE */
-	if (node->tablespacename)
-	{
-		appendStringInfoString(&fmtStr, " %{tablespace}s");
-		insert_jsonb_key(state, "tablespace");
-		pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-		new_jsonb_VA(state, 2,
-					 "fmt", jbvString, "TABLESPACE %{tablespace}I",
-					 "tablespace", jbvString, node->tablespacename);
-		pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-	}
-
-	relation_close(relation, AccessShareLock);
-
-	/* We have full fmt by now, so add jsonb element for that */
-	new_jsonb_VA(state, 1, "fmt", jbvString, fmtStr.data);
-
-	pfree(fmtStr.data);
-
-	/* Mark the end of ROOT object */
-	value = pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-
-	return JsonbValueToJsonb(value);
-}
-
-/*
- * Deparse a DropStmt (DROP TABLE).
- *
- * Given an object identity and the parse tree that created it, return
- * jsonb string representing the drop command.
- *
- * Verbose syntax
- * DROP %{objtype}s %{concurrently}s %{if_exists}s %{objidentity}s %{cascade}s
- */
-char *
-deparse_drop_table(const char *objidentity, const char *objecttype,
-				   Node *parsetree)
-{
-	DropStmt   *node = (DropStmt *) parsetree;
-	StringInfoData fmtStr;
-	JsonbValue *jsonbval;
-	Jsonb	   *jsonb;
-	StringInfoData str;
-	JsonbParseState *state = NULL;
-
-	initStringInfo(&str);
-	initStringInfo(&fmtStr);
-
-	/* mark the begin of ROOT object and start adding elements to it. */
-	pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-
-	/* Start constructing fmt string */
-	appendStringInfoString(&fmtStr, "DROP %{objtype}s");
-
-	/* OBJTYPE */
-	new_jsonb_VA(state, 1, "objtype", jbvString, objecttype);
-
-	/* CONCURRENTLY */
-	if (node->concurrent)
-	{
-		appendStringInfoString(&fmtStr, " %{concurrently}s");
-		new_jsonb_VA(state, 1,
-					 "concurrently", jbvString, "CONCURRENTLY");
-	}
-
-	/* IF EXISTS */
-	if (node->missing_ok)
-	{
-		appendStringInfoString(&fmtStr, " %{if_exists}s");
-		new_jsonb_VA(state, 1, "if_exists", jbvString, "IF EXISTS");
-	}
-
-	/* IDENTITY */
-	appendStringInfoString(&fmtStr, " %{objidentity}s");
-	new_jsonb_VA(state, 1, "objidentity", jbvString, objidentity);
-
-	/* CASCADE */
-	if (node->behavior == DROP_CASCADE)
-	{
-		appendStringInfoString(&fmtStr, " %{cascade}s");
-		new_jsonb_VA(state, 1, "cascade", jbvString, "CASCADE");
-	}
-
-	/* We have full fmt by now, so add jsonb element for that */
-	new_jsonb_VA(state, 1, "fmt", jbvString, fmtStr.data);
-	pfree(fmtStr.data);
-
-	jsonbval = pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-
-	jsonb = JsonbValueToJsonb(jsonbval);
-	return JsonbToCString(&str, &jsonb->root, JSONB_ESTIMATED_LEN);
-}
-
-/*
- * Deparse all the collected subcommands and return jsonb string representing
- * the alter command.
- *
- * Verbose syntax
- * ALTER %{objtype}s %{only}s %{identity}D %{subcmds:, }s
- */
-static Jsonb *
-deparse_AlterTableStmt(CollectedCommand *cmd)
-{
-	List	   *dpcontext;
-	Relation	rel;
-	ListCell   *cell;
-	const char *reltype;
-	Oid			relId = cmd->d.alterTable.objectId;
-	AlterTableStmt *stmt = NULL;
-	StringInfoData fmtStr;
-	JsonbParseState *state = NULL;
-	bool		subCmdArray = false;
-	JsonbValue *value;
-
-	Assert(cmd->type == SCT_AlterTable);
-	stmt = (AlterTableStmt *) cmd->parsetree;
-
-	Assert(IsA(stmt, AlterTableStmt) || IsA(stmt, AlterTableMoveAllStmt));
-
-	initStringInfo(&fmtStr);
-
-	/*
-	 * ALTER TABLE subcommands generated for TableLikeClause is processed in
-	 * the top level CREATE TABLE command; return empty here.
-	 */
-	if (IsA(stmt, AlterTableStmt) && stmt->table_like)
-		return NULL;
-
-	rel = relation_open(relId, AccessShareLock);
-
-	switch (rel->rd_rel->relkind)
-	{
-		case RELKIND_RELATION:
-		case RELKIND_PARTITIONED_TABLE:
-			reltype = "TABLE";
-			break;
-		case RELKIND_INDEX:
-		case RELKIND_PARTITIONED_INDEX:
-		case RELKIND_VIEW:
-		case RELKIND_COMPOSITE_TYPE:
-		case RELKIND_FOREIGN_TABLE:
-		case RELKIND_MATVIEW:
-			/* unsupported relkind */
-			table_close(rel, AccessShareLock);
-			return NULL;
-
-		default:
-			elog(ERROR, "unexpected relkind %d", rel->rd_rel->relkind);
-	}
-
-
-	dpcontext = deparse_context_for(RelationGetRelationName(rel), relId);
-
-	pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-
-	/* Start constructing fmt string */
-	appendStringInfoString(&fmtStr, "ALTER %{objtype}s");
-
-	new_jsonb_VA(state, 1, "objtype", jbvString, reltype);
-
-	if (!stmt->relation->inh)
-	{
-		appendStringInfoString(&fmtStr, " %{only}s");
-		new_jsonb_VA(state, 1, "only", jbvString, "ONLY");
-	}
-
-	appendStringInfoString(&fmtStr, " %{identity}D");
-	insert_identity_object(state, rel->rd_rel->relnamespace,
-						   RelationGetRelationName(rel));
-
-	foreach(cell, cmd->d.alterTable.subcmds)
-	{
-		CollectedATSubcmd *sub = (CollectedATSubcmd *) lfirst(cell);
-		AlterTableCmd *subcmd = (AlterTableCmd *) sub->parsetree;
-
-		Assert(IsA(subcmd, AlterTableCmd));
-
-		/*
-		 * Skip deparse of the subcommand if the objectId doesn't match the
-		 * target relation ID. It can happen for inherited tables when
-		 * subcommands for inherited tables and the parent table are both
-		 * collected in the ALTER TABLE command for the parent table.
-		 */
-		if (subcmd->subtype != AT_AttachPartition &&
-			sub->address.objectId != relId &&
-			has_superclass(sub->address.objectId))
-			continue;
-
-		/* Mark the begin of subcmds array */
-		if (!subCmdArray)
-		{
-			appendStringInfoString(&fmtStr, " %{subcmds:, }s");
-			insert_jsonb_key(state, "subcmds");
-			pushJsonbValue(&state, WJB_BEGIN_ARRAY, NULL);
-			subCmdArray = true;
-		}
-
-		switch (subcmd->subtype)
-		{
-			case AT_AddColumn:
-				{
-					StringInfoData fmtSub;
-
-					initStringInfo(&fmtSub);
-
-					/* XXX need to set the "recurse" bit somewhere? */
-					Assert(IsA(subcmd->def, ColumnDef));
-
-					/*
-					 * Syntax: ADD COLUMN %{if_not_exists}s %{definition}s"
-					 * where definition: "%{name}I %{coltype}T STORAGE
-					 * %{colstorage}s %{compression}s %{collation}s
-					 * %{not_null}s %{default}s %{identity_column}s
-					 * %{generated_column}s"
-					 */
-					pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-
-					appendStringInfoString(&fmtSub, "ADD COLUMN");
-					new_jsonb_VA(state, 1, "type", jbvString, "add column");
-
-					if (subcmd->missing_ok)
-					{
-						appendStringInfoString(&fmtSub, " %{if_not_exists}s");
-						new_jsonb_VA(state, 1,
-									 "if_not_exists", jbvString, "IF NOT EXISTS");
-					}
-
-					/* Push definition key-value pair */
-					appendStringInfoString(&fmtSub, " %{definition}s");
-					insert_jsonb_key(state, "definition");
-
-					deparse_ColumnDef_toJsonb(state, rel, dpcontext,
-											  false, (ColumnDef *) subcmd->def,
-											  true);
-
-					/* We have full fmt by now, so add jsonb element for that */
-					new_jsonb_VA(state, 1, "fmt", jbvString, fmtSub.data);
-					pfree(fmtSub.data);
-
-					pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-					break;
-				}
-
-			case AT_AddIndexConstraint:
-				{
-					IndexStmt  *istmt;
-					Relation	idx;
-					Oid			conOid = sub->address.objectId;
-
-					Assert(IsA(subcmd->def, IndexStmt));
-					istmt = (IndexStmt *) subcmd->def;
-
-					Assert(istmt->isconstraint && istmt->unique);
-
-					idx = relation_open(istmt->indexOid, AccessShareLock);
-
-					/*
-					 * Syntax: ADD CONSTRAINT %{name}I %{constraint_type}s
-					 * USING INDEX %index_name}I %{deferrable}s
-					 * %{init_deferred}s
-					 */
-					pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-
-					new_jsonb_VA(state, 7,
-								 "fmt", jbvString,
-								 "ADD CONSTRAINT %{name}I %{constraint_type}s"
-								 " USING INDEX %{index_name}I %{deferrable}s"
-								 " %{init_deferred}s",
-								 "type", jbvString, "add constraint using index",
-								 "name", jbvString, get_constraint_name(conOid),
-								 "constraint_type", jbvString,
-								 istmt->primary ? "PRIMARY KEY" : "UNIQUE",
-								 "index_name", jbvString,
-								 RelationGetRelationName(idx),
-								 "deferrable", jbvString,
-								 istmt->deferrable ? "DEFERRABLE" :
-								 "NOT DEFERRABLE",
-								 "init_deferred", jbvString,
-								 istmt->initdeferred ? "INITIALLY DEFERRED" :
-								 "INITIALLY IMMEDIATE");
-
-					pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-					relation_close(idx, AccessShareLock);
-					break;
-				}
-			case AT_ReAddIndex:
-			case AT_ReAddConstraint:
-			case AT_ReAddDomainConstraint:
-			case AT_ReAddComment:
-			case AT_ReplaceRelOptions:
-			case AT_CheckNotNull:
-			case AT_ReAddStatistics:
-				/* Subtypes used for internal operations; nothing to do here */
-				break;
-
-			case AT_ColumnDefault:
-				if (subcmd->def == NULL)
-				{
-					/*
-					 * Syntax: ALTER COLUMN %{column}I DROP DEFAULT
-					 */
-					pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-					new_jsonb_VA(state, 3,
-								 "fmt", jbvString,
-								 "ALTER COLUMN %{column}I DROP DEFAULT",
-								 "type", jbvString, "drop default",
-								 "column", jbvString, subcmd->name);
-					pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				}
-				else
-				{
-					List	   *dpcontext_rel;
-					HeapTuple	attrtup;
-					AttrNumber	attno;
-
-					dpcontext_rel = deparse_context_for(
-														RelationGetRelationName(rel),
-														RelationGetRelid(rel));
-					attrtup = SearchSysCacheAttName(RelationGetRelid(rel),
-													subcmd->name);
-					attno = ((Form_pg_attribute) GETSTRUCT(attrtup))->attnum;
-
-					/*
-					 * Syntax: ALTER COLUMN %{column}I SET DEFAULT
-					 * %{definition}s
-					 */
-					pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-
-					new_jsonb_VA(state, 4,
-								 "fmt", jbvString,
-								 "ALTER COLUMN %{column}I SET DEFAULT"
-								 " %{definition}s",
-								 "type", jbvString, "set default",
-								 "column", jbvString, subcmd->name,
-								 "definition", jbvString,
-								 RelationGetColumnDefault(rel, attno,
-														  dpcontext_rel));
-
-					pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-					ReleaseSysCache(attrtup);
-				}
-
-				break;
-
-			case AT_DropNotNull:
-
-				/*
-				 * Syntax: ALTER COLUMN %{column}I DROP NOT NULL
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 3,
-							 "fmt", jbvString,
-							 "ALTER COLUMN %{column}I DROP NOT NULL",
-							 "type", jbvString, "drop not null",
-							 "column", jbvString, subcmd->name);
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-
-			case AT_ForceRowSecurity:
-
-				/*
-				 * Syntax: FORCE ROW LEVEL SECURITY
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 1, "fmt", jbvString,
-							 "FORCE ROW LEVEL SECURITY");
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-
-			case AT_NoForceRowSecurity:
-
-				/*
-				 * Syntax: NO FORCE ROW LEVEL SECURITY
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 1, "fmt", jbvString,
-							 "NO FORCE ROW LEVEL SECURITY");
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-
-			case AT_SetNotNull:
-
-				/*
-				 * Syntax: ALTER COLUMN %{column}I SET NOT NULL
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 3,
-							 "fmt", jbvString,
-							 "ALTER COLUMN %{column}I SET NOT NULL",
-							 "type", jbvString, "set not null",
-							 "column", jbvString, subcmd->name);
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-
-			case AT_DropExpression:
-				{
-					StringInfoData fmtSub;
-
-					initStringInfo(&fmtSub);
-
-					/*
-					 * Syntax: ALTER COLUMN %{column}I DROP EXPRESSION
-					 * %{if_exists}s
-					 */
-					pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-					appendStringInfoString(&fmtSub, "ALTER COLUMN"
-										   " %{column}I DROP EXPRESSION");
-					new_jsonb_VA(state, 2,
-								 "type", jbvString, "drop expression",
-								 "column", jbvString, subcmd->name);
-
-					if (subcmd->missing_ok)
-					{
-						appendStringInfoString(&fmtSub, " %{if_exists}s");
-						new_jsonb_VA(state, 1,
-									 "if_exists", jbvString, "IF EXISTS");
-					}
-
-					/* We have full fmt by now, so add jsonb element for that */
-					new_jsonb_VA(state, 1, "fmt", jbvString, fmtSub.data);
-					pfree(fmtSub.data);
-
-					pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-					break;
-				}
-
-			case AT_SetStatistics:
-				Assert(IsA(subcmd->def, Integer));
-
-				/*
-				 * Syntax: ALTER COLUMN %{column}I SET STATISTICS
-				 * %{statistics}n
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 4,
-							 "fmt", jbvString,
-							 "ALTER COLUMN %{column}I SET STATISTICS"
-							 " %{statistics}n",
-							 "type", jbvString, "set statistics",
-							 "column", jbvString, subcmd->name,
-							 "statistics", jbvNumeric,
-							 intVal((Integer *) subcmd->def));
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-
-			case AT_SetOptions:
-			case AT_ResetOptions:
-
-				/*
-				 * Syntax: ALTER COLUMN %{column}I RESET|SET (%{options:, }s)
-				 */
-				deparse_ColumnSetOptions_ToJsonb(state, subcmd);
-				break;
-
-			case AT_SetStorage:
-				Assert(IsA(subcmd->def, String));
-
-				/*
-				 * Syntax: ALTER COLUMN %{column}I SET STORAGE %{storage}s
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 4,
-							 "fmt", jbvString,
-							 "ALTER COLUMN %{column}I SET STORAGE"
-							 " %{storage}s",
-							 "type", jbvString, "set storage",
-							 "column", jbvString, subcmd->name,
-							 "storage", jbvString,
-							 strVal((String *) subcmd->def));
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-
-			case AT_SetCompression:
-				Assert(IsA(subcmd->def, String));
-
-				/*
-				 * Syntax: ALTER COLUMN %{column}I SET COMPRESSION
-				 * %{compression_method}s
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 4,
-							 "fmt", jbvString,
-							 "ALTER COLUMN %{column}I SET COMPRESSION"
-							 " %{compression_method}s",
-							 "type", jbvString, "set compression",
-							 "column", jbvString, subcmd->name,
-							 "compression_method", jbvString,
-							 strVal((String *) subcmd->def));
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-
-			case AT_DropColumn:
-				{
-					StringInfoData fmtSub;
-
-					initStringInfo(&fmtSub);
-
-					/*
-					 * Syntax: DROP COLUMN %{if_exists}s %{column}I
-					 * %{cascade}s
-					 */
-					pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-
-					appendStringInfoString(&fmtSub, "DROP COLUMN");
-					new_jsonb_VA(state, 1, "type", jbvString, "drop column");
-
-					if (subcmd->missing_ok)
-					{
-						appendStringInfoString(&fmtSub, " %{if_exists}s");
-						new_jsonb_VA(state, 1,
-									 "if_exists", jbvString, "IF EXISTS");
-					}
-
-					appendStringInfoString(&fmtSub, " %{column}I");
-					new_jsonb_VA(state, 1, "column", jbvString, subcmd->name);
-
-					if (subcmd->behavior == DROP_CASCADE)
-					{
-						appendStringInfoString(&fmtSub, " %{cascade}s");
-						new_jsonb_VA(state, 1,
-									 "cascade", jbvString, "CASCADE");
-					}
-
-					/* We have full fmt by now, so add jsonb element for that */
-					new_jsonb_VA(state, 1, "fmt", jbvString, fmtSub.data);
-					pfree(fmtSub.data);
-
-					pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-
-					break;
-				}
-			case AT_AddIndex:
-				{
-					Oid			idxOid = sub->address.objectId;
-					IndexStmt  *istmt PG_USED_FOR_ASSERTS_ONLY =
-						(IndexStmt *) subcmd->def;
-					Relation	idx;
-					const char *idxname;
-					Oid			constrOid;
-
-					Assert(IsA(subcmd->def, IndexStmt));
-					Assert(istmt->isconstraint);
-
-					idx = relation_open(idxOid, AccessShareLock);
-					idxname = RelationGetRelationName(idx);
-
-					constrOid = get_relation_constraint_oid(
-															cmd->d.alterTable.objectId,
-															idxname, false);
-
-					/*
-					 * Syntax: ADD CONSTRAINT %{name}I %{definition}s
-					 */
-					pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-
-					new_jsonb_VA(state, 4,
-								 "fmt", jbvString,
-								 "ADD CONSTRAINT %{name}I %{definition}s",
-								 "type", jbvString, "add constraint",
-								 "name", jbvString, idxname,
-								 "definition", jbvString,
-								 pg_get_constraintdef_string(constrOid));
-
-					pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-
-					relation_close(idx, AccessShareLock);
-				}
-				break;
-			case AT_AddConstraint:
-				{
-					/* XXX need to set the "recurse" bit somewhere? */
-					Oid			constrOid = sub->address.objectId;
-
-					/* Skip adding constraint for inherits table sub command */
-					if (!OidIsValid(constrOid))
-						continue;
-
-					Assert(IsA(subcmd->def, Constraint));
-
-					/*
-					 * Syntax: ADD CONSTRAINT %{name}I %{definition}s
-					 */
-					pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-					new_jsonb_VA(state, 4,
-								 "fmt", jbvString,
-								 "ADD CONSTRAINT %{name}I %{definition}s",
-								 "type", jbvString, "add constraint",
-								 "name", jbvString, get_constraint_name(constrOid),
-								 "definition", jbvString,
-								 pg_get_constraintdef_string(constrOid));
-					pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-
-					break;
-				}
-
-			case AT_AlterConstraint:
-				{
-					Oid			conOid = sub->address.objectId;
-					Constraint *c = (Constraint *) subcmd->def;
-
-					/* If no constraint was altered, silently skip it */
-					if (!OidIsValid(conOid))
-						break;
-
-					Assert(IsA(c, Constraint));
-
-					/*
-					 * Syntax: ALTER CONSTRAINT %{name}I %{deferrable}s
-					 * %{init_deferred}s
-					 */
-					pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-					new_jsonb_VA(state, 5,
-								 "fmt", jbvString,
-								 "ALTER CONSTRAINT %{name}I %{deferrable}s"
-								 " %{init_deferred}s",
-								 "type", jbvString, "alter constraint",
-								 "name", jbvString, get_constraint_name(conOid),
-								 "deferrable", jbvString,
-								 c->deferrable ? "DEFERRABLE" : "NOT DEFERRABLE",
-								 "init_deferred", jbvString,
-								 c->initdeferred ? "INITIALLY DEFERRED" :
-								 "INITIALLY IMMEDIATE");
-					pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				}
-				break;
-
-			case AT_ValidateConstraint:
-
-				/*
-				 * Syntax: VALIDATE CONSTRAINT %{constraint}I
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 3,
-							 "fmt", jbvString,
-							 "VALIDATE CONSTRAINT %{constraint}I",
-							 "type", jbvString, "validate constraint",
-							 "constraint", jbvString, subcmd->name);
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-
-			case AT_DropConstraint:
-				{
-					StringInfoData fmtSub;
-
-					initStringInfo(&fmtSub);
-
-					/*
-					 * Syntax: DROP CONSTRAINT %{if_exists}s %{constraint}I
-					 * %{cascade}s
-					 */
-					pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-					appendStringInfoString(&fmtSub, "DROP CONSTRAINT");
-					new_jsonb_VA(state, 1, "type", jbvString, "drop constraint");
-
-					if (subcmd->missing_ok)
-					{
-						appendStringInfoString(&fmtSub, " %{if_exists}s");
-						new_jsonb_VA(state, 1,
-									 "if_exists", jbvString, "IF EXISTS");
-					}
-
-					appendStringInfoString(&fmtSub, " %{constraint}I");
-					new_jsonb_VA(state, 1,
-								 "constraint", jbvString, subcmd->name);
-
-					if (subcmd->behavior == DROP_CASCADE)
-					{
-						appendStringInfoString(&fmtSub, " %{cascade}s");
-						new_jsonb_VA(state, 1, "cascade", jbvString, "CASCADE");
-					}
-
-					/* We have full fmt by now, so add jsonb element for that */
-					new_jsonb_VA(state, 1, "fmt", jbvString, fmtSub.data);
-					pfree(fmtSub.data);
-
-					pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				}
-				break;
-
-			case AT_AlterColumnType:
-				{
-					TupleDesc	tupdesc = RelationGetDescr(rel);
-					Form_pg_attribute att;
-					ColumnDef  *def;
-					StringInfoData fmtSub;
-
-					initStringInfo(&fmtSub);
-
-					att = &(tupdesc->attrs[sub->address.objectSubId - 1]);
-					def = (ColumnDef *) subcmd->def;
-					Assert(IsA(def, ColumnDef));
-
-					/*
-					 * Syntax: ALTER COLUMN %{column}I SET DATA TYPE
-					 * %{datatype}T %{collation}s %{using}s where using: USING
-					 * %{expression}s
-					 */
-					pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-					appendStringInfoString(&fmtSub, "ALTER COLUMN %{column}I"
-										   " SET DATA TYPE %{datatype}T");
-					new_jsonb_VA(state, 2,
-								 "type", jbvString, "alter column type",
-								 "column", jbvString, subcmd->name);
-
-					new_jsonb_for_type(state, "datatype",
-									   att->atttypid, att->atttypmod);
-
-					/* Add a COLLATE clause, if needed */
-					if (OidIsValid(att->attcollation))
-					{
-						appendStringInfoString(&fmtSub, " %{collation}s");
-						insert_collate_object(state, "collation",
-											  "COLLATE %{name}D",
-											  CollationRelationId,
-											  att->attcollation, "name");
-					}
-
-					/*
-					 * If there's a USING clause, transformAlterTableStmt ran
-					 * it through transformExpr and stored the resulting node
-					 * in cooked_default, which we can use here.
-					 */
-					if (def->raw_default)
-					{
-						Datum		deparsed;
-						char	   *defexpr;
-						List	   *exprs = NIL;
-
-						exprs = lappend(exprs, def->cooked_default);
-						defexpr = nodeToString(def->cooked_default);
-						deparsed = DirectFunctionCall2(pg_get_expr,
-													   CStringGetTextDatum(defexpr),
-													   RelationGetRelid(rel));
-						appendStringInfoString(&fmtSub, " %{using}s");
-						insert_jsonb_key(state, "using");
-						pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-						new_jsonb_VA(state, 2,
-									 "fmt", jbvString, "USING %{expression}s",
-									 "expression", jbvString,
-									 TextDatumGetCString(deparsed));
-						pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-					}
-
-					/* We have full fmt by now, so add jsonb element for that */
-					new_jsonb_VA(state, 1, "fmt", jbvString, fmtSub.data);
-
-					pfree(fmtSub.data);
-					pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				}
-				break;
-
-			case AT_ChangeOwner:
-
-				/*
-				 * Syntax: OWNER TO %{owner}I
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 3,
-							 "fmt", jbvString, "OWNER TO %{owner}I",
-							 "type", jbvString, "change owner",
-							 "owner", jbvString,
-							 get_rolespec_name(subcmd->newowner));
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-
-			case AT_ClusterOn:
-
-				/*
-				 * Syntax: CLUSTER ON %{index}I
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 3,
-							 "fmt", jbvString, "CLUSTER ON %{index}I",
-							 "type", jbvString, "cluster on",
-							 "index", jbvString, subcmd->name);
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-
-
-			case AT_DropCluster:
-
-				/*
-				 * Syntax: SET WITHOUT CLUSTER
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 2,
-							 "fmt", jbvString, "SET WITHOUT CLUSTER",
-							 "type", jbvString, "set without cluster");
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-
-			case AT_SetLogged:
-
-				/*
-				 * Syntax: SET LOGGED
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 2,
-							 "fmt", jbvString, "SET LOGGED",
-							 "type", jbvString, "set logged");
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-
-			case AT_SetUnLogged:
-
-				/*
-				 * Syntax: SET UNLOGGED
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 2,
-							 "fmt", jbvString, "SET UNLOGGED",
-							 "type", jbvString, "set unlogged");
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-
-			case AT_DropOids:
-
-				/*
-				 * Syntax: SET WITHOUT OIDS
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 2,
-							 "fmt", jbvString, "SET WITHOUT OIDS",
-							 "type", jbvString, "set without oids");
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-
-			case AT_SetAccessMethod:
-
-				/*
-				 * Syntax: SET ACCESS METHOD %{access_method}I
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 3,
-							 "fmt", jbvString,
-							 "SET ACCESS METHOD %{access_method}I",
-							 "type", jbvString, "set access method",
-							 "access_method", jbvString, subcmd->name);
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-
-			case AT_SetTableSpace:
-
-				/*
-				 * Syntax: SET TABLESPACE %{tablespace}I
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 3,
-							 "fmt", jbvString, "SET TABLESPACE %{tablespace}I",
-							 "type", jbvString, "set tablespace",
-							 "tablespace", jbvString, subcmd->name);
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-
-			case AT_SetRelOptions:
-			case AT_ResetRelOptions:
-
-				/*
-				 * Syntax: SET|RESET (%{options:, }s)
-				 */
-				deparse_RelSetOptions_toJsonb(state, subcmd);
-				break;
-
-			case AT_EnableTrig:
-
-				/*
-				 * Syntax: ENABLE TRIGGER %{trigger}I
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 3,
-							 "fmt", jbvString, "ENABLE TRIGGER %{trigger}I",
-							 "type", jbvString, "enable trigger",
-							 "trigger", jbvString, subcmd->name);
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-
-			case AT_EnableAlwaysTrig:
-
-				/*
-				 * Syntax: ENABLE ALWAYS TRIGGER %{trigger}I
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 3,
-							 "fmt", jbvString,
-							 "ENABLE ALWAYS TRIGGER %{trigger}I",
-							 "type", jbvString, "enable always trigger",
-							 "trigger", jbvString, subcmd->name);
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-
-			case AT_EnableReplicaTrig:
-
-				/*
-				 * Syntax: ENABLE REPLICA TRIGGER %{trigger}I
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 3,
-							 "fmt", jbvString,
-							 "ENABLE REPLICA TRIGGER %{trigger}I",
-							 "type", jbvString, "enable replica trigger",
-							 "trigger", jbvString, subcmd->name);
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-
-			case AT_DisableTrig:
-
-				/*
-				 * Syntax: DISABLE TRIGGER %{trigger}I
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 3,
-							 "fmt", jbvString, "DISABLE TRIGGER %{trigger}I",
-							 "type", jbvString, "disable trigger",
-							 "trigger", jbvString, subcmd->name);
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-
-			case AT_EnableTrigAll:
-
-				/*
-				 * Syntax: ENABLE TRIGGER ALL
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 2,
-							 "fmt", jbvString, "ENABLE TRIGGER ALL",
-							 "type", jbvString, "enable trigger all");
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-
-			case AT_DisableTrigAll:
-
-				/*
-				 * Syntax: DISABLE TRIGGER ALL
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 2,
-							 "fmt", jbvString, "DISABLE TRIGGER ALL",
-							 "type", jbvString, "disable trigger all");
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-
-			case AT_EnableTrigUser:
-
-				/*
-				 * Syntax: ENABLE TRIGGER USER
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 2,
-							 "fmt", jbvString, "ENABLE TRIGGER USER",
-							 "type", jbvString, "enable trigger user");
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-
-			case AT_DisableTrigUser:
-
-				/*
-				 * Syntax: DISABLE TRIGGER USER
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 2,
-							 "fmt", jbvString, "DISABLE TRIGGER USER",
-							 "type", jbvString, "disable trigger user");
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-
-			case AT_EnableRule:
-
-				/*
-				 * Syntax: ENABLE RULE %{rule}I
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 3,
-							 "fmt", jbvString, "ENABLE RULE %{rule}I",
-							 "type", jbvString, "enable rule",
-							 "rule", jbvString, subcmd->name);
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-
-			case AT_EnableAlwaysRule:
-
-				/*
-				 * Syntax: ENABLE ALWAYS RULE %{rule}I
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 3,
-							 "fmt", jbvString, "ENABLE ALWAYS RULE %{rule}I",
-							 "type", jbvString, "enable always rule",
-							 "rule", jbvString, subcmd->name);
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-
-			case AT_EnableReplicaRule:
-
-				/*
-				 * Syntax: ENABLE REPLICA RULE %{rule}I
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 3,
-							 "fmt", jbvString, "ENABLE REPLICA RULE %{rule}I",
-							 "type", jbvString, "enable replica rule",
-							 "rule", jbvString, subcmd->name);
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-
-			case AT_DisableRule:
-
-				/*
-				 * Syntax: DISABLE RULE %{rule}I
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 3,
-							 "fmt", jbvString, "DISABLE RULE %{rule}I",
-							 "type", jbvString, "disable rule",
-							 "rule", jbvString, subcmd->name);
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-
-			case AT_AddInherit:
-
-				/*
-				 * Syntax: INHERIT %{parent}D
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 2,
-							 "fmt", jbvString, "INHERIT %{parent}D",
-							 "type", jbvString, "inherit");
-				new_jsonb_for_qualname_id(state, RelationRelationId,
-										  sub->address.objectId, "parent", true);
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-
-			case AT_DropInherit:
-
-				/*
-				 * Syntax: NO INHERIT %{parent}D
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 2,
-							 "fmt", jbvString, "NO INHERIT %{parent}D",
-							 "type", jbvString, "drop inherit");
-				new_jsonb_for_qualname_id(state, RelationRelationId,
-										  sub->address.objectId, "parent", true);
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-
-			case AT_AddOf:
-
-				/*
-				 * Syntax: OF %{type_of}T
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 2,
-							 "fmt", jbvString, "OF %{type_of}T",
-							 "type", jbvString, "add of");
-				new_jsonb_for_type(state, "type_of", sub->address.objectId, -1);
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-
-			case AT_DropOf:
-
-				/*
-				 * Syntax: NOT OF
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 2,
-							 "fmt", jbvString, "NOT OF",
-							 "type", jbvString, "not of");
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-
-			case AT_ReplicaIdentity:
-
-				/*
-				 * Syntax: REPLICA IDENTITY %{ident}s
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 2,
-							 "fmt", jbvString,
-							 "REPLICA IDENTITY %{ident}s",
-							 "type", jbvString, "replica identity");
-				switch (((ReplicaIdentityStmt *) subcmd->def)->identity_type)
-				{
-					case REPLICA_IDENTITY_DEFAULT:
-						new_jsonb_VA(state, 1, "ident", jbvString, "DEFAULT");
-						break;
-					case REPLICA_IDENTITY_FULL:
-						new_jsonb_VA(state, 1, "ident", jbvString, "FULL");
-						break;
-					case REPLICA_IDENTITY_NOTHING:
-						new_jsonb_VA(state, 1, "ident", jbvString, "NOTHING");
-						break;
-					case REPLICA_IDENTITY_INDEX:
-						insert_jsonb_key(state, "ident");
-						new_jsonb_VA(state, 2,
-									 "fmt", jbvString, "USING INDEX %{index}I",
-									 "index", jbvString,
-									 ((ReplicaIdentityStmt *) subcmd->def)->name);
-						break;
-				}
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-
-			case AT_EnableRowSecurity:
-
-				/*
-				 * Syntax: ENABLE ROW LEVEL SECURITY
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 2,
-							 "fmt", jbvString,
-							 "ENABLE ROW LEVEL SECURITY",
-							 "type", jbvString, "enable row security");
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-
-			case AT_DisableRowSecurity:
-
-				/*
-				 * Syntax: DISABLE ROW LEVEL SECURITY
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 2,
-							 "fmt", jbvString,
-							 "DISABLE ROW LEVEL SECURITY",
-							 "type", jbvString, "disable row security");
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-
-			case AT_AttachPartition:
-				{
-					StringInfoData fmtSub;
-
-					initStringInfo(&fmtSub);
-
-					/*
-					 * Syntax: ATTACH PARTITION %{partition_identity}D
-					 * %{partition_bound}s
-					 */
-					pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-					appendStringInfoString(&fmtSub, "ATTACH PARTITION"
-										   " %{partition_identity}D");
-
-					new_jsonb_VA(state, 1, "type", jbvString,
-								 "attach partition");
-					new_jsonb_for_qualname_id(state, RelationRelationId,
-											  sub->address.objectId,
-											  "partition_identity", true);
-
-					if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-					{
-						appendStringInfoString(&fmtSub, " %{partition_bound}s");
-						new_jsonb_VA(state, 1,
-									 "partition_bound", jbvString,
-									 RelationGetPartitionBound(sub->address.objectId));
-					}
-
-					/* We have full fmt by now, so add jsonb element for that */
-					new_jsonb_VA(state, 1, "fmt", jbvString, fmtSub.data);
-					pfree(fmtSub.data);
-
-					pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-
-					break;
-				}
-			case AT_DetachPartition:
-				{
-					PartitionCmd *cmd;
-					StringInfoData fmtSub;
-
-					initStringInfo(&fmtSub);
-
-					Assert(IsA(subcmd->def, PartitionCmd));
-					cmd = (PartitionCmd *) subcmd->def;
-
-					/*
-					 * Syntax: DETACH PARTITION %{partition_identity}D
-					 * %{concurrent}s
-					 */
-					pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-					appendStringInfoString(&fmtSub, "DETACH PARTITION"
-										   " %{partition_identity}D");
-
-					new_jsonb_VA(state, 1, "type", jbvString, "detach partition");
-					new_jsonb_for_qualname_id(state, RelationRelationId,
-											  sub->address.objectId,
-											  "partition_identity", true);
-					if (cmd->concurrent)
-					{
-						appendStringInfoString(&fmtSub, " %{concurrent}s");
-						new_jsonb_VA(state, 1,
-									 "concurrent", jbvString, "CONCURRENTLY");
-					}
-
-					/* We have full fmt by now, so add jsonb element for that */
-					new_jsonb_VA(state, 1, "fmt", jbvString, fmtSub.data);
-					pfree(fmtSub.data);
-
-					pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-					break;
-				}
-			case AT_DetachPartitionFinalize:
-
-				/*
-				 * Syntax: DETACH PARTITION %{partition_identity}D FINALIZE
-				 */
-				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-				new_jsonb_VA(state, 2,
-							 "fmt", jbvString, "DETACH PARTITION"
-							 " %{partition_identity}D FINALIZE",
-							 "type", jbvString, "detach partition finalize");
-
-				new_jsonb_for_qualname_id(state, RelationRelationId,
-										  sub->address.objectId,
-										  "partition_identity", true);
-				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				break;
-			case AT_AddIdentity:
-				{
-					AttrNumber	attnum;
-					Oid			seq_relid;
-					ColumnDef  *coldef = (ColumnDef *) subcmd->def;
-					StringInfoData fmtSub;
-
-					initStringInfo(&fmtSub);
-
-					/*
-					 * Syntax: ALTER COLUMN %{column}I %{definition}s where
-					 * definition : ADD %{identity_column}s where
-					 * identity_column: %{identity_type}s ( %{seq_definition:
-					 * }s )
-					 */
-					pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-
-					appendStringInfoString(&fmtSub, "ALTER COLUMN %{column}I");
-					new_jsonb_VA(state, 2,
-								 "type", jbvString, "add identity",
-								 "column", jbvString, subcmd->name);
-
-					attnum = get_attnum(RelationGetRelid(rel), subcmd->name);
-					seq_relid = getIdentitySequence(RelationGetRelid(rel),
-													attnum, true);
-
-					if (OidIsValid(seq_relid))
-					{
-
-						appendStringInfoString(&fmtSub, " %{definition}s");
-						insert_jsonb_key(state, "definition");
-
-						/* insert definition's value now */
-						pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-						new_jsonb_VA(state, 1,
-									 "fmt", jbvString, "ADD %{identity_column}s");
-
-						/* insert identity_column */
-						deparse_ColumnIdentity_toJsonb(state, "identity_column",
-													   seq_relid,
-													   coldef->identity, false);
-
-						/* mark definition's value end */
-						pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-					}
-
-					/* We have full fmt by now, so add jsonb element for that */
-					new_jsonb_VA(state, 1, "fmt", jbvString, fmtSub.data);
-
-					pfree(fmtSub.data);
-
-					pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-				}
-				break;
-			case AT_SetIdentity:
-				{
-					DefElem    *defel;
-					char		identity = 0;
-					AttrNumber	attnum;
-					Oid			seq_relid;
-					StringInfoData fmtSub;
-
-					initStringInfo(&fmtSub);
-
-					/*
-					 * Syntax: ALTER COLUMN %{column}I %{definition}s where
-					 * definition : %{identity_type}s ( %{seq_definition: }s )
-					 */
-					pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-
-					appendStringInfoString(&fmtSub, "ALTER COLUMN %{column}I");
-					new_jsonb_VA(state, 2,
-								 "type", jbvString, "set identity",
-								 "column", jbvString, subcmd->name);
-
-					if (subcmd->def)
-					{
-						List	   *def = (List *) subcmd->def;
-
-						Assert(IsA(subcmd->def, List));
-
-						defel = linitial_node(DefElem, def);
-						identity = defGetInt32(defel);
-					}
-
-					attnum = get_attnum(RelationGetRelid(rel), subcmd->name);
-					seq_relid = getIdentitySequence(RelationGetRelid(rel),
-													attnum, true);
-
-					if (OidIsValid(seq_relid))
-					{
-						appendStringInfoString(&fmtSub, " %{definition}s");
-						deparse_ColumnIdentity_toJsonb(state, "definition",
-													   seq_relid, identity,
-													   true);
-					}
-
-					/* We have full fmt by now, so add jsonb element for that */
-					new_jsonb_VA(state, 1, "fmt", jbvString, fmtSub.data);
-
-					pfree(fmtSub.data);
-					pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-
-					break;
-				}
-			case AT_DropIdentity:
-				{
-					StringInfoData fmtSub;
-
-					initStringInfo(&fmtSub);
-
-					/*
-					 * Syntax: ALTER COLUMN %{column}I DROP IDENTITY
-					 * %{if_exists}s
-					 */
-					pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
-					appendStringInfoString(&fmtSub, "ALTER COLUMN"
-										   " %{column}I DROP IDENTITY");
-					new_jsonb_VA(state, 2,
-								 "type", jbvString, "drop identity",
-								 "column", jbvString, subcmd->name);
-
-					if (subcmd->missing_ok)
-					{
-						appendStringInfoString(&fmtSub, " %{if_exists}s");
-						new_jsonb_VA(state, 1,
-									 "if_exists", jbvString, "IF EXISTS");
-					}
-
-					/* We have full fmt by now, so add jsonb element for that */
-					new_jsonb_VA(state, 1, "fmt", jbvString, fmtSub.data);
-					pfree(fmtSub.data);
-
-					pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-					break;
-				}
-			default:
-				elog(WARNING, "unsupported alter table subtype %d",
-					 subcmd->subtype);
-				break;
-		}
-	}
-
-	table_close(rel, AccessShareLock);
-
-	/* if subcmds array is not even created or has 0 elements, return NULL */
-	if (!subCmdArray ||
-		((state->contVal.type == jbvArray) &&
-		 (state->contVal.val.array.nElems == 0)))
-	{
-		pfree(fmtStr.data);
-		return NULL;
-	}
-
-	/* Mark the end of subcmds array */
-	pushJsonbValue(&state, WJB_END_ARRAY, NULL);
-
-	/* We have full fmt by now, so add jsonb element for that */
-	new_jsonb_VA(state, 1, "fmt", jbvString, fmtStr.data);
-
-	pfree(fmtStr.data);
-
-	/* Mark the end of ROOT object */
-	value = pushJsonbValue(&state, WJB_END_OBJECT, NULL);
-
-	return JsonbValueToJsonb(value);
-}
-
 /*
  * Deparse a CreateSeqStmt.
  *
@@ -3641,7 +2054,7 @@ deparse_simple_command(CollectedCommand *cmd)
 			return deparse_CreateSeqStmt(objectId, parsetree);
 
 		case T_CreateStmt:
-			return deparse_CreateStmt(objectId, parsetree);
+			return deparse_create_table(objectId, parsetree);
 		case T_RenameStmt:
 			return deparse_RenameStmt(cmd->d.simple.address, parsetree);
 
diff --git a/src/backend/nodes/Makefile b/src/backend/nodes/Makefile
index 0a95e683d0..a26607b9b1 100644
--- a/src/backend/nodes/Makefile
+++ b/src/backend/nodes/Makefile
@@ -17,6 +17,7 @@ override CPPFLAGS := -I. -I$(srcdir) $(CPPFLAGS)
 OBJS = \
 	bitmapset.o \
 	copyfuncs.o \
+	ddldeparsefuncs.o \
 	equalfuncs.o \
 	extensible.o \
 	list.o \
diff --git a/src/backend/nodes/ddldeparsefuncs.c b/src/backend/nodes/ddldeparsefuncs.c
new file mode 100644
index 0000000000..9cd42fd7e3
--- /dev/null
+++ b/src/backend/nodes/ddldeparsefuncs.c
@@ -0,0 +1,1636 @@
+/*-------------------------------------------------------------------------
+ *
+ * ddldeparsefuncs.c
+ *	 DDL deparsing.
+ *
+ * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  src/backend/nodes/ddldeparsefuncs.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/amapi.h"
+#include "access/relation.h"
+#include "access/table.h"
+#include "catalog/namespace.h"
+#include "catalog/pg_collation.h"
+#include "catalog/pg_constraint.h"
+#include "catalog/pg_depend.h"
+#include "catalog/pg_inherits.h"
+#include "catalog/pg_namespace.h"
+#include "catalog/pg_proc.h"
+#include "catalog/pg_type.h"
+#include "commands/defrem.h"
+#include "commands/sequence.h"
+#include "commands/tablespace.h"
+#include "commands/tablecmds.h"
+#include "funcapi.h"
+#include "optimizer/optimizer.h"
+#include "rewrite/rewriteHandler.h"
+#include "tcop/ddldeparse.h"
+#include "tcop/utility.h"
+#include "utils/builtins.h"
+#include "utils/fmgroids.h"
+#include "utils/guc.h"
+#include "utils/jsonb.h"
+#include "utils/lsyscache.h"
+#include "utils/rel.h"
+#include "utils/ruleutils.h"
+#include "utils/syscache.h"
+
+/* Estimated length of the generated jsonb string */
+#define JSONB_ESTIMATED_LEN 128
+
+extern bool		verbose;
+
+/*
+ * Deparse a CreateStmt (CREATE TABLE).
+ *
+ * Given a table OID and the parse tree that created it, return JsonbValue
+ * representing the creation command.
+ *
+ * Verbose syntax
+ * CREATE %{persistence}s TABLE %{if_not_exists}s %{identity}D [OF
+ * %{of_type}T | PARTITION OF %{parent_identity}D] %{table_elements}s
+ * %{inherits}s %{partition_by}s %{access_method}s %{with_clause}s
+ * %{tablespace}s
+ */
+Jsonb *
+deparse_create_table(Oid objectId, Node *parsetree)
+{
+	CreateStmt *node = (CreateStmt *) parsetree;
+	Relation	relation = relation_open(objectId, AccessShareLock);
+	Oid			nspid = relation->rd_rel->relnamespace;
+	char	   *relname = RelationGetRelationName(relation);
+	List	   *dpcontext;
+	char	   *perstr;
+	StringInfoData fmtStr;
+	JsonbParseState *state = NULL;
+	JsonbValue *value;
+
+	initStringInfo(&fmtStr);
+
+	/* mark the begin of ROOT object and start adding elements to it. */
+	pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+
+	appendStringInfoString(&fmtStr, "CREATE");
+
+	/* PERSISTENCE */
+	perstr = get_persistence_str(relation->rd_rel->relpersistence);
+	if (perstr)
+	{
+		appendStringInfoString(&fmtStr, " %{persistence}s");
+		new_jsonb_VA(state, 1,
+					 "persistence", jbvString, perstr);
+	}
+
+	appendStringInfoString(&fmtStr, " TABLE");
+
+	/* IF NOT EXISTS */
+	if (node->if_not_exists)
+	{
+		appendStringInfoString(&fmtStr, " %{if_not_exists}s");
+		new_jsonb_VA(state, 1,
+					 "if_not_exists", jbvString, "IF NOT EXISTS");
+	}
+
+	/* IDENTITY */
+	appendStringInfoString(&fmtStr, " %{identity}D");
+	insert_identity_object(state, nspid, relname);
+
+	dpcontext = deparse_context_for(RelationGetRelationName(relation),
+									objectId);
+
+	/*
+	 * TABLE-ELEMENTS array creation
+	 *
+	 * Typed tables and partitions use a slightly different format string: we
+	 * must not put table_elements with parents directly in the fmt string,
+	 * because if there are no options the parentheses must not be emitted;
+	 * and also, typed tables do not allow for inheritance.
+	 */
+	if (node->ofTypename || node->partbound)
+	{
+		/* Insert the "of type" or "partition of" clause whichever present */
+		if (node->ofTypename)
+		{
+			appendStringInfoString(&fmtStr, " OF %{of_type}T");
+			new_jsonb_for_type(state, "of_type",
+							   relation->rd_rel->reloftype, -1);
+		}
+		else
+		{
+			List	   *parents;
+			Oid			objid;
+
+			appendStringInfoString(&fmtStr, " PARTITION OF %{parent_identity}D");
+			parents = deparse_InhRels_ToJsonb(objectId);
+			objid = linitial_oid(parents);
+			Assert(list_length(parents) == 1);
+			new_jsonb_for_qualname_id(state, RelationRelationId,
+									  objid, "parent_identity", true);
+		}
+
+		/*
+		 * We can't put table elements directly in the fmt string as an array
+		 * surrounded by parentheses here, because an empty clause would cause
+		 * a syntax error. Therefore, we first check the presence and then add
+		 * the elements.
+		 */
+		add_table_elems_if_any(state, &fmtStr, relation,
+							   node->tableElts, dpcontext, objectId,
+							   true,	/* typed table */
+							   false);	/* not composite */
+	}
+	else
+	{
+		List	   *inhrelations;
+		bool		telems_present = false;
+
+		/*
+		 * There is no need to process LIKE clauses separately; they have
+		 * already been transformed into columns and constraints.
+		 */
+
+		/* Check if table elements are present, if so, add them. */
+		telems_present = add_table_elems_if_any(state, &fmtStr, relation,
+												node->tableElts, dpcontext, objectId,
+												false,	/* not typed table */
+												false); /* not composite */
+
+		/*
+		 * If no table elements added, then add empty "()" needed for
+		 * 'inherit' create table syntax. Example: CREATE TABLE t1 () INHERITS
+		 * (t0);
+		 */
+		if (!telems_present)
+			appendStringInfoString(&fmtStr, " ()");
+
+		/*
+		 * Add inheritance specification.  We cannot simply scan the list of
+		 * parents from the parser node, because that may lack the actual
+		 * qualified names of the parent relations.  Rather than trying to
+		 * re-resolve them from the information in the parse node, it seems
+		 * more accurate and convenient to grab it from pg_inherits.
+		 */
+		if (node->inhRelations != NIL)
+		{
+			appendStringInfoString(&fmtStr, " %{inherits}s");
+			insert_jsonb_key(state, "inherits");
+
+			pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+
+			new_jsonb_VA(state, 1, "fmt", jbvString, "INHERITS (%{parents:, }D)");
+			inhrelations = deparse_InhRels_ToJsonb(objectId);
+
+			new_jsonbArray_for_qualname_id(state, "parents", inhrelations);
+			pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+		}
+	}
+
+	/* FOR VALUES clause */
+	if (node->partbound)
+	{
+		appendStringInfoString(&fmtStr, " %{partition_bound}s");
+
+		/*
+		 * Get pg_class.relpartbound. We cannot use partbound in the parsetree
+		 * directly as it's the original partbound expression which haven't
+		 * been transformed.
+		 */
+		new_jsonb_VA(state, 1,
+					 "partition_bound", jbvString,
+					 RelationGetPartitionBound(objectId));
+	}
+
+	/* PARTITION BY clause */
+	if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+	{
+		appendStringInfoString(&fmtStr, " %{partition_by}s");
+		insert_jsonb_key(state, "partition_by");
+		pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+
+		new_jsonb_VA(state, 2,
+					 "fmt", jbvString, "PARTITION BY %{definition}s",
+					 "definition", jbvString,
+					 pg_get_partkeydef_string(objectId));
+
+		pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+	}
+
+	/* USING clause */
+	if (node->accessMethod)
+	{
+		appendStringInfoString(&fmtStr, " %{access_method}s");
+		insert_jsonb_key(state, "access_method");
+		pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+
+		new_jsonb_VA(state, 2,
+					 "fmt", jbvString, "USING %{access_method}I",
+					 "access_method", jbvString, node->accessMethod);
+		pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+	}
+
+	/* WITH clause */
+	if (node->options)
+	{
+		appendStringInfoString(&fmtStr, " %{with_clause}s");
+		insert_jsonb_key(state, "with_clause");
+		pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+		new_jsonb_VA(state, 1,
+					 "fmt", jbvString, "WITH (%{with:, }s)");
+
+		deparse_withObj_ToJsonb(state, node);
+
+		pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+
+	}
+
+	/* TABLESPACE */
+	if (node->tablespacename)
+	{
+		appendStringInfoString(&fmtStr, " %{tablespace}s");
+		insert_jsonb_key(state, "tablespace");
+		pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+		new_jsonb_VA(state, 2,
+					 "fmt", jbvString, "TABLESPACE %{tablespace}I",
+					 "tablespace", jbvString, node->tablespacename);
+		pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+	}
+
+	relation_close(relation, AccessShareLock);
+
+	/* We have full fmt by now, so add jsonb element for that */
+	new_jsonb_VA(state, 1, "fmt", jbvString, fmtStr.data);
+
+	pfree(fmtStr.data);
+
+	/* Mark the end of ROOT object */
+	value = pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+
+	return JsonbValueToJsonb(value);
+}
+
+/*
+ * Deparse a DropStmt (DROP TABLE).
+ *
+ * Given an object identity and the parse tree that created it, return
+ * jsonb string representing the drop command.
+ *
+ * Verbose syntax
+ * DROP %{objtype}s %{concurrently}s %{if_exists}s %{objidentity}s %{cascade}s
+ */
+char *
+deparse_drop_table(const char *objidentity, const char *objecttype,
+				   Node *parsetree)
+{
+	DropStmt   *node = (DropStmt *) parsetree;
+	StringInfoData fmtStr;
+	JsonbValue *jsonbval;
+	Jsonb	   *jsonb;
+	StringInfoData str;
+	JsonbParseState *state = NULL;
+
+	initStringInfo(&str);
+	initStringInfo(&fmtStr);
+
+	/* mark the begin of ROOT object and start adding elements to it. */
+	pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+
+	/* Start constructing fmt string */
+	appendStringInfoString(&fmtStr, "DROP %{objtype}s");
+
+	/* OBJTYPE */
+	new_jsonb_VA(state, 1, "objtype", jbvString, objecttype);
+
+	/* CONCURRENTLY */
+	if (node->concurrent)
+	{
+		appendStringInfoString(&fmtStr, " %{concurrently}s");
+		new_jsonb_VA(state, 1,
+					 "concurrently", jbvString, "CONCURRENTLY");
+	}
+
+	/* IF EXISTS */
+	if (node->missing_ok)
+	{
+		appendStringInfoString(&fmtStr, " %{if_exists}s");
+		new_jsonb_VA(state, 1, "if_exists", jbvString, "IF EXISTS");
+	}
+
+	/* IDENTITY */
+	appendStringInfoString(&fmtStr, " %{objidentity}s");
+	new_jsonb_VA(state, 1, "objidentity", jbvString, objidentity);
+
+	/* CASCADE */
+	if (node->behavior == DROP_CASCADE)
+	{
+		appendStringInfoString(&fmtStr, " %{cascade}s");
+		new_jsonb_VA(state, 1, "cascade", jbvString, "CASCADE");
+	}
+
+	/* We have full fmt by now, so add jsonb element for that */
+	new_jsonb_VA(state, 1, "fmt", jbvString, fmtStr.data);
+	pfree(fmtStr.data);
+
+	jsonbval = pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+
+	jsonb = JsonbValueToJsonb(jsonbval);
+	return JsonbToCString(&str, &jsonb->root, JSONB_ESTIMATED_LEN);
+}
+
+/*
+ * Deparse all the collected subcommands and return jsonb string representing
+ * the alter command.
+ *
+ * Verbose syntax
+ * ALTER %{objtype}s %{only}s %{identity}D %{subcmds:, }s
+ */
+Jsonb *
+deparse_AlterTableStmt(CollectedCommand *cmd)
+{
+	List	   *dpcontext;
+	Relation	rel;
+	ListCell   *cell;
+	const char *reltype;
+	Oid			relId = cmd->d.alterTable.objectId;
+	AlterTableStmt *stmt = NULL;
+	StringInfoData fmtStr;
+	JsonbParseState *state = NULL;
+	bool		subCmdArray = false;
+	JsonbValue *value;
+
+	Assert(cmd->type == SCT_AlterTable);
+	stmt = (AlterTableStmt *) cmd->parsetree;
+
+	Assert(IsA(stmt, AlterTableStmt) || IsA(stmt, AlterTableMoveAllStmt));
+
+	initStringInfo(&fmtStr);
+
+	/*
+	 * ALTER TABLE subcommands generated for TableLikeClause is processed in
+	 * the top level CREATE TABLE command; return empty here.
+	 */
+	if (IsA(stmt, AlterTableStmt) && stmt->table_like)
+		return NULL;
+
+	rel = relation_open(relId, AccessShareLock);
+
+	switch (rel->rd_rel->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			reltype = "TABLE";
+			break;
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_VIEW:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+			/* unsupported relkind */
+			table_close(rel, AccessShareLock);
+			return NULL;
+
+		default:
+			elog(ERROR, "unexpected relkind %d", rel->rd_rel->relkind);
+	}
+
+
+	dpcontext = deparse_context_for(RelationGetRelationName(rel), relId);
+
+	pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+
+	/* Start constructing fmt string */
+	appendStringInfoString(&fmtStr, "ALTER %{objtype}s");
+
+	new_jsonb_VA(state, 1, "objtype", jbvString, reltype);
+
+	if (!stmt->relation->inh)
+	{
+		appendStringInfoString(&fmtStr, " %{only}s");
+		new_jsonb_VA(state, 1, "only", jbvString, "ONLY");
+	}
+
+	appendStringInfoString(&fmtStr, " %{identity}D");
+	insert_identity_object(state, rel->rd_rel->relnamespace,
+						   RelationGetRelationName(rel));
+
+	foreach(cell, cmd->d.alterTable.subcmds)
+	{
+		CollectedATSubcmd *sub = (CollectedATSubcmd *) lfirst(cell);
+		AlterTableCmd *subcmd = (AlterTableCmd *) sub->parsetree;
+
+		Assert(IsA(subcmd, AlterTableCmd));
+
+		/*
+		 * Skip deparse of the subcommand if the objectId doesn't match the
+		 * target relation ID. It can happen for inherited tables when
+		 * subcommands for inherited tables and the parent table are both
+		 * collected in the ALTER TABLE command for the parent table.
+		 */
+		if (subcmd->subtype != AT_AttachPartition &&
+			sub->address.objectId != relId &&
+			has_superclass(sub->address.objectId))
+			continue;
+
+		/* Mark the begin of subcmds array */
+		if (!subCmdArray)
+		{
+			appendStringInfoString(&fmtStr, " %{subcmds:, }s");
+			insert_jsonb_key(state, "subcmds");
+			pushJsonbValue(&state, WJB_BEGIN_ARRAY, NULL);
+			subCmdArray = true;
+		}
+
+		switch (subcmd->subtype)
+		{
+			case AT_AddColumn:
+				{
+					StringInfoData fmtSub;
+
+					initStringInfo(&fmtSub);
+
+					/* XXX need to set the "recurse" bit somewhere? */
+					Assert(IsA(subcmd->def, ColumnDef));
+
+					/*
+					 * Syntax: ADD COLUMN %{if_not_exists}s %{definition}s"
+					 * where definition: "%{name}I %{coltype}T STORAGE
+					 * %{colstorage}s %{compression}s %{collation}s
+					 * %{not_null}s %{default}s %{identity_column}s
+					 * %{generated_column}s"
+					 */
+					pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+
+					appendStringInfoString(&fmtSub, "ADD COLUMN");
+					new_jsonb_VA(state, 1, "type", jbvString, "add column");
+
+					if (subcmd->missing_ok)
+					{
+						appendStringInfoString(&fmtSub, " %{if_not_exists}s");
+						new_jsonb_VA(state, 1,
+									 "if_not_exists", jbvString, "IF NOT EXISTS");
+					}
+
+					/* Push definition key-value pair */
+					appendStringInfoString(&fmtSub, " %{definition}s");
+					insert_jsonb_key(state, "definition");
+
+					deparse_ColumnDef_toJsonb(state, rel, dpcontext,
+											  false, (ColumnDef *) subcmd->def,
+											  true);
+
+					/* We have full fmt by now, so add jsonb element for that */
+					new_jsonb_VA(state, 1, "fmt", jbvString, fmtSub.data);
+					pfree(fmtSub.data);
+
+					pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+					break;
+				}
+
+			case AT_AddIndexConstraint:
+				{
+					IndexStmt  *istmt;
+					Relation	idx;
+					Oid			conOid = sub->address.objectId;
+
+					Assert(IsA(subcmd->def, IndexStmt));
+					istmt = (IndexStmt *) subcmd->def;
+
+					Assert(istmt->isconstraint && istmt->unique);
+
+					idx = relation_open(istmt->indexOid, AccessShareLock);
+
+					/*
+					 * Syntax: ADD CONSTRAINT %{name}I %{constraint_type}s
+					 * USING INDEX %index_name}I %{deferrable}s
+					 * %{init_deferred}s
+					 */
+					pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+
+					new_jsonb_VA(state, 7,
+								 "fmt", jbvString,
+								 "ADD CONSTRAINT %{name}I %{constraint_type}s"
+								 " USING INDEX %{index_name}I %{deferrable}s"
+								 " %{init_deferred}s",
+								 "type", jbvString, "add constraint using index",
+								 "name", jbvString, get_constraint_name(conOid),
+								 "constraint_type", jbvString,
+								 istmt->primary ? "PRIMARY KEY" : "UNIQUE",
+								 "index_name", jbvString,
+								 RelationGetRelationName(idx),
+								 "deferrable", jbvString,
+								 istmt->deferrable ? "DEFERRABLE" :
+								 "NOT DEFERRABLE",
+								 "init_deferred", jbvString,
+								 istmt->initdeferred ? "INITIALLY DEFERRED" :
+								 "INITIALLY IMMEDIATE");
+
+					pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+					relation_close(idx, AccessShareLock);
+					break;
+				}
+			case AT_ReAddIndex:
+			case AT_ReAddConstraint:
+			case AT_ReAddDomainConstraint:
+			case AT_ReAddComment:
+			case AT_ReplaceRelOptions:
+			case AT_CheckNotNull:
+			case AT_ReAddStatistics:
+				/* Subtypes used for internal operations; nothing to do here */
+				break;
+
+			case AT_ColumnDefault:
+				if (subcmd->def == NULL)
+				{
+					/*
+					 * Syntax: ALTER COLUMN %{column}I DROP DEFAULT
+					 */
+					pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+					new_jsonb_VA(state, 3,
+								 "fmt", jbvString,
+								 "ALTER COLUMN %{column}I DROP DEFAULT",
+								 "type", jbvString, "drop default",
+								 "column", jbvString, subcmd->name);
+					pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				}
+				else
+				{
+					List	   *dpcontext_rel;
+					HeapTuple	attrtup;
+					AttrNumber	attno;
+
+					dpcontext_rel = deparse_context_for(
+														RelationGetRelationName(rel),
+														RelationGetRelid(rel));
+					attrtup = SearchSysCacheAttName(RelationGetRelid(rel),
+													subcmd->name);
+					attno = ((Form_pg_attribute) GETSTRUCT(attrtup))->attnum;
+
+					/*
+					 * Syntax: ALTER COLUMN %{column}I SET DEFAULT
+					 * %{definition}s
+					 */
+					pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+
+					new_jsonb_VA(state, 4,
+								 "fmt", jbvString,
+								 "ALTER COLUMN %{column}I SET DEFAULT"
+								 " %{definition}s",
+								 "type", jbvString, "set default",
+								 "column", jbvString, subcmd->name,
+								 "definition", jbvString,
+								 RelationGetColumnDefault(rel, attno,
+														  dpcontext_rel));
+
+					pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+					ReleaseSysCache(attrtup);
+				}
+
+				break;
+
+			case AT_DropNotNull:
+
+				/*
+				 * Syntax: ALTER COLUMN %{column}I DROP NOT NULL
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 3,
+							 "fmt", jbvString,
+							 "ALTER COLUMN %{column}I DROP NOT NULL",
+							 "type", jbvString, "drop not null",
+							 "column", jbvString, subcmd->name);
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+
+			case AT_ForceRowSecurity:
+
+				/*
+				 * Syntax: FORCE ROW LEVEL SECURITY
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 1, "fmt", jbvString,
+							 "FORCE ROW LEVEL SECURITY");
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+
+			case AT_NoForceRowSecurity:
+
+				/*
+				 * Syntax: NO FORCE ROW LEVEL SECURITY
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 1, "fmt", jbvString,
+							 "NO FORCE ROW LEVEL SECURITY");
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+
+			case AT_SetNotNull:
+
+				/*
+				 * Syntax: ALTER COLUMN %{column}I SET NOT NULL
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 3,
+							 "fmt", jbvString,
+							 "ALTER COLUMN %{column}I SET NOT NULL",
+							 "type", jbvString, "set not null",
+							 "column", jbvString, subcmd->name);
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+
+			case AT_DropExpression:
+				{
+					StringInfoData fmtSub;
+
+					initStringInfo(&fmtSub);
+
+					/*
+					 * Syntax: ALTER COLUMN %{column}I DROP EXPRESSION
+					 * %{if_exists}s
+					 */
+					pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+					appendStringInfoString(&fmtSub, "ALTER COLUMN"
+										   " %{column}I DROP EXPRESSION");
+					new_jsonb_VA(state, 2,
+								 "type", jbvString, "drop expression",
+								 "column", jbvString, subcmd->name);
+
+					if (subcmd->missing_ok)
+					{
+						appendStringInfoString(&fmtSub, " %{if_exists}s");
+						new_jsonb_VA(state, 1,
+									 "if_exists", jbvString, "IF EXISTS");
+					}
+
+					/* We have full fmt by now, so add jsonb element for that */
+					new_jsonb_VA(state, 1, "fmt", jbvString, fmtSub.data);
+					pfree(fmtSub.data);
+
+					pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+					break;
+				}
+
+			case AT_SetStatistics:
+				Assert(IsA(subcmd->def, Integer));
+
+				/*
+				 * Syntax: ALTER COLUMN %{column}I SET STATISTICS
+				 * %{statistics}n
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 4,
+							 "fmt", jbvString,
+							 "ALTER COLUMN %{column}I SET STATISTICS"
+							 " %{statistics}n",
+							 "type", jbvString, "set statistics",
+							 "column", jbvString, subcmd->name,
+							 "statistics", jbvNumeric,
+							 intVal((Integer *) subcmd->def));
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+
+			case AT_SetOptions:
+			case AT_ResetOptions:
+
+				/*
+				 * Syntax: ALTER COLUMN %{column}I RESET|SET (%{options:, }s)
+				 */
+				deparse_ColumnSetOptions_ToJsonb(state, subcmd);
+				break;
+
+			case AT_SetStorage:
+				Assert(IsA(subcmd->def, String));
+
+				/*
+				 * Syntax: ALTER COLUMN %{column}I SET STORAGE %{storage}s
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 4,
+							 "fmt", jbvString,
+							 "ALTER COLUMN %{column}I SET STORAGE"
+							 " %{storage}s",
+							 "type", jbvString, "set storage",
+							 "column", jbvString, subcmd->name,
+							 "storage", jbvString,
+							 strVal((String *) subcmd->def));
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+
+			case AT_SetCompression:
+				Assert(IsA(subcmd->def, String));
+
+				/*
+				 * Syntax: ALTER COLUMN %{column}I SET COMPRESSION
+				 * %{compression_method}s
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 4,
+							 "fmt", jbvString,
+							 "ALTER COLUMN %{column}I SET COMPRESSION"
+							 " %{compression_method}s",
+							 "type", jbvString, "set compression",
+							 "column", jbvString, subcmd->name,
+							 "compression_method", jbvString,
+							 strVal((String *) subcmd->def));
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+
+			case AT_DropColumn:
+				{
+					StringInfoData fmtSub;
+
+					initStringInfo(&fmtSub);
+
+					/*
+					 * Syntax: DROP COLUMN %{if_exists}s %{column}I
+					 * %{cascade}s
+					 */
+					pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+
+					appendStringInfoString(&fmtSub, "DROP COLUMN");
+					new_jsonb_VA(state, 1, "type", jbvString, "drop column");
+
+					if (subcmd->missing_ok)
+					{
+						appendStringInfoString(&fmtSub, " %{if_exists}s");
+						new_jsonb_VA(state, 1,
+									 "if_exists", jbvString, "IF EXISTS");
+					}
+
+					appendStringInfoString(&fmtSub, " %{column}I");
+					new_jsonb_VA(state, 1, "column", jbvString, subcmd->name);
+
+					if (subcmd->behavior == DROP_CASCADE)
+					{
+						appendStringInfoString(&fmtSub, " %{cascade}s");
+						new_jsonb_VA(state, 1,
+									 "cascade", jbvString, "CASCADE");
+					}
+
+					/* We have full fmt by now, so add jsonb element for that */
+					new_jsonb_VA(state, 1, "fmt", jbvString, fmtSub.data);
+					pfree(fmtSub.data);
+
+					pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+
+					break;
+				}
+			case AT_AddIndex:
+				{
+					Oid			idxOid = sub->address.objectId;
+					IndexStmt  *istmt PG_USED_FOR_ASSERTS_ONLY =
+						(IndexStmt *) subcmd->def;
+					Relation	idx;
+					const char *idxname;
+					Oid			constrOid;
+
+					Assert(IsA(subcmd->def, IndexStmt));
+					Assert(istmt->isconstraint);
+
+					idx = relation_open(idxOid, AccessShareLock);
+					idxname = RelationGetRelationName(idx);
+
+					constrOid = get_relation_constraint_oid(
+															cmd->d.alterTable.objectId,
+															idxname, false);
+
+					/*
+					 * Syntax: ADD CONSTRAINT %{name}I %{definition}s
+					 */
+					pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+
+					new_jsonb_VA(state, 4,
+								 "fmt", jbvString,
+								 "ADD CONSTRAINT %{name}I %{definition}s",
+								 "type", jbvString, "add constraint",
+								 "name", jbvString, idxname,
+								 "definition", jbvString,
+								 pg_get_constraintdef_string(constrOid));
+
+					pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+
+					relation_close(idx, AccessShareLock);
+				}
+				break;
+			case AT_AddConstraint:
+				{
+					/* XXX need to set the "recurse" bit somewhere? */
+					Oid			constrOid = sub->address.objectId;
+
+					/* Skip adding constraint for inherits table sub command */
+					if (!OidIsValid(constrOid))
+						continue;
+
+					Assert(IsA(subcmd->def, Constraint));
+
+					/*
+					 * Syntax: ADD CONSTRAINT %{name}I %{definition}s
+					 */
+					pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+					new_jsonb_VA(state, 4,
+								 "fmt", jbvString,
+								 "ADD CONSTRAINT %{name}I %{definition}s",
+								 "type", jbvString, "add constraint",
+								 "name", jbvString, get_constraint_name(constrOid),
+								 "definition", jbvString,
+								 pg_get_constraintdef_string(constrOid));
+					pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+
+					break;
+				}
+
+			case AT_AlterConstraint:
+				{
+					Oid			conOid = sub->address.objectId;
+					Constraint *c = (Constraint *) subcmd->def;
+
+					/* If no constraint was altered, silently skip it */
+					if (!OidIsValid(conOid))
+						break;
+
+					Assert(IsA(c, Constraint));
+
+					/*
+					 * Syntax: ALTER CONSTRAINT %{name}I %{deferrable}s
+					 * %{init_deferred}s
+					 */
+					pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+					new_jsonb_VA(state, 5,
+								 "fmt", jbvString,
+								 "ALTER CONSTRAINT %{name}I %{deferrable}s"
+								 " %{init_deferred}s",
+								 "type", jbvString, "alter constraint",
+								 "name", jbvString, get_constraint_name(conOid),
+								 "deferrable", jbvString,
+								 c->deferrable ? "DEFERRABLE" : "NOT DEFERRABLE",
+								 "init_deferred", jbvString,
+								 c->initdeferred ? "INITIALLY DEFERRED" :
+								 "INITIALLY IMMEDIATE");
+					pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				}
+				break;
+
+			case AT_ValidateConstraint:
+
+				/*
+				 * Syntax: VALIDATE CONSTRAINT %{constraint}I
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 3,
+							 "fmt", jbvString,
+							 "VALIDATE CONSTRAINT %{constraint}I",
+							 "type", jbvString, "validate constraint",
+							 "constraint", jbvString, subcmd->name);
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+
+			case AT_DropConstraint:
+				{
+					StringInfoData fmtSub;
+
+					initStringInfo(&fmtSub);
+
+					/*
+					 * Syntax: DROP CONSTRAINT %{if_exists}s %{constraint}I
+					 * %{cascade}s
+					 */
+					pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+					appendStringInfoString(&fmtSub, "DROP CONSTRAINT");
+					new_jsonb_VA(state, 1, "type", jbvString, "drop constraint");
+
+					if (subcmd->missing_ok)
+					{
+						appendStringInfoString(&fmtSub, " %{if_exists}s");
+						new_jsonb_VA(state, 1,
+									 "if_exists", jbvString, "IF EXISTS");
+					}
+
+					appendStringInfoString(&fmtSub, " %{constraint}I");
+					new_jsonb_VA(state, 1,
+								 "constraint", jbvString, subcmd->name);
+
+					if (subcmd->behavior == DROP_CASCADE)
+					{
+						appendStringInfoString(&fmtSub, " %{cascade}s");
+						new_jsonb_VA(state, 1, "cascade", jbvString, "CASCADE");
+					}
+
+					/* We have full fmt by now, so add jsonb element for that */
+					new_jsonb_VA(state, 1, "fmt", jbvString, fmtSub.data);
+					pfree(fmtSub.data);
+
+					pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				}
+				break;
+
+			case AT_AlterColumnType:
+				{
+					TupleDesc	tupdesc = RelationGetDescr(rel);
+					Form_pg_attribute att;
+					ColumnDef  *def;
+					StringInfoData fmtSub;
+
+					initStringInfo(&fmtSub);
+
+					att = &(tupdesc->attrs[sub->address.objectSubId - 1]);
+					def = (ColumnDef *) subcmd->def;
+					Assert(IsA(def, ColumnDef));
+
+					/*
+					 * Syntax: ALTER COLUMN %{column}I SET DATA TYPE
+					 * %{datatype}T %{collation}s %{using}s where using: USING
+					 * %{expression}s
+					 */
+					pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+					appendStringInfoString(&fmtSub, "ALTER COLUMN %{column}I"
+										   " SET DATA TYPE %{datatype}T");
+					new_jsonb_VA(state, 2,
+								 "type", jbvString, "alter column type",
+								 "column", jbvString, subcmd->name);
+
+					new_jsonb_for_type(state, "datatype",
+									   att->atttypid, att->atttypmod);
+
+					/* Add a COLLATE clause, if needed */
+					if (OidIsValid(att->attcollation))
+					{
+						appendStringInfoString(&fmtSub, " %{collation}s");
+						insert_collate_object(state, "collation",
+											  "COLLATE %{name}D",
+											  CollationRelationId,
+											  att->attcollation, "name");
+					}
+
+					/*
+					 * If there's a USING clause, transformAlterTableStmt ran
+					 * it through transformExpr and stored the resulting node
+					 * in cooked_default, which we can use here.
+					 */
+					if (def->raw_default)
+					{
+						Datum		deparsed;
+						char	   *defexpr;
+						List	   *exprs = NIL;
+
+						exprs = lappend(exprs, def->cooked_default);
+						defexpr = nodeToString(def->cooked_default);
+						deparsed = DirectFunctionCall2(pg_get_expr,
+													   CStringGetTextDatum(defexpr),
+													   RelationGetRelid(rel));
+						appendStringInfoString(&fmtSub, " %{using}s");
+						insert_jsonb_key(state, "using");
+						pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+						new_jsonb_VA(state, 2,
+									 "fmt", jbvString, "USING %{expression}s",
+									 "expression", jbvString,
+									 TextDatumGetCString(deparsed));
+						pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+					}
+
+					/* We have full fmt by now, so add jsonb element for that */
+					new_jsonb_VA(state, 1, "fmt", jbvString, fmtSub.data);
+
+					pfree(fmtSub.data);
+					pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				}
+				break;
+
+			case AT_ChangeOwner:
+
+				/*
+				 * Syntax: OWNER TO %{owner}I
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 3,
+							 "fmt", jbvString, "OWNER TO %{owner}I",
+							 "type", jbvString, "change owner",
+							 "owner", jbvString,
+							 get_rolespec_name(subcmd->newowner));
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+
+			case AT_ClusterOn:
+
+				/*
+				 * Syntax: CLUSTER ON %{index}I
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 3,
+							 "fmt", jbvString, "CLUSTER ON %{index}I",
+							 "type", jbvString, "cluster on",
+							 "index", jbvString, subcmd->name);
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+
+
+			case AT_DropCluster:
+
+				/*
+				 * Syntax: SET WITHOUT CLUSTER
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 2,
+							 "fmt", jbvString, "SET WITHOUT CLUSTER",
+							 "type", jbvString, "set without cluster");
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+
+			case AT_SetLogged:
+
+				/*
+				 * Syntax: SET LOGGED
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 2,
+							 "fmt", jbvString, "SET LOGGED",
+							 "type", jbvString, "set logged");
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+
+			case AT_SetUnLogged:
+
+				/*
+				 * Syntax: SET UNLOGGED
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 2,
+							 "fmt", jbvString, "SET UNLOGGED",
+							 "type", jbvString, "set unlogged");
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+
+			case AT_DropOids:
+
+				/*
+				 * Syntax: SET WITHOUT OIDS
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 2,
+							 "fmt", jbvString, "SET WITHOUT OIDS",
+							 "type", jbvString, "set without oids");
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+
+			case AT_SetAccessMethod:
+
+				/*
+				 * Syntax: SET ACCESS METHOD %{access_method}I
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 3,
+							 "fmt", jbvString,
+							 "SET ACCESS METHOD %{access_method}I",
+							 "type", jbvString, "set access method",
+							 "access_method", jbvString, subcmd->name);
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+
+			case AT_SetTableSpace:
+
+				/*
+				 * Syntax: SET TABLESPACE %{tablespace}I
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 3,
+							 "fmt", jbvString, "SET TABLESPACE %{tablespace}I",
+							 "type", jbvString, "set tablespace",
+							 "tablespace", jbvString, subcmd->name);
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+
+			case AT_SetRelOptions:
+			case AT_ResetRelOptions:
+
+				/*
+				 * Syntax: SET|RESET (%{options:, }s)
+				 */
+				deparse_RelSetOptions_toJsonb(state, subcmd);
+				break;
+
+			case AT_EnableTrig:
+
+				/*
+				 * Syntax: ENABLE TRIGGER %{trigger}I
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 3,
+							 "fmt", jbvString, "ENABLE TRIGGER %{trigger}I",
+							 "type", jbvString, "enable trigger",
+							 "trigger", jbvString, subcmd->name);
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+
+			case AT_EnableAlwaysTrig:
+
+				/*
+				 * Syntax: ENABLE ALWAYS TRIGGER %{trigger}I
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 3,
+							 "fmt", jbvString,
+							 "ENABLE ALWAYS TRIGGER %{trigger}I",
+							 "type", jbvString, "enable always trigger",
+							 "trigger", jbvString, subcmd->name);
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+
+			case AT_EnableReplicaTrig:
+
+				/*
+				 * Syntax: ENABLE REPLICA TRIGGER %{trigger}I
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 3,
+							 "fmt", jbvString,
+							 "ENABLE REPLICA TRIGGER %{trigger}I",
+							 "type", jbvString, "enable replica trigger",
+							 "trigger", jbvString, subcmd->name);
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+
+			case AT_DisableTrig:
+
+				/*
+				 * Syntax: DISABLE TRIGGER %{trigger}I
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 3,
+							 "fmt", jbvString, "DISABLE TRIGGER %{trigger}I",
+							 "type", jbvString, "disable trigger",
+							 "trigger", jbvString, subcmd->name);
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+
+			case AT_EnableTrigAll:
+
+				/*
+				 * Syntax: ENABLE TRIGGER ALL
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 2,
+							 "fmt", jbvString, "ENABLE TRIGGER ALL",
+							 "type", jbvString, "enable trigger all");
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+
+			case AT_DisableTrigAll:
+
+				/*
+				 * Syntax: DISABLE TRIGGER ALL
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 2,
+							 "fmt", jbvString, "DISABLE TRIGGER ALL",
+							 "type", jbvString, "disable trigger all");
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+
+			case AT_EnableTrigUser:
+
+				/*
+				 * Syntax: ENABLE TRIGGER USER
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 2,
+							 "fmt", jbvString, "ENABLE TRIGGER USER",
+							 "type", jbvString, "enable trigger user");
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+
+			case AT_DisableTrigUser:
+
+				/*
+				 * Syntax: DISABLE TRIGGER USER
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 2,
+							 "fmt", jbvString, "DISABLE TRIGGER USER",
+							 "type", jbvString, "disable trigger user");
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+
+			case AT_EnableRule:
+
+				/*
+				 * Syntax: ENABLE RULE %{rule}I
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 3,
+							 "fmt", jbvString, "ENABLE RULE %{rule}I",
+							 "type", jbvString, "enable rule",
+							 "rule", jbvString, subcmd->name);
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+
+			case AT_EnableAlwaysRule:
+
+				/*
+				 * Syntax: ENABLE ALWAYS RULE %{rule}I
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 3,
+							 "fmt", jbvString, "ENABLE ALWAYS RULE %{rule}I",
+							 "type", jbvString, "enable always rule",
+							 "rule", jbvString, subcmd->name);
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+
+			case AT_EnableReplicaRule:
+
+				/*
+				 * Syntax: ENABLE REPLICA RULE %{rule}I
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 3,
+							 "fmt", jbvString, "ENABLE REPLICA RULE %{rule}I",
+							 "type", jbvString, "enable replica rule",
+							 "rule", jbvString, subcmd->name);
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+
+			case AT_DisableRule:
+
+				/*
+				 * Syntax: DISABLE RULE %{rule}I
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 3,
+							 "fmt", jbvString, "DISABLE RULE %{rule}I",
+							 "type", jbvString, "disable rule",
+							 "rule", jbvString, subcmd->name);
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+
+			case AT_AddInherit:
+
+				/*
+				 * Syntax: INHERIT %{parent}D
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 2,
+							 "fmt", jbvString, "INHERIT %{parent}D",
+							 "type", jbvString, "inherit");
+				new_jsonb_for_qualname_id(state, RelationRelationId,
+										  sub->address.objectId, "parent", true);
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+
+			case AT_DropInherit:
+
+				/*
+				 * Syntax: NO INHERIT %{parent}D
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 2,
+							 "fmt", jbvString, "NO INHERIT %{parent}D",
+							 "type", jbvString, "drop inherit");
+				new_jsonb_for_qualname_id(state, RelationRelationId,
+										  sub->address.objectId, "parent", true);
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+
+			case AT_AddOf:
+
+				/*
+				 * Syntax: OF %{type_of}T
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 2,
+							 "fmt", jbvString, "OF %{type_of}T",
+							 "type", jbvString, "add of");
+				new_jsonb_for_type(state, "type_of", sub->address.objectId, -1);
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+
+			case AT_DropOf:
+
+				/*
+				 * Syntax: NOT OF
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 2,
+							 "fmt", jbvString, "NOT OF",
+							 "type", jbvString, "not of");
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+
+			case AT_ReplicaIdentity:
+
+				/*
+				 * Syntax: REPLICA IDENTITY %{ident}s
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 2,
+							 "fmt", jbvString,
+							 "REPLICA IDENTITY %{ident}s",
+							 "type", jbvString, "replica identity");
+				switch (((ReplicaIdentityStmt *) subcmd->def)->identity_type)
+				{
+					case REPLICA_IDENTITY_DEFAULT:
+						new_jsonb_VA(state, 1, "ident", jbvString, "DEFAULT");
+						break;
+					case REPLICA_IDENTITY_FULL:
+						new_jsonb_VA(state, 1, "ident", jbvString, "FULL");
+						break;
+					case REPLICA_IDENTITY_NOTHING:
+						new_jsonb_VA(state, 1, "ident", jbvString, "NOTHING");
+						break;
+					case REPLICA_IDENTITY_INDEX:
+						insert_jsonb_key(state, "ident");
+						new_jsonb_VA(state, 2,
+									 "fmt", jbvString, "USING INDEX %{index}I",
+									 "index", jbvString,
+									 ((ReplicaIdentityStmt *) subcmd->def)->name);
+						break;
+				}
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+
+			case AT_EnableRowSecurity:
+
+				/*
+				 * Syntax: ENABLE ROW LEVEL SECURITY
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 2,
+							 "fmt", jbvString,
+							 "ENABLE ROW LEVEL SECURITY",
+							 "type", jbvString, "enable row security");
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+
+			case AT_DisableRowSecurity:
+
+				/*
+				 * Syntax: DISABLE ROW LEVEL SECURITY
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 2,
+							 "fmt", jbvString,
+							 "DISABLE ROW LEVEL SECURITY",
+							 "type", jbvString, "disable row security");
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+
+			case AT_AttachPartition:
+				{
+					StringInfoData fmtSub;
+
+					initStringInfo(&fmtSub);
+
+					/*
+					 * Syntax: ATTACH PARTITION %{partition_identity}D
+					 * %{partition_bound}s
+					 */
+					pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+					appendStringInfoString(&fmtSub, "ATTACH PARTITION"
+										   " %{partition_identity}D");
+
+					new_jsonb_VA(state, 1, "type", jbvString,
+								 "attach partition");
+					new_jsonb_for_qualname_id(state, RelationRelationId,
+											  sub->address.objectId,
+											  "partition_identity", true);
+
+					if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+					{
+						appendStringInfoString(&fmtSub, " %{partition_bound}s");
+						new_jsonb_VA(state, 1,
+									 "partition_bound", jbvString,
+									 RelationGetPartitionBound(sub->address.objectId));
+					}
+
+					/* We have full fmt by now, so add jsonb element for that */
+					new_jsonb_VA(state, 1, "fmt", jbvString, fmtSub.data);
+					pfree(fmtSub.data);
+
+					pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+
+					break;
+				}
+			case AT_DetachPartition:
+				{
+					PartitionCmd *cmd;
+					StringInfoData fmtSub;
+
+					initStringInfo(&fmtSub);
+
+					Assert(IsA(subcmd->def, PartitionCmd));
+					cmd = (PartitionCmd *) subcmd->def;
+
+					/*
+					 * Syntax: DETACH PARTITION %{partition_identity}D
+					 * %{concurrent}s
+					 */
+					pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+					appendStringInfoString(&fmtSub, "DETACH PARTITION"
+										   " %{partition_identity}D");
+
+					new_jsonb_VA(state, 1, "type", jbvString, "detach partition");
+					new_jsonb_for_qualname_id(state, RelationRelationId,
+											  sub->address.objectId,
+											  "partition_identity", true);
+					if (cmd->concurrent)
+					{
+						appendStringInfoString(&fmtSub, " %{concurrent}s");
+						new_jsonb_VA(state, 1,
+									 "concurrent", jbvString, "CONCURRENTLY");
+					}
+
+					/* We have full fmt by now, so add jsonb element for that */
+					new_jsonb_VA(state, 1, "fmt", jbvString, fmtSub.data);
+					pfree(fmtSub.data);
+
+					pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+					break;
+				}
+			case AT_DetachPartitionFinalize:
+
+				/*
+				 * Syntax: DETACH PARTITION %{partition_identity}D FINALIZE
+				 */
+				pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+				new_jsonb_VA(state, 2,
+							 "fmt", jbvString, "DETACH PARTITION"
+							 " %{partition_identity}D FINALIZE",
+							 "type", jbvString, "detach partition finalize");
+
+				new_jsonb_for_qualname_id(state, RelationRelationId,
+										  sub->address.objectId,
+										  "partition_identity", true);
+				pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				break;
+			case AT_AddIdentity:
+				{
+					AttrNumber	attnum;
+					Oid			seq_relid;
+					ColumnDef  *coldef = (ColumnDef *) subcmd->def;
+					StringInfoData fmtSub;
+
+					initStringInfo(&fmtSub);
+
+					/*
+					 * Syntax: ALTER COLUMN %{column}I %{definition}s where
+					 * definition : ADD %{identity_column}s where
+					 * identity_column: %{identity_type}s ( %{seq_definition:
+					 * }s )
+					 */
+					pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+
+					appendStringInfoString(&fmtSub, "ALTER COLUMN %{column}I");
+					new_jsonb_VA(state, 2,
+								 "type", jbvString, "add identity",
+								 "column", jbvString, subcmd->name);
+
+					attnum = get_attnum(RelationGetRelid(rel), subcmd->name);
+					seq_relid = getIdentitySequence(RelationGetRelid(rel),
+													attnum, true);
+
+					if (OidIsValid(seq_relid))
+					{
+
+						appendStringInfoString(&fmtSub, " %{definition}s");
+						insert_jsonb_key(state, "definition");
+
+						/* insert definition's value now */
+						pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+						new_jsonb_VA(state, 1,
+									 "fmt", jbvString, "ADD %{identity_column}s");
+
+						/* insert identity_column */
+						deparse_ColumnIdentity_toJsonb(state, "identity_column",
+													   seq_relid,
+													   coldef->identity, false);
+
+						/* mark definition's value end */
+						pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+					}
+
+					/* We have full fmt by now, so add jsonb element for that */
+					new_jsonb_VA(state, 1, "fmt", jbvString, fmtSub.data);
+
+					pfree(fmtSub.data);
+
+					pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+				}
+				break;
+			case AT_SetIdentity:
+				{
+					DefElem    *defel;
+					char		identity = 0;
+					AttrNumber	attnum;
+					Oid			seq_relid;
+					StringInfoData fmtSub;
+
+					initStringInfo(&fmtSub);
+
+					/*
+					 * Syntax: ALTER COLUMN %{column}I %{definition}s where
+					 * definition : %{identity_type}s ( %{seq_definition: }s )
+					 */
+					pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+
+					appendStringInfoString(&fmtSub, "ALTER COLUMN %{column}I");
+					new_jsonb_VA(state, 2,
+								 "type", jbvString, "set identity",
+								 "column", jbvString, subcmd->name);
+
+					if (subcmd->def)
+					{
+						List	   *def = (List *) subcmd->def;
+
+						Assert(IsA(subcmd->def, List));
+
+						defel = linitial_node(DefElem, def);
+						identity = defGetInt32(defel);
+					}
+
+					attnum = get_attnum(RelationGetRelid(rel), subcmd->name);
+					seq_relid = getIdentitySequence(RelationGetRelid(rel),
+													attnum, true);
+
+					if (OidIsValid(seq_relid))
+					{
+						appendStringInfoString(&fmtSub, " %{definition}s");
+						deparse_ColumnIdentity_toJsonb(state, "definition",
+													   seq_relid, identity,
+													   true);
+					}
+
+					/* We have full fmt by now, so add jsonb element for that */
+					new_jsonb_VA(state, 1, "fmt", jbvString, fmtSub.data);
+
+					pfree(fmtSub.data);
+					pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+
+					break;
+				}
+			case AT_DropIdentity:
+				{
+					StringInfoData fmtSub;
+
+					initStringInfo(&fmtSub);
+
+					/*
+					 * Syntax: ALTER COLUMN %{column}I DROP IDENTITY
+					 * %{if_exists}s
+					 */
+					pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
+					appendStringInfoString(&fmtSub, "ALTER COLUMN"
+										   " %{column}I DROP IDENTITY");
+					new_jsonb_VA(state, 2,
+								 "type", jbvString, "drop identity",
+								 "column", jbvString, subcmd->name);
+
+					if (subcmd->missing_ok)
+					{
+						appendStringInfoString(&fmtSub, " %{if_exists}s");
+						new_jsonb_VA(state, 1,
+									 "if_exists", jbvString, "IF EXISTS");
+					}
+
+					/* We have full fmt by now, so add jsonb element for that */
+					new_jsonb_VA(state, 1, "fmt", jbvString, fmtSub.data);
+					pfree(fmtSub.data);
+
+					pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+					break;
+				}
+			default:
+				elog(WARNING, "unsupported alter table subtype %d",
+					 subcmd->subtype);
+				break;
+		}
+	}
+
+	table_close(rel, AccessShareLock);
+
+	/* if subcmds array is not even created or has 0 elements, return NULL */
+	if (!subCmdArray ||
+		((state->contVal.type == jbvArray) &&
+		 (state->contVal.val.array.nElems == 0)))
+	{
+		pfree(fmtStr.data);
+		return NULL;
+	}
+
+	/* Mark the end of subcmds array */
+	pushJsonbValue(&state, WJB_END_ARRAY, NULL);
+
+	/* We have full fmt by now, so add jsonb element for that */
+	new_jsonb_VA(state, 1, "fmt", jbvString, fmtStr.data);
+
+	pfree(fmtStr.data);
+
+	/* Mark the end of ROOT object */
+	value = pushJsonbValue(&state, WJB_END_OBJECT, NULL);
+
+	return JsonbValueToJsonb(value);
+}
\ No newline at end of file
diff --git a/src/backend/nodes/meson.build b/src/backend/nodes/meson.build
index 31467a12d3..a117ade6ed 100644
--- a/src/backend/nodes/meson.build
+++ b/src/backend/nodes/meson.build
@@ -19,6 +19,7 @@ backend_sources += files(
 # add that as an include path for the whole backend
 nodefunc_sources = files(
   'copyfuncs.c',
+  'ddldeparsefuncs.c',
   'equalfuncs.c',
   'queryjumblefuncs.c',
   'outfuncs.c',
diff --git a/src/include/tcop/ddldeparse.h b/src/include/tcop/ddldeparse.h
index 8b369fd8c5..0304f34c5d 100644
--- a/src/include/tcop/ddldeparse.h
+++ b/src/include/tcop/ddldeparse.h
@@ -13,10 +13,50 @@
 #define DDL_DEPARSE_H
 
 #include "tcop/deparse_utility.h"
+#include "utils/jsonb.h"
 
+extern void new_jsonb_VA(JsonbParseState *state, int numobjs, ...);
+extern void insert_jsonb_key(JsonbParseState *state, char *name);
+
+extern void deparse_ColumnDef_toJsonb(JsonbParseState *state,
+									  Relation relation, List *dpcontext,
+									  bool composite, ColumnDef *coldef,
+									  bool is_alter);
+extern void deparse_ColumnIdentity_toJsonb(JsonbParseState *state,
+										   char *parentKey, Oid seqrelid,
+										   char identity, bool alter_table);
+extern void deparse_RelSetOptions_toJsonb(JsonbParseState *state,
+										  AlterTableCmd *subcmd);
+extern void deparse_ColumnSetOptions_ToJsonb(JsonbParseState *state,
+											 AlterTableCmd *subcmd);
+extern char *RelationGetColumnDefault(Relation rel, AttrNumber attno,
+									  List *dpcontext);
+extern void new_jsonb_for_qualname_id(JsonbParseState *state, Oid classId,
+									  Oid objectId, char *keyName,
+									  bool createObject);
+extern char *RelationGetPartitionBound(Oid relid);
+extern void new_jsonb_for_type(JsonbParseState *state, char *parentKey,
+							   Oid typId, int32 typmod);
+extern void insert_collate_object(JsonbParseState *state, char *parentKey,
+								  char *fmt, Oid classId, Oid objectId,
+								  char *key);
+extern void insert_identity_object(JsonbParseState *state, Oid nspid,
+								   char *relname);
+extern bool add_table_elems_if_any(JsonbParseState *state, StringInfo fmtStr,
+								   Relation relation, List *tableElts,
+								   List *dpcontext, Oid objectId, bool typed,
+								   bool composite);
+extern void new_jsonbArray_for_qualname_id(JsonbParseState *state,
+										   char *keyname, List *array);
+extern void role_to_jsonb_element(JsonbParseState *state, char *owner);
+extern char *get_persistence_str(char persistence);
+extern void deparse_withObj_ToJsonb(JsonbParseState *state, CreateStmt *node);
+extern List *deparse_InhRels_ToJsonb(Oid objectId);
 extern char *deparse_utility_command(CollectedCommand *cmd);
 extern char *deparse_ddl_json_to_string(char *jsonb);
+extern Jsonb *deparse_create_table(Oid objectId, Node *parsetree);
 extern char *deparse_drop_table(const char *objidentity, const char *objecttype,
-								  Node *parsetree);
+								Node *parsetree);
+extern Jsonb *deparse_AlterTableStmt(CollectedCommand *cmd);
 
 #endif							/* DDL_DEPARSE_H */
-- 
2.34.1

