From 9de426b08407e42e89a709e5d78f38a85a2b1235 Mon Sep 17 00:00:00 2001
From: Nikita Glukhov <n.gluhov@postgrespro.ru>
Date: Tue, 4 Dec 2018 02:05:11 +0300
Subject: [PATCH 08/13] Add function formats

---
 contrib/pg_stat_statements/pg_stat_statements.c |  6 ++++
 src/backend/nodes/copyfuncs.c                   |  6 ++++
 src/backend/nodes/equalfuncs.c                  |  6 ++++
 src/backend/nodes/outfuncs.c                    |  6 ++++
 src/backend/nodes/readfuncs.c                   |  6 ++++
 src/backend/optimizer/util/clauses.c            |  4 +++
 src/backend/utils/adt/ruleutils.c               | 37 +++++++++++++++++++++----
 src/include/nodes/primnodes.h                   | 11 ++++++++
 8 files changed, 76 insertions(+), 6 deletions(-)

diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 33f9a79..7f770d2 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -2481,11 +2481,13 @@ JumbleExpr(pgssJumbleState *jstate, Node *node)
 				Aggref	   *expr = (Aggref *) node;
 
 				APP_JUMB(expr->aggfnoid);
+				APP_JUMB(expr->aggformat);
 				JumbleExpr(jstate, (Node *) expr->aggdirectargs);
 				JumbleExpr(jstate, (Node *) expr->args);
 				JumbleExpr(jstate, (Node *) expr->aggorder);
 				JumbleExpr(jstate, (Node *) expr->aggdistinct);
 				JumbleExpr(jstate, (Node *) expr->aggfilter);
+				JumbleExpr(jstate, (Node *) expr->aggformatopts);
 			}
 			break;
 		case T_GroupingFunc:
@@ -2501,8 +2503,10 @@ JumbleExpr(pgssJumbleState *jstate, Node *node)
 
 				APP_JUMB(expr->winfnoid);
 				APP_JUMB(expr->winref);
+				APP_JUMB(expr->winformat);
 				JumbleExpr(jstate, (Node *) expr->args);
 				JumbleExpr(jstate, (Node *) expr->aggfilter);
+				JumbleExpr(jstate, (Node *) expr->winformatopts);
 			}
 			break;
 		case T_ArrayRef:
@@ -2520,7 +2524,9 @@ JumbleExpr(pgssJumbleState *jstate, Node *node)
 				FuncExpr   *expr = (FuncExpr *) node;
 
 				APP_JUMB(expr->funcid);
+				APP_JUMB(expr->funcformat2);
 				JumbleExpr(jstate, (Node *) expr->args);
+				JumbleExpr(jstate, (Node *) expr->funcformatopts);
 			}
 			break;
 		case T_NamedArgExpr:
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index db49968..30c234e 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -1441,6 +1441,8 @@ _copyAggref(const Aggref *from)
 	COPY_SCALAR_FIELD(aggkind);
 	COPY_SCALAR_FIELD(agglevelsup);
 	COPY_SCALAR_FIELD(aggsplit);
+	COPY_SCALAR_FIELD(aggformat);
+	COPY_NODE_FIELD(aggformatopts);
 	COPY_LOCATION_FIELD(location);
 
 	return newnode;
@@ -1480,6 +1482,8 @@ _copyWindowFunc(const WindowFunc *from)
 	COPY_SCALAR_FIELD(winref);
 	COPY_SCALAR_FIELD(winstar);
 	COPY_SCALAR_FIELD(winagg);
+	COPY_SCALAR_FIELD(winformat);
+	COPY_NODE_FIELD(winformatopts);
 	COPY_LOCATION_FIELD(location);
 
 	return newnode;
@@ -1521,6 +1525,8 @@ _copyFuncExpr(const FuncExpr *from)
 	COPY_SCALAR_FIELD(funccollid);
 	COPY_SCALAR_FIELD(inputcollid);
 	COPY_NODE_FIELD(args);
+	COPY_SCALAR_FIELD(funcformat2);
+	COPY_NODE_FIELD(funcformatopts);
 	COPY_LOCATION_FIELD(location);
 
 	return newnode;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 3a084b4..edfcb78 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -226,6 +226,8 @@ _equalAggref(const Aggref *a, const Aggref *b)
 	COMPARE_SCALAR_FIELD(aggkind);
 	COMPARE_SCALAR_FIELD(agglevelsup);
 	COMPARE_SCALAR_FIELD(aggsplit);
+	COMPARE_SCALAR_FIELD(aggformat);
+	COMPARE_NODE_FIELD(aggformatopts);
 	COMPARE_LOCATION_FIELD(location);
 
 	return true;
@@ -258,6 +260,8 @@ _equalWindowFunc(const WindowFunc *a, const WindowFunc *b)
 	COMPARE_SCALAR_FIELD(winref);
 	COMPARE_SCALAR_FIELD(winstar);
 	COMPARE_SCALAR_FIELD(winagg);
+	COMPARE_SCALAR_FIELD(winformat);
+	COMPARE_NODE_FIELD(winformatopts);
 	COMPARE_LOCATION_FIELD(location);
 
 	return true;
@@ -289,6 +293,8 @@ _equalFuncExpr(const FuncExpr *a, const FuncExpr *b)
 	COMPARE_SCALAR_FIELD(funccollid);
 	COMPARE_SCALAR_FIELD(inputcollid);
 	COMPARE_NODE_FIELD(args);
+	COMPARE_SCALAR_FIELD(funcformat2);
+	COMPARE_NODE_FIELD(funcformatopts);
 	COMPARE_LOCATION_FIELD(location);
 
 	return true;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index f0c3965..b884bb8 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -1219,6 +1219,8 @@ _outAggref(StringInfo str, const Aggref *node)
 	WRITE_CHAR_FIELD(aggkind);
 	WRITE_UINT_FIELD(agglevelsup);
 	WRITE_ENUM_FIELD(aggsplit, AggSplit);
+	WRITE_ENUM_FIELD(aggformat, FuncFormat);
+	WRITE_NODE_FIELD(aggformatopts);
 	WRITE_LOCATION_FIELD(location);
 }
 
@@ -1248,6 +1250,8 @@ _outWindowFunc(StringInfo str, const WindowFunc *node)
 	WRITE_UINT_FIELD(winref);
 	WRITE_BOOL_FIELD(winstar);
 	WRITE_BOOL_FIELD(winagg);
+	WRITE_ENUM_FIELD(winformat, FuncFormat);
+	WRITE_NODE_FIELD(winformatopts);
 	WRITE_LOCATION_FIELD(location);
 }
 
@@ -1279,6 +1283,8 @@ _outFuncExpr(StringInfo str, const FuncExpr *node)
 	WRITE_OID_FIELD(funccollid);
 	WRITE_OID_FIELD(inputcollid);
 	WRITE_NODE_FIELD(args);
+	WRITE_ENUM_FIELD(funcformat2, FuncFormat);
+	WRITE_NODE_FIELD(funcformatopts);
 	WRITE_LOCATION_FIELD(location);
 }
 
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index e117867..cc55517 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -611,6 +611,8 @@ _readAggref(void)
 	READ_CHAR_FIELD(aggkind);
 	READ_UINT_FIELD(agglevelsup);
 	READ_ENUM_FIELD(aggsplit, AggSplit);
+	READ_ENUM_FIELD(aggformat, FuncFormat);
+	READ_NODE_FIELD(aggformatopts);
 	READ_LOCATION_FIELD(location);
 
 	READ_DONE();
@@ -650,6 +652,8 @@ _readWindowFunc(void)
 	READ_UINT_FIELD(winref);
 	READ_BOOL_FIELD(winstar);
 	READ_BOOL_FIELD(winagg);
+	READ_ENUM_FIELD(winformat, FuncFormat);
+	READ_NODE_FIELD(winformatopts);
 	READ_LOCATION_FIELD(location);
 
 	READ_DONE();
@@ -691,6 +695,8 @@ _readFuncExpr(void)
 	READ_OID_FIELD(funccollid);
 	READ_OID_FIELD(inputcollid);
 	READ_NODE_FIELD(args);
+	READ_ENUM_FIELD(funcformat2, FuncFormat);
+	READ_NODE_FIELD(funcformatopts);
 	READ_LOCATION_FIELD(location);
 
 	READ_DONE();
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 8df3693..4413d03 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -2692,6 +2692,8 @@ eval_const_expressions_mutator(Node *node,
 				newexpr->winref = expr->winref;
 				newexpr->winstar = expr->winstar;
 				newexpr->winagg = expr->winagg;
+				newexpr->winformat = expr->winformat;
+				newexpr->winformatopts = copyObject(expr->winformatopts);
 				newexpr->location = expr->location;
 
 				return (Node *) newexpr;
@@ -2738,6 +2740,8 @@ eval_const_expressions_mutator(Node *node,
 				newexpr->funccollid = expr->funccollid;
 				newexpr->inputcollid = expr->inputcollid;
 				newexpr->args = args;
+				newexpr->funcformat2 = expr->funcformat2;
+				newexpr->funcformatopts = copyObject(expr->funcformatopts);
 				newexpr->location = expr->location;
 				return (Node *) newexpr;
 			}
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 3c84f91..46ddc35 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -9045,6 +9045,16 @@ get_oper_expr(OpExpr *expr, deparse_context *context)
 		appendStringInfoChar(buf, ')');
 }
 
+static void
+get_func_opts(FuncFormat aggformat, Node *aggformatopts, deparse_context *context)
+{
+	switch (aggformat)
+	{
+		default:
+			break;
+	}
+}
+
 /*
  * get_func_expr			- Parse back a FuncExpr node
  */
@@ -9059,6 +9069,7 @@ get_func_expr(FuncExpr *expr, deparse_context *context,
 	List	   *argnames;
 	bool		use_variadic;
 	ListCell   *l;
+	const char *funcname;
 
 	/*
 	 * If the function call came from an implicit coercion, then just show the
@@ -9113,12 +9124,19 @@ get_func_expr(FuncExpr *expr, deparse_context *context,
 		nargs++;
 	}
 
-	appendStringInfo(buf, "%s(",
-					 generate_function_name(funcoid, nargs,
-											argnames, argtypes,
-											expr->funcvariadic,
-											&use_variadic,
-											context->special_exprkind));
+	switch (expr->funcformat2)
+	{
+		default:
+			funcname = generate_function_name(funcoid, nargs,
+											  argnames, argtypes,
+											  expr->funcvariadic,
+											  &use_variadic,
+											  context->special_exprkind);
+			break;
+	}
+
+	appendStringInfo(buf, "%s(", funcname);
+
 	nargs = 0;
 	foreach(l, expr->args)
 	{
@@ -9128,6 +9146,9 @@ get_func_expr(FuncExpr *expr, deparse_context *context,
 			appendStringInfoString(buf, "VARIADIC ");
 		get_rule_expr((Node *) lfirst(l), context, true);
 	}
+
+	get_func_opts(expr->funcformat2, expr->funcformatopts, context);
+
 	appendStringInfoChar(buf, ')');
 }
 
@@ -9226,6 +9247,8 @@ get_agg_expr(Aggref *aggref, deparse_context *context,
 		}
 	}
 
+	get_func_opts(aggref->aggformat, aggref->aggformatopts, context);
+
 	if (aggref->aggfilter != NULL)
 	{
 		appendStringInfoString(buf, ") FILTER (WHERE ");
@@ -9292,6 +9315,8 @@ get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context)
 	else
 		get_rule_expr((Node *) wfunc->args, context, true);
 
+	get_func_opts(wfunc->winformat, wfunc->winformatopts, context);
+
 	if (wfunc->aggfilter != NULL)
 	{
 		appendStringInfoString(buf, ") FILTER (WHERE ");
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 67533d4..ecf6ff6 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -252,6 +252,11 @@ typedef struct Param
 	int			location;		/* token location, or -1 if unknown */
 } Param;
 
+typedef enum FuncFormat
+{
+	FUNCFMT_REGULAR = 0,
+} FuncFormat;
+
 /*
  * Aggref
  *
@@ -311,6 +316,8 @@ typedef struct Aggref
 	char		aggkind;		/* aggregate kind (see pg_aggregate.h) */
 	Index		agglevelsup;	/* > 0 if agg belongs to outer query */
 	AggSplit	aggsplit;		/* expected agg-splitting mode of parent Agg */
+	FuncFormat	aggformat;		/* how to display this aggregate */
+	Node	   *aggformatopts;	/* display options, if any */
 	int			location;		/* token location, or -1 if unknown */
 } Aggref;
 
@@ -364,6 +371,8 @@ typedef struct WindowFunc
 	Index		winref;			/* index of associated WindowClause */
 	bool		winstar;		/* true if argument list was really '*' */
 	bool		winagg;			/* is function a simple aggregate? */
+	FuncFormat	winformat;		/* how to display this window function */
+	Node	   *winformatopts;	/* display options, if any */
 	int			location;		/* token location, or -1 if unknown */
 } WindowFunc;
 
@@ -459,6 +468,8 @@ typedef struct FuncExpr
 	Oid			funccollid;		/* OID of collation of result */
 	Oid			inputcollid;	/* OID of collation that function should use */
 	List	   *args;			/* arguments to the function */
+	FuncFormat	funcformat2;	/* how to display this function call */
+	Node	   *funcformatopts;	/* display options, if any */
 	int			location;		/* token location, or -1 if unknown */
 } FuncExpr;
 
-- 
2.7.4

