@@ -55,6 +55,13 @@ plpgsql_check_CallExprGetRowTarget(PLpgSQL_checkstate *cstate, PLpgSQL_expr *Cal
5555 int nfields = 0 ;
5656 int numargs ;
5757
58+ #if PG_VERSION_NUM < 140000
59+
60+ List * funcargs ;
61+ ListCell * lc ;
62+
63+ #endif
64+
5865 plansource = plpgsql_check_get_plan_source (cstate , CallExpr -> plan );
5966
6067 /*
@@ -74,12 +81,26 @@ plpgsql_check_CallExprGetRowTarget(PLpgSQL_checkstate *cstate, PLpgSQL_expr *Cal
7481 if (!HeapTupleIsValid (tuple ))
7582 elog (ERROR , "cache lookup failed for function %u" , funcexpr -> funcid );
7683
84+ #if PG_VERSION_NUM < 140000
85+
86+ /* Extract function arguments, and expand any named-arg notation */
87+ funcargs = expand_function_arguments (funcexpr -> args ,
88+ funcexpr -> funcresulttype ,
89+ tuple );
90+
91+ get_func_arg_info (tuple , & argtypes , & argnames , & argmodes );
92+ numargs = list_length (funcargs );
93+
94+ #else
95+
7796 /*
7897 * Get the argument names and modes, so that we can deliver on-point error
7998 * messages when something is wrong.
8099 */
81100 numargs = get_func_arg_info (tuple , & argtypes , & argnames , & argmodes );
82101
102+ #endif
103+
83104 ReleaseSysCache (tuple );
84105
85106 row = (PLpgSQL_row * ) palloc0 (sizeof (PLpgSQL_row ));
@@ -89,6 +110,48 @@ plpgsql_check_CallExprGetRowTarget(PLpgSQL_checkstate *cstate, PLpgSQL_expr *Cal
89110 row -> lineno = -1 ;
90111 row -> varnos = (int * ) palloc (numargs * sizeof (int ));
91112
113+ #if PG_VERSION_NUM < 140000
114+
115+ /*
116+ * Construct row
117+ */
118+ i = 0 ;
119+ foreach (lc , funcargs )
120+ {
121+ Node * n = lfirst (lc );
122+
123+ if (argmodes &&
124+ (argmodes [i ] == PROARGMODE_INOUT ||
125+ argmodes [i ] == PROARGMODE_OUT ))
126+ {
127+ if (IsA (n , Param ))
128+ {
129+ Param * param = (Param * ) n ;
130+
131+ /* paramid is offset by 1 (see make_datum_param()) */
132+ row -> varnos [nfields ++ ] = param -> paramid - 1 ;
133+ plpgsql_check_is_assignable (cstate -> estate , param -> paramid - 1 );
134+ }
135+ else
136+ {
137+ /* report error using parameter name, if available */
138+ if (argnames && argnames [i ] && argnames [i ][0 ])
139+ ereport (ERROR ,
140+ (errcode (ERRCODE_SYNTAX_ERROR ),
141+ errmsg ("procedure parameter \"%s\" is an output parameter but corresponding argument is not writable" ,
142+ argnames [i ])));
143+ else
144+ ereport (ERROR ,
145+ (errcode (ERRCODE_SYNTAX_ERROR ),
146+ errmsg ("procedure parameter %d is an output parameter but corresponding argument is not writable" ,
147+ i + 1 )));
148+ }
149+ }
150+ i ++ ;
151+ }
152+
153+ #else
154+
92155 /*
93156 * Examine procedure's argument list. Each output arg position should be
94157 * an unadorned plpgsql variable (Datum), which we can insert into the row
@@ -133,6 +196,8 @@ plpgsql_check_CallExprGetRowTarget(PLpgSQL_checkstate *cstate, PLpgSQL_expr *Cal
133196
134197 Assert (nfields == list_length (stmt -> outargs ));
135198
199+ #endif
200+
136201 row -> nfields = nfields ;
137202
138203 /* Don't return empty row variable */
0 commit comments