From d471ba92638dbf59a53a3a9e8a68dbce2db70692 Mon Sep 17 00:00:00 2001
From: Ajin Cherian <ajinc@fast.au.fujitsu.com>
Date: Wed, 13 Apr 2022 09:13:28 -0400
Subject: [PATCH 2/3] Move some ddl-deparsing code from ruleutils to extension.

---
 src/backend/utils/adt/format_type.c | 125 --------------
 src/backend/utils/adt/ruleutils.c   | 325 +-----------------------------------
 src/include/utils/builtins.h        |   4 -
 src/include/utils/ruleutils.h       |  17 +-
 4 files changed, 8 insertions(+), 463 deletions(-)

diff --git a/src/backend/utils/adt/format_type.c b/src/backend/utils/adt/format_type.c
index 42e3af3..060fd7e 100644
--- a/src/backend/utils/adt/format_type.c
+++ b/src/backend/utils/adt/format_type.c
@@ -334,131 +334,6 @@ format_type_extended(Oid type_oid, int32 typemod, bits16 flags)
 }
 
 /*
- * Similar to format_type_internal, except we return each bit of information
- * separately:
- *
- * - nspid is the schema OID.  For certain SQL-standard types which have weird
- *   typmod rules, we return InvalidOid; caller is expected to not schema-
- *   qualify the name nor add quotes to the type name in this case.
- *
- * - typename is set to the type name, without quotes
- *
- * - typmod is set to the typemod, if any, as a string with parens
- *
- * - typarray indicates whether []s must be added
- *
- * We don't try to decode type names to their standard-mandated names, except
- * in the cases of types with unusual typmod rules.
- */
-void
-format_type_detailed(Oid type_oid, int32 typemod,
-					 Oid *nspid, char **typname, char **typemodstr,
-					 bool *typarray)
-{
-	HeapTuple	tuple;
-	Form_pg_type typeform;
-	Oid			array_base_type;
-
-	tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid));
-	if (!HeapTupleIsValid(tuple))
-		elog(ERROR, "cache lookup failed for type %u", type_oid);
-
-	typeform = (Form_pg_type) GETSTRUCT(tuple);
-
-	/*	 * Special-case crock for types with strange typmod rules.
-	 */
-	if (type_oid == INTERVALOID ||
-		type_oid == TIMESTAMPOID ||
-		type_oid == TIMESTAMPTZOID ||
-		type_oid == TIMEOID ||
-		type_oid == TIMETZOID)
-	{
-		*typarray = false;
-
-peculiar_typmod:
-		switch (type_oid)
-		{
-			case INTERVALOID:
-				*typname = pstrdup("INTERVAL");
-				break;
-			case TIMESTAMPTZOID:
-				if (typemod < 0)
-				{
-					*typname = pstrdup("TIMESTAMP WITH TIME ZONE");
-					break;
-				}
-				/* otherwise, WITH TZ is added by typmod, so fall through */
-			case TIMESTAMPOID:
-				*typname = pstrdup("TIMESTAMP");
-				break;
-			case TIMETZOID:
-				if (typemod < 0)
-				{
-					*typname = pstrdup("TIME WITH TIME ZONE");
-					break;
-				}
-				/* otherwise, WITH TZ is added by typmode, so fall through */
-			case TIMEOID:
-				*typname = pstrdup("TIME");
-				break;
-		}
-		*nspid = InvalidOid;
-
-		if (typemod >= 0)
-			*typemodstr = printTypmod(NULL, typemod, typeform->typmodout);
-		else
-			*typemodstr = pstrdup("");
-
-		ReleaseSysCache(tuple);
-		return;
-	}
-
-	/*
-	 * Check if it's a regular (variable length) array type.  As above,
-	 * fixed-length array types such as "name" shouldn't get deconstructed.
-	 */
-	array_base_type = typeform->typelem;
-
-	if (array_base_type != InvalidOid &&
-		typeform->typstorage != 'p')
-	{
-		/* Switch our attention to the array element type */
-		ReleaseSysCache(tuple);
-		tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(array_base_type));
-		if (!HeapTupleIsValid(tuple))
-			elog(ERROR, "cache lookup failed for type %u", type_oid);
-
-		typeform = (Form_pg_type) GETSTRUCT(tuple);
-		type_oid = array_base_type;
-		*typarray = true;
-
-		/*
-		 * If it's an array of one of the types with special typmod rules,
-		 * have the element type be processed as above, but now with typarray
-		 * set to true.
-		 */
-		if (type_oid == INTERVALOID ||
-			type_oid == TIMESTAMPTZOID ||
-			type_oid == TIMESTAMPOID ||
-			type_oid == TIMETZOID ||
-			type_oid == TIMEOID)
-			goto peculiar_typmod;
-	}
-	else
-		*typarray = false;
-
-	*nspid = typeform->typnamespace;
-	*typname = pstrdup(NameStr(typeform->typname));
-
-	if (typemod >= 0)
-		*typemodstr = printTypmod(NULL, typemod, typeform->typmodout);
-	else
-		*typemodstr = pstrdup("");
-
-	ReleaseSysCache(tuple);
-}
-
-/*
  * This version is for use within the backend in error messages, etc.
  * One difference is that it will fail for an invalid type.
  *
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index f1d6e9a..77a5b79 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -484,8 +484,6 @@ static void get_from_clause_coldeflist(RangeTblFunction *rtfunc,
 									   deparse_context *context);
 static void get_tablesample_def(TableSampleClause *tablesample,
 								deparse_context *context);
-static void get_opclass_name(Oid opclass, Oid actual_datatype,
-							 StringInfo buf);
 static Node *processIndirection(Node *node, deparse_context *context);
 static void printSubscripts(SubscriptingRef *sbsref, deparse_context *context);
 static char *get_relation_name(Oid relid);
@@ -499,7 +497,6 @@ static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2);
 static void add_cast_to(StringInfo buf, Oid typid);
 static char *generate_qualified_type_name(Oid typid);
 static text *string_to_text(char *str);
-static char *flatten_reloptions(Oid relid);
 static void get_reloptions(StringInfo buf, Datum reloptions);
 static void get_json_path_spec(Node *path_spec, deparse_context *context,
 							   bool showimplicit);
@@ -558,8 +555,8 @@ pg_get_ruledef_ext(PG_FUNCTION_ARGS)
  * NIL, signalling NOTHING) in actions.
  */
 void
-pg_get_ruledef_details(Datum ev_qual, Datum ev_action,
-					   char **whereClause, List **actions)
+pg_get_ruledef_detailed(Datum ev_qual, Datum ev_action,
+						char **whereClause, List **actions)
 {
 	int prettyFlags = 0;
 	char *qualstr = TextDatumGetCString(ev_qual);
@@ -1627,250 +1624,6 @@ pg_get_indexdef_worker(Oid indexrelid, int colno,
 	return buf.data;
 }
 
-/*
- * Return an index definition, split in several pieces.
- *
- * There is a huge lot of code that's a dupe of pg_get_indexdef_worker, but
- * control flow is different enough that it doesn't seem worth keeping them
- * together.
- */
-void
-pg_get_indexdef_detailed(Oid indexrelid,
-						char **index_am,
-						char **definition,
-						char **reloptions,
-						char **tablespace,
-						char **whereClause)
-{
-	HeapTuple   ht_idx;
-	HeapTuple   ht_idxrel;
-	HeapTuple   ht_am;
-	Form_pg_index idxrec;
-	Form_pg_class idxrelrec;
-	Form_pg_am  amrec;
-	IndexAmRoutine *amroutine;
-	List       *indexprs;
-	ListCell   *indexpr_item;
-	List       *context;
-	Oid         indrelid;
-	int         keyno;
-	Datum       indcollDatum;
-	Datum       indclassDatum;
-	Datum       indoptionDatum;
-	bool        isnull;
-	oidvector  *indcollation;
-	oidvector  *indclass;
-	int2vector *indoption;
-	StringInfoData definitionBuf;
-	char       *sep;
-
-	/*
-	 * Fetch the pg_index tuple by the Oid of the index
-	 */
-	ht_idx = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexrelid));
-	if (!HeapTupleIsValid(ht_idx))
-		elog(ERROR, "cache lookup failed for index %u", indexrelid);
-	idxrec = (Form_pg_index) GETSTRUCT(ht_idx);
-
-	indrelid = idxrec->indrelid;
-	Assert(indexrelid == idxrec->indexrelid);
-
-	/* Must get indcollation, indclass, and indoption the hard way */
-	indcollDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
-									Anum_pg_index_indcollation, &isnull);
-	Assert(!isnull);
-	indcollation = (oidvector *) DatumGetPointer(indcollDatum);
-
-	indclassDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
-									Anum_pg_index_indclass, &isnull);
-	Assert(!isnull);
-	indclass = (oidvector *) DatumGetPointer(indclassDatum);
-
-	indoptionDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
-									 Anum_pg_index_indoption, &isnull);
-	Assert(!isnull);
-	indoption = (int2vector *) DatumGetPointer(indoptionDatum);
-
-	/*
-	 * Fetch the pg_class tuple of the index relation
-	 */
-	ht_idxrel = SearchSysCache1(RELOID, ObjectIdGetDatum(indexrelid));
-	if (!HeapTupleIsValid(ht_idxrel))
-		elog(ERROR, "cache lookup failed for relation %u", indexrelid);
-	idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
-
-	/*
-	 * Fetch the pg_am tuple of the index' access method
-	 */
-	ht_am = SearchSysCache1(AMOID, ObjectIdGetDatum(idxrelrec->relam));
-	if (!HeapTupleIsValid(ht_am))
-		elog(ERROR, "cache lookup failed for access method %u",
-			idxrelrec->relam);
-	amrec = (Form_pg_am) GETSTRUCT(ht_am);
-
-	/* Fetch the index AM's API struct */
-	amroutine = GetIndexAmRoutine(amrec->amhandler);
-
-	/*
-	 * Get the index expressions, if any.  (NOTE: we do not use the relcache
-	 * versions of the expressions and predicate, because we want to display
-	 * non-const-folded expressions.)
-	 */
-	if (!heap_attisnull(ht_idx, Anum_pg_index_indexprs, NULL))
-	{
-		Datum       exprsDatum;
-		bool        isnull;
-		char       *exprsString;
-
-		exprsDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
-									 Anum_pg_index_indexprs, &isnull);
-		Assert(!isnull);
-		exprsString = TextDatumGetCString(exprsDatum);
-		indexprs = (List *) stringToNode(exprsString);
-		pfree(exprsString);
-	}
-	else
-		indexprs = NIL;
-
-	indexpr_item = list_head(indexprs);
-
-	context = deparse_context_for(get_relation_name(indrelid), indrelid);
-
-	initStringInfo(&definitionBuf);
-
-	/* output index AM */
-	*index_am = pstrdup(quote_identifier(NameStr(amrec->amname)));
-
-	/*
-	 * Output index definition.  Note the outer parens must be supplied by
-	 * caller.
-	 */
-	sep = "";
-	for (keyno = 0; keyno < idxrec->indnatts; keyno++)
-	{
-		AttrNumber  attnum = idxrec->indkey.values[keyno];
-		int16       opt = indoption->values[keyno];
-		Oid         keycoltype;
-		Oid         keycolcollation;
-
-		Oid         indcoll;
-
-		appendStringInfoString(&definitionBuf, sep);
-		sep = ", ";
-
-		if (attnum != 0)
-		{
-			/* Simple index column */
-			char       *attname;
-			int32       keycoltypmod;
-
-			attname = get_attname(indrelid, attnum, false);
-			appendStringInfoString(&definitionBuf, quote_identifier(attname));
-			get_atttypetypmodcoll(indrelid, attnum,
-								  &keycoltype, &keycoltypmod,
-								  &keycolcollation);
-		}
-		else
-		{
-			/* expressional index */
-			Node       *indexkey;
-			char       *str;
-
-			if (indexpr_item == NULL)
-				elog(ERROR, "too few entries in indexprs list");
-			indexkey = (Node *) lfirst(indexpr_item);
-			indexpr_item = lnext(indexprs, indexpr_item);
-			/* Deparse */
-			str = deparse_expression_pretty(indexkey, context, false, false,
-											0, 0);
-
-			/* Need parens if it's not a bare function call */
-			if (indexkey && IsA(indexkey, FuncExpr) &&
-				((FuncExpr *) indexkey)->funcformat == COERCE_EXPLICIT_CALL)
-				appendStringInfoString(&definitionBuf, str);
-			else
-				appendStringInfo(&definitionBuf, "(%s)", str);
-
-			keycoltype = exprType(indexkey);
-			keycolcollation = exprCollation(indexkey);
-		}
-
-		/* Add collation, even if default */
-		indcoll = indcollation->values[keyno];
-		if (OidIsValid(indcoll))
-			appendStringInfo(&definitionBuf, " COLLATE %s",
-							 generate_collation_name((indcoll)));
-
-		/* Add the operator class name, even if default */
-		get_opclass_name(indclass->values[keyno], InvalidOid, &definitionBuf);
-
-		/* Add options if relevant */
-		if (amroutine->amcanorder)
-		{
-			/* if it supports sort ordering, report DESC and NULLS opts */
-			if (opt & INDOPTION_DESC)
-			{
-				appendStringInfoString(&definitionBuf, " DESC");
-				/* NULLS FIRST is the default in this case */
-				if (!(opt & INDOPTION_NULLS_FIRST))
-					appendStringInfoString(&definitionBuf, " NULLS LAST");
-			}
-			else
-			{
-				if (opt & INDOPTION_NULLS_FIRST)
-					appendStringInfoString(&definitionBuf, " NULLS FIRST");
-			}
-		}
-
-		/* XXX excludeOps thingy was here; do we need anything? */
-	}
-	*definition = definitionBuf.data;
-
-	/* output reloptions */
-	*reloptions = flatten_reloptions(indexrelid);
-
-	/* output tablespace */
-	{
-		Oid         tblspc;
-
-		tblspc = get_rel_tablespace(indexrelid);
-		if (OidIsValid(tblspc))
-			*tablespace = pstrdup(quote_identifier(get_tablespace_name(tblspc)));
-		else
-			*tablespace = NULL;
-	}
-
-	/* report index predicate, if any */
-	if (!heap_attisnull(ht_idx, Anum_pg_index_indpred, NULL))
-	{
-		Node       *node;
-		Datum       predDatum;
-		bool        isnull;
-		char       *predString;
-
-		/* Convert text string to node tree */
-		predDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
-									Anum_pg_index_indpred, &isnull);
-		Assert(!isnull);
-		predString = TextDatumGetCString(predDatum);
-		node = (Node *) stringToNode(predString);
-		pfree(predString);
-
-		/* Deparse */
-		*whereClause =
-			deparse_expression_pretty(node, context, false, false,
-									  0, 0);
-	}
-	else
-		*whereClause = NULL;
-
-	/* Clean up */
-	ReleaseSysCache(ht_idx);
-	ReleaseSysCache(ht_idxrel);
-	ReleaseSysCache(ht_am);
-
-	/* all done */
-}
 
 /* ----------
  * pg_get_querydef
@@ -12331,7 +12084,7 @@ get_tablesample_def(TableSampleClause *tablesample, deparse_context *context)
  * actual_datatype.  (If you don't want this behavior, just pass
  * InvalidOid for actual_datatype.)
  */
-static void
+void
 get_opclass_name(Oid opclass, Oid actual_datatype,
 				 StringInfo buf)
 {
@@ -13112,7 +12865,7 @@ get_reloptions(StringInfo buf, Datum reloptions)
 /*
  * Generate a C string representing a relation's reloptions, or NULL if none.
  */
-static char *
+char *
 flatten_reloptions(Oid relid)
 {
 	char	   *result = NULL;
@@ -13180,73 +12933,3 @@ get_range_partbound_string(List *bound_datums)
 
 	return buf->data;
 }
-
-
-/*
- * Obtain the deparsed default value for the given column of the given table.
- *
- * Caller must have set a correct deparse context.
- */
-char *
-RelationGetColumnDefault(Relation rel, AttrNumber attno, List *dpcontext)
-{
-	Node *defval;
-	char *defstr;
-
-	defval = build_column_default(rel, attno);
-	defstr = deparse_expression_pretty(defval, dpcontext, false, false,
-									   0, 0);
-
-	return defstr;
-}
-
-/*
- * Return the default value of a domain.
- */
-char *
-DomainGetDefault(HeapTuple domTup)
-{
-	Datum   def;
-	Node   *defval;
-	char   *defstr;
-	bool    isnull;
-
-	def = SysCacheGetAttr(TYPEOID, domTup, Anum_pg_type_typdefaultbin,
-						  &isnull);
-	if (isnull)
-		elog(ERROR, "domain \"%s\" does not have a default value",
-			NameStr(((Form_pg_type) GETSTRUCT(domTup))->typname));
-	defval = stringToNode(TextDatumGetCString(def));
-	defstr = deparse_expression_pretty(defval, NULL /* dpcontext? */,
-									   false, false, 0, 0);
-
-	return defstr;
-}
-
-
-/*
- * Return the defaults values of arguments to a function, as a list of
- * deparsed expressions.
- */
-List *
-FunctionGetDefaults(text *proargdefaults)
-{
-	List   *nodedefs;
-	List   *strdefs = NIL;
-	ListCell *cell;
-
-	nodedefs = (List *) stringToNode(TextDatumGetCString(proargdefaults));
-	if (!IsA(nodedefs, List))
-		elog(ERROR, "proargdefaults is not a list");
-
-	foreach(cell, nodedefs)
-	{
-		Node   *onedef = lfirst(cell);
-
-		strdefs = lappend(strdefs, deparse_expression_pretty(onedef, NIL, false, false, 0, 0));
-	}
-
-	return strdefs;
-}
-
-
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index cde659f..d14bb8f 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -121,10 +121,6 @@ extern char *format_type_be_qualified(Oid type_oid);
 extern char *format_type_with_typemod(Oid type_oid, int32 typemod);
 
 extern int32 type_maximum_size(Oid type_oid, int32 typemod);
-extern void format_type_detailed(Oid type_oid, int32 typemod,
-                    Oid *nspid, char **typname,
-                    char **typemodstr, bool *is_array);
-
 
 /* quote.c */
 extern char *quote_literal_cstr(const char *rawstr);
diff --git a/src/include/utils/ruleutils.h b/src/include/utils/ruleutils.h
index 83c242d..e359c90 100644
--- a/src/include/utils/ruleutils.h
+++ b/src/include/utils/ruleutils.h
@@ -24,17 +24,11 @@ struct PlannedStmt;
 
 extern char *pg_get_indexdef_string(Oid indexrelid);
 extern char *pg_get_indexdef_columns(Oid indexrelid, bool pretty);
-extern void pg_get_indexdef_detailed(Oid indexrelid,
-                        char **index_am,
-                        char **definition,
-                        char **reloptions,
-                        char **tablespace,
-                        char **whereClause);
 extern char *pg_get_trigger_whenclause(Form_pg_trigger trigrec,
 									   Node *whenClause, bool pretty);
 extern char *pg_get_constraintdef_string(Oid constraintId, bool fullCommand);
 extern char *pg_get_constraintdef_command(Oid constraintId);
-extern void pg_get_ruledef_details(Datum ev_qual, Datum ev_action,
+extern void pg_get_ruledef_detailed(Datum ev_qual, Datum ev_action,
 								   char **whereClause, List **actions);
 extern char *pg_get_viewdef_internal(Oid viewoid);
 extern char *pg_get_createtableas_def(Query *query);
@@ -53,13 +47,10 @@ extern List *set_deparse_context_plan(List *dpcontext,
 									  struct Plan *plan, List *ancestors);
 extern List *select_rtable_names_for_explain(List *rtable,
 											 Bitmapset *rels_used);
+extern void get_opclass_name(Oid opclass, Oid actual_datatype,
+							 StringInfo buf);
 extern char *generate_collation_name(Oid collid);
-extern List *FunctionGetDefaults(text *proargdefaults);
-
-extern char *RelationGetColumnDefault(Relation rel, AttrNumber attno,
-                        List *dpcontext);
-
-extern char *DomainGetDefault(HeapTuple domTup);
+extern char *flatten_reloptions(Oid relid);
 extern char *generate_opclass_name(Oid opclass);
 extern char *get_range_partbound_string(List *bound_datums);
 
-- 
1.8.3.1

