diff --git a/src/backend/parser/parse_param.c b/src/backend/parser/parse_param.c
index 2240284f21..cbd70e3315 100644
--- a/src/backend/parser/parse_param.c
+++ b/src/backend/parser/parse_param.c
@@ -49,6 +49,7 @@ typedef struct VarParamState
 {
 	Oid		  **paramTypes;		/* array of parameter type OIDs */
 	int		   *numParams;		/* number of array entries */
+	bool		haveUnresolved; /* have we made any Params of type UNKNOWN? */
 } VarParamState;
 
 static Node *fixed_paramref_hook(ParseState *pstate, ParamRef *pref);
@@ -87,6 +88,7 @@ setup_parse_variable_parameters(ParseState *pstate,
 
 	parstate->paramTypes = paramTypes;
 	parstate->numParams = numParams;
+	parstate->haveUnresolved = false;
 	pstate->p_ref_hook_state = (void *) parstate;
 	pstate->p_paramref_hook = variable_paramref_hook;
 	pstate->p_coerce_param_hook = variable_coerce_param_hook;
@@ -168,6 +170,10 @@ variable_paramref_hook(ParseState *pstate, ParamRef *pref)
 	if (*pptype == VOIDOID && pstate->p_expr_kind == EXPR_KIND_CALL_ARGUMENT)
 		*pptype = UNKNOWNOID;
 
+	/* If we've not yet resolved the type, remember we need to fix it later */
+	if (*pptype == UNKNOWNOID)
+		parstate->haveUnresolved = true;
+
 	param = makeNode(Param);
 	param->paramkind = PARAM_EXTERN;
 	param->paramid = paramno;
@@ -257,30 +263,31 @@ variable_coerce_param_hook(ParseState *pstate, Param *param,
 }
 
 /*
- * Check for consistent assignment of variable parameters after completion
+ * Check for complete assignment of variable parameters after completion
  * of parsing with parse_variable_parameters.
  *
  * Note: this code intentionally does not check that all parameter positions
- * were used, nor that all got non-UNKNOWN types assigned.  Caller of parser
- * should enforce that if it's important.
+ * were used.  Caller of parser should enforce that if it's important.
  */
 void
 check_variable_parameters(ParseState *pstate, Query *query)
 {
 	VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state;
 
-	/* If numParams is zero then no Params were generated, so no work */
-	if (*parstate->numParams > 0)
+	/* Needn't do anything unless we made some UNKNOWN Params */
+	if (parstate->haveUnresolved)
 		(void) query_tree_walker(query,
 								 check_parameter_resolution_walker,
 								 (void *) pstate, 0);
 }
 
 /*
- * Traverse a fully-analyzed tree to verify that parameter symbols
- * match their types.  We need this because some Params might still
- * be UNKNOWN, if there wasn't anything to force their coercion,
- * and yet other instances seen later might have gotten coerced.
+ * Traverse a fully-analyzed tree to back-fill any Params whose types were not
+ * determined at creation or during local parse analysis.  This would only be
+ * possible in contexts where we did not have any need to force immediate
+ * resolution of the Param's type, for example "SELECT ... WHERE $1 IS NULL".
+ * If we have no other clue about the type of such a Param, resolve it as
+ * text, following the precedent of unknown-type literals.
  */
 static bool
 check_parameter_resolution_walker(Node *node, ParseState *pstate)
@@ -295,6 +302,7 @@ check_parameter_resolution_walker(Node *node, ParseState *pstate)
 		{
 			VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state;
 			int			paramno = param->paramid;
+			Oid			resolvedType;
 
 			if (paramno <= 0 || /* shouldn't happen, but... */
 				paramno > *parstate->numParams)
@@ -303,7 +311,26 @@ check_parameter_resolution_walker(Node *node, ParseState *pstate)
 						 errmsg("there is no parameter $%d", paramno),
 						 parser_errposition(pstate, param->location)));
 
-			if (param->paramtype != (*parstate->paramTypes)[paramno - 1])
+			resolvedType = (*parstate->paramTypes)[paramno - 1];
+
+			/* If no use of the Param identified a type, resolve it as TEXT */
+			if (resolvedType == UNKNOWNOID)
+			{
+				resolvedType = TEXTOID;
+				(*parstate->paramTypes)[paramno - 1] = resolvedType;
+			}
+
+			/* If this particular Param wasn't resolved previously, fix it */
+			if (param->paramtype == UNKNOWNOID)
+			{
+				param->paramtype = resolvedType;
+				/* Update typmod and collation the same as above */
+				param->paramtypmod = -1;
+				param->paramcollid = get_typcollation(resolvedType);
+			}
+
+			/* Cross-check, just for paranoia */
+			else if (param->paramtype != resolvedType)
 				ereport(ERROR,
 						(errcode(ERRCODE_AMBIGUOUS_PARAMETER),
 						 errmsg("could not determine data type of parameter $%d",
