commit 708fe3468d0f373c2208ae927d0de52247f2fda8
Author: Lukas Fittl <lukas@fittl.com>
Date:   Sun Jan 3 15:06:25 2021 -0800

    pg_query: Allow passing $i numbered parameters in more places
    
    Due to pg_stat_statements using $1, etc for substitution of constants, the
    parser needs to support additional locations where these values are
    allowed to be passed in.
    
    Examples:
    
    CREATE USER test PASSWORD $1;
    ALTER USER test ENCRYPTED PASSWORD $2;
    SET SCHEMA $3;
    SET ROLE $4;
    SET SESSION AUTHORIZATION $5;
    SET TIME ZONE $6;
    SELECT EXTRACT($1 FROM TIMESTAMP $2);
    SELECT DATE $1;
    SELECT INTERVAL $1;
    SELECT INTERVAL $1 YEAR;
    SELECT INTERVAL (6) $1;

diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 215d47e5a2..452e17edf2 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -177,6 +177,8 @@ static Node *makeBoolAConst(bool state, int location);
 static Node *makeBitStringConst(char *str, int location);
 static Node *makeNullAConst(int location);
 static Node *makeAConst(Node *v, int location);
+static Node *makeParamRef(int number, int location);
+static Node *makeParamRefCast(int number, int location, TypeName *typename);
 static RoleSpec *makeRoleSpec(RoleSpecType type, int location);
 static void check_qualified_name(List *names, core_yyscan_t yyscanner);
 static List *check_func_name(List *names, core_yyscan_t yyscanner);
@@ -1210,6 +1212,11 @@ AlterOptRoleElem:
 					$$ = makeDefElem("password",
 									 (Node *) makeString($2), @1);
 				}
+			| PASSWORD PARAM
+				{
+					$$ = makeDefElem("password",
+						(Node *)makeParamRef($2, @2), @1);
+				}
 			| PASSWORD NULL_P
 				{
 					$$ = makeDefElem("password", NULL, @1);
@@ -1224,6 +1231,16 @@ AlterOptRoleElem:
 					$$ = makeDefElem("password",
 									 (Node *) makeString($3), @1);
 				}
+			| ENCRYPTED PASSWORD PARAM
+				{
+					/*
+					 * These days, passwords are always stored in encrypted
+					 * form, so there is no difference between PASSWORD and
+					 * ENCRYPTED PASSWORD.
+					 */
+					$$ = makeDefElem("password",
+									 (Node *)makeParamRef($3, @3), @1);
+				}
 			| UNENCRYPTED PASSWORD Sconst
 				{
 					ereport(ERROR,
@@ -1737,6 +1754,14 @@ set_rest_more:	/* Generic SET syntaxes: */
 					n->args = list_make1(makeStringConst($2, @2));
 					$$ = n;
 				}
+			| SCHEMA PARAM
+				{
+					VariableSetStmt *n = makeNode(VariableSetStmt);
+					n->kind = VAR_SET_VALUE;
+					n->name = "search_path";
+					n->args = list_make1(makeParamRef($2, @2));
+					$$ = n;
+				}
 			| NAMES opt_encoding
 				{
 					VariableSetStmt *n = makeNode(VariableSetStmt);
@@ -1758,6 +1783,14 @@ set_rest_more:	/* Generic SET syntaxes: */
 					n->args = list_make1(makeStringConst($2, @2));
 					$$ = n;
 				}
+			| ROLE PARAM
+				{
+					VariableSetStmt *n = makeNode(VariableSetStmt);
+					n->kind = VAR_SET_VALUE;
+					n->name = "role";
+					n->args = list_make1(makeParamRef($2, @2));
+					$$ = n;
+				}
 			| SESSION AUTHORIZATION NonReservedWord_or_Sconst
 				{
 					VariableSetStmt *n = makeNode(VariableSetStmt);
@@ -1767,6 +1800,14 @@ set_rest_more:	/* Generic SET syntaxes: */
 					n->args = list_make1(makeStringConst($3, @3));
 					$$ = n;
 				}
+			| SESSION AUTHORIZATION PARAM
+				{
+					VariableSetStmt *n = makeNode(VariableSetStmt);
+					n->kind = VAR_SET_VALUE;
+					n->name = "session_authorization";
+					n->args = list_make1(makeParamRef($3, @3));
+					$$ = n;
+				}
 			| SESSION AUTHORIZATION DEFAULT
 				{
 					VariableSetStmt *n = makeNode(VariableSetStmt);
@@ -1809,6 +1850,8 @@ var_value:	opt_boolean_or_string
 				{ $$ = makeStringConst($1, @1); }
 			| NumericOnly
 				{ $$ = makeAConst($1, @1); }
+			| PARAM
+				{ $$ = makeParamRef($1, @1); }
 		;
 
 iso_level:	READ UNCOMMITTED						{ $$ = "read uncommitted"; }
@@ -1842,6 +1885,10 @@ zone_value:
 				{
 					$$ = makeStringConst($1, @1);
 				}
+			| PARAM
+				{
+					$$ = makeParamRef($1, @1);
+				}
 			| IDENT
 				{
 					$$ = makeStringConst($1, @1);
@@ -16590,6 +16637,10 @@ extract_list:
 				{
 					$$ = list_make2(makeStringConst($1, @1), $3);
 				}
+			| PARAM FROM a_expr
+				{
+					$$ = list_make2(makeParamRef($1, @1), $3);
+				}
 		;
 
 /* Allow delimited string Sconst in extract_arg as an SQL extension.
@@ -17246,6 +17297,45 @@ AexprConst: Iconst
 					t->location = @1;
 					$$ = makeStringConstCast($6, @6, t);
 				}
+			| func_name PARAM
+				{
+					/* generic type 'literal' syntax */
+					TypeName *t = makeTypeNameFromNameList($1);
+					t->location = @1;
+					$$ = makeParamRefCast($2, @2, t);
+				}
+			| func_name '(' func_arg_list opt_sort_clause ')' PARAM
+				{
+					/* generic syntax with a type modifier */
+					TypeName *t = makeTypeNameFromNameList($1);
+					ListCell *lc;
+
+					/*
+					 * We must use func_arg_list and opt_sort_clause in the
+					 * production to avoid reduce/reduce conflicts, but we
+					 * don't actually wish to allow NamedArgExpr in this
+					 * context, nor ORDER BY.
+					 */
+					foreach(lc, $3)
+					{
+						NamedArgExpr *arg = (NamedArgExpr *) lfirst(lc);
+
+						if (IsA(arg, NamedArgExpr))
+							ereport(ERROR,
+									(errcode(ERRCODE_SYNTAX_ERROR),
+									 errmsg("type modifier cannot have parameter name"),
+									 parser_errposition(arg->location)));
+					}
+					if ($4 != NIL)
+							ereport(ERROR,
+									(errcode(ERRCODE_SYNTAX_ERROR),
+									 errmsg("type modifier cannot have ORDER BY"),
+									 parser_errposition(@4)));
+
+					t->typmods = $3;
+					t->location = @1;
+					$$ = makeParamRefCast($6, @6, t);
+				}
 			| ConstTypename Sconst
 				{
 					$$ = makeStringConstCast($2, @2, $1);
@@ -17265,6 +17355,23 @@ AexprConst: Iconst
 											makeIntConst($3, @3));
 					$$ = makeStringConstCast($5, @5, t);
 				}
+			| ConstTypename PARAM
+				{
+					$$ = makeParamRefCast($2, @2, $1);
+				}
+			| ConstInterval PARAM opt_interval
+				{
+					TypeName *t = $1;
+					t->typmods = $3;
+					$$ = makeParamRefCast($2, @2, t);
+				}
+			| ConstInterval '(' Iconst ')' PARAM
+				{
+					TypeName *t = $1;
+					t->typmods = list_make2(makeIntConst(INTERVAL_FULL_RANGE, -1),
+											makeIntConst($3, @3));
+					$$ = makeParamRefCast($5, @5, t);
+				}
 			| TRUE_P
 				{
 					$$ = makeBoolAConst(true, @1);
@@ -18698,6 +18805,24 @@ makeAConst(Node *v, int location)
 	return n;
 }
 
+/* makeParamRef
+ * Creates a new ParamRef node
+ */
+static Node* makeParamRef(int number, int location)
+{
+	ParamRef *p = makeNode(ParamRef);
+	p->number = number;
+	p->location = location;
+	return (Node *) p;
+}
+
+static Node *
+makeParamRefCast(int number, int location, TypeName *typename)
+{
+	Node *p = makeParamRef(number, location);
+	return makeTypeCast(p, typename, -1);
+}
+
 /* makeRoleSpec
  * Create a RoleSpec with the given type
  */
