@@ -46,14 +46,14 @@ plpgsql_check_CallExprGetRowTarget(PLpgSQL_checkstate *cstate, PLpgSQL_expr *Cal
4646 {
4747 PLpgSQL_row * row ;
4848 CachedPlanSource * plansource ;
49- HeapTuple tuple ;
50- List * funcargs ;
49+ CallStmt * stmt ;
50+ HeapTuple tuple ;
5151 Oid * argtypes ;
5252 char * * argnames ;
5353 char * argmodes ;
54- ListCell * lc ;
5554 int i ;
5655 int nfields = 0 ;
56+ int numargs ;
5757
5858 plansource = plpgsql_check_get_plan_source (cstate , CallExpr -> plan );
5959
@@ -64,7 +64,8 @@ plpgsql_check_CallExprGetRowTarget(PLpgSQL_checkstate *cstate, PLpgSQL_expr *Cal
6464 if (!IsA (node , CallStmt ))
6565 elog (ERROR , "returned row from not a CallStmt" );
6666
67- funcexpr = castNode (CallStmt , node )-> funcexpr ;
67+ stmt = castNode (CallStmt , node );
68+ funcexpr = stmt -> funcexpr ;
6869
6970 /*
7071 * Get the argument modes
@@ -73,43 +74,45 @@ plpgsql_check_CallExprGetRowTarget(PLpgSQL_checkstate *cstate, PLpgSQL_expr *Cal
7374 if (!HeapTupleIsValid (tuple ))
7475 elog (ERROR , "cache lookup failed for function %u" , funcexpr -> funcid );
7576
76- /* Extract function arguments, and expand any named-arg notation */
77- funcargs = expand_function_arguments (funcexpr -> args ,
78- #if PG_VERSION_NUM >= 140000
79- true ,
80- #endif
81- funcexpr -> funcresulttype ,
82- tuple );
83-
84- get_func_arg_info (tuple , & argtypes , & argnames , & argmodes );
77+ /*
78+ * Get the argument names and modes, so that we can deliver on-point error
79+ * messages when something is wrong.
80+ */
81+ numargs = get_func_arg_info (tuple , & argtypes , & argnames , & argmodes );
8582
8683 ReleaseSysCache (tuple );
8784
88- row = palloc0 (sizeof (PLpgSQL_row ));
85+ row = ( PLpgSQL_row * ) palloc0 (sizeof (PLpgSQL_row ));
8986 row -> dtype = PLPGSQL_DTYPE_ROW ;
90- row -> dno = -1 ;
9187 row -> refname = NULL ;
92- row -> lineno = 0 ;
93- row -> varnos = palloc (sizeof (int ) * list_length (funcargs ));
88+ row -> dno = -1 ;
89+ row -> lineno = -1 ;
90+ row -> varnos = (int * ) palloc (numargs * sizeof (int ));
9491
9592 /*
96- * Construct row
93+ * Examine procedure's argument list. Each output arg position should be
94+ * an unadorned plpgsql variable (Datum), which we can insert into the row
95+ * Datum.
9796 */
98- i = 0 ;
99- foreach ( lc , funcargs )
97+ nfields = 0 ;
98+ for ( i = 0 ; i < numargs ; i ++ )
10099 {
101- Node * n = lfirst (lc );
102-
103100 if (argmodes &&
104101 (argmodes [i ] == PROARGMODE_INOUT ||
105102 argmodes [i ] == PROARGMODE_OUT ))
106103 {
104+ Node * n = list_nth (stmt -> outargs , nfields );
105+
107106 if (IsA (n , Param ))
108107 {
109108 Param * param = (Param * ) n ;
109+ int dno ;
110110
111111 /* paramid is offset by 1 (see make_datum_param()) */
112- row -> varnos [nfields ++ ] = param -> paramid - 1 ;
112+ dno = param -> paramid - 1 ;
113+ /* must check assignability now, because grammar can't */
114+ plpgsql_check_is_assignable (cstate -> estate , dno );
115+ row -> varnos [nfields ++ ] = dno ;
113116 }
114117 else
115118 {
@@ -126,9 +129,10 @@ plpgsql_check_CallExprGetRowTarget(PLpgSQL_checkstate *cstate, PLpgSQL_expr *Cal
126129 i + 1 )));
127130 }
128131 }
129- i ++ ;
130132 }
131133
134+ Assert (nfields == list_length (stmt -> outargs ));
135+
132136 row -> nfields = nfields ;
133137
134138 /* Don't return empty row variable */
0 commit comments