From 3180e288160a2d2e3325f211ff086e0eda75fbf8 Mon Sep 17 00:00:00 2001
From: Alvaro Herrera <alvherre@alvh.no-ip.org>
Date: Thu, 25 Sep 2014 15:45:04 -0300
Subject: [PATCH 20/29] deparse: support COMMENT ON and SECURITY LABEL

---
 src/backend/tcop/deparse_utility.c | 155 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 153 insertions(+), 2 deletions(-)

diff --git a/src/backend/tcop/deparse_utility.c b/src/backend/tcop/deparse_utility.c
index 747e076..479d46b 100644
--- a/src/backend/tcop/deparse_utility.c
+++ b/src/backend/tcop/deparse_utility.c
@@ -4364,6 +4364,157 @@ deparse_AlterEnumStmt(Oid objectId, Node *parsetree)
 	return alterEnum;
 }
 
+/*
+ * Append a NULL-or-quoted-literal clause.  Useful for COMMENT and SECURITY
+ * LABEL.
+ */
+static void
+append_literal_or_null(ObjTree *mainobj, char *elemname, char *value)
+{
+	ObjTree	*top;
+	ObjTree *part;
+
+	top = new_objtree_VA("%{null}s%{literal}s", 0);
+	part = new_objtree_VA("NULL", 1,
+						  "present", ObjTypeBool,
+						  !value);
+	append_object_object(top, "null", part);
+	part = new_objtree_VA("%{value}L", 1,
+						  "present", ObjTypeBool,
+						  !!value);
+	if (value)
+		append_string_object(part, "value", value);
+	append_object_object(top, "literal", part);
+
+	append_object_object(mainobj, elemname, top);
+}
+
+/*
+ * Deparse a CommentStmt when it pertains to a constraint.
+ */
+static ObjTree *
+deparse_CommentOnConstraintSmt(Oid objectId, Node *parsetree)
+{
+	CommentStmt *node = (CommentStmt *) parsetree;
+	ObjTree	   *comment;
+	HeapTuple	constrTup;
+	Form_pg_constraint constrForm;
+	char	   *fmt;
+	ObjectAddress addr;
+
+	Assert(node->objtype == OBJECT_TABCONSTRAINT || node->objtype == OBJECT_DOMCONSTRAINT);
+
+	constrTup = SearchSysCache1(CONSTROID, objectId);
+	if (!HeapTupleIsValid(constrTup))
+		elog(ERROR, "cache lookup failed for constraint %u", objectId);
+	constrForm = (Form_pg_constraint) GETSTRUCT(constrTup);
+
+	if (OidIsValid(constrForm->conrelid))
+		ObjectAddressSet(addr, RelationRelationId, constrForm->conrelid);
+	else
+		ObjectAddressSet(addr, TypeRelationId, constrForm->contypid);
+
+	fmt = psprintf("COMMENT ON CONSTRAINT %%{identity}s ON %s%%{parentobj}s IS %%{comment}s",
+				   node->objtype == OBJECT_TABCONSTRAINT ? "" : "DOMAIN ");
+	comment = new_objtree_VA(fmt, 0);
+
+	/* Add the comment clause */
+	append_literal_or_null(comment, "comment", node->comment);
+
+	append_string_object(comment, "identity", pstrdup(NameStr(constrForm->conname)));
+
+	append_string_object(comment, "parentobj",
+						 getObjectIdentity(&addr));
+
+	ReleaseSysCache(constrTup);
+
+	return comment;
+}
+
+static ObjTree *
+deparse_CommentStmt(ObjectAddress address, Node *parsetree)
+{
+	CommentStmt *node = (CommentStmt *) parsetree;
+	ObjTree	   *comment;
+	char	   *fmt;
+	char	   *identity;
+
+	/*
+	 * Constraints are sufficiently different that it is easier to handle them
+	 * separately.
+	 */
+	if (node->objtype == OBJECT_DOMCONSTRAINT ||
+		node->objtype == OBJECT_TABCONSTRAINT)
+	{
+		Assert(address.classId == ConstraintRelationId);
+		return deparse_CommentOnConstraintSmt(address.objectId, parsetree);
+	}
+
+	fmt = psprintf("COMMENT ON %s %%{identity}s IS %%{comment}s",
+				   stringify_objtype(node->objtype));
+	comment = new_objtree_VA(fmt, 0);
+
+	/* Add the comment clause; can be either NULL or a quoted literal.  */
+	append_literal_or_null(comment, "comment", node->comment);
+
+	/*
+	 * Add the object identity clause.  For zero argument aggregates we need to
+	 * add the (*) bit; in all other cases we can just use getObjectIdentity.
+	 *
+	 * XXX shouldn't we instead fix the object identities for zero-argument
+	 * aggregates?
+	 */
+	if (node->objtype == OBJECT_AGGREGATE)
+	{
+		HeapTuple		procTup;
+		Form_pg_proc	procForm;
+
+		procTup = SearchSysCache1(PROCOID, ObjectIdGetDatum(address.objectId));
+		if (!HeapTupleIsValid(procTup))
+			elog(ERROR, "cache lookup failed for procedure %u", address.objectId);
+		procForm = (Form_pg_proc) GETSTRUCT(procTup);
+		if (procForm->pronargs == 0)
+			identity = psprintf("%s(*)",
+								quote_qualified_identifier(get_namespace_name(procForm->pronamespace),
+														   NameStr(procForm->proname)));
+		else
+			identity = getObjectIdentity(&address);
+		ReleaseSysCache(procTup);
+	}
+	else
+		identity = getObjectIdentity(&address);
+
+	append_string_object(comment, "identity", identity);
+
+	return comment;
+}
+
+static ObjTree *
+deparse_SecLabelStmt(ObjectAddress address, Node *parsetree)
+{
+	SecLabelStmt *node = (SecLabelStmt *) parsetree;
+	ObjTree	   *label;
+	char	   *fmt;
+
+	Assert(node->provider);
+
+	fmt = psprintf("SECURITY LABEL FOR %%{provider}s ON %s %%{identity}s IS %%{label}s",
+				   stringify_objtype(node->objtype));
+	label = new_objtree_VA(fmt, 0);
+
+	/* Add the label clause; can be either NULL or a quoted literal. */
+	append_literal_or_null(label, "label", node->label);
+
+	/* Add the security provider clause */
+	append_string_object(label, "provider", node->provider);
+
+	/* Add the object identity clause */
+	append_string_object(label, "identity",
+						 getObjectIdentity(&address));
+
+	return label;
+}
+
 static ObjTree *
 deparse_CreateConversion(Oid objectId, Node *parsetree)
 {
@@ -5452,7 +5603,7 @@ deparse_simple_command(StashedCommand *cmd)
 			break;
 
 		case T_CommentStmt:
-			elog(ERROR, "unimplemented deparse of %s", CreateCommandTag(parsetree));
+			command = deparse_CommentStmt(cmd->d.simple.address, parsetree);
 			break;
 
 		case T_GrantStmt:
@@ -5478,7 +5629,7 @@ deparse_simple_command(StashedCommand *cmd)
 			break;
 
 		case T_SecLabelStmt:
-			elog(ERROR, "unimplemented deparse of %s", CreateCommandTag(parsetree));
+			command = deparse_SecLabelStmt(cmd->d.simple.address, parsetree);
 			break;
 
 		default:
-- 
2.1.4

