* commits that might occur inside the procedure.
*/
void
-ExecuteCallStmt(ParseState *pstate, CallStmt *stmt, bool atomic)
+ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic)
{
- List *targs;
ListCell *lc;
- Node *node;
FuncExpr *fexpr;
int nargs;
int i;
ExprContext *econtext;
HeapTuple tp;
- /* We need to do parse analysis on the procedure call and its arguments */
- targs = NIL;
- foreach(lc, stmt->funccall->args)
- {
- targs = lappend(targs, transformExpr(pstate,
- (Node *) lfirst(lc),
- EXPR_KIND_CALL_ARGUMENT));
- }
-
- node = ParseFuncOrColumn(pstate,
- stmt->funccall->funcname,
- targs,
- pstate->p_last_srf,
- stmt->funccall,
- true,
- stmt->funccall->location);
-
- fexpr = castNode(FuncExpr, node);
+ fexpr = stmt->funcexpr;
+ Assert(fexpr);
aclresult = pg_proc_aclcheck(fexpr->funcid, GetUserId(), ACL_EXECUTE);
if (aclresult != ACLCHECK_OK)
* we can't free this context till the procedure returns.
*/
estate = CreateExecutorState();
+ estate->es_param_list_info = params;
econtext = CreateExprContext(estate);
i = 0;
CallStmt *newnode = makeNode(CallStmt);
COPY_NODE_FIELD(funccall);
+ COPY_NODE_FIELD(funcexpr);
return newnode;
}
_equalCallStmt(const CallStmt *a, const CallStmt *b)
{
COMPARE_NODE_FIELD(funccall);
+ COMPARE_NODE_FIELD(funcexpr);
return true;
}
#include "parser/parse_coerce.h"
#include "parser/parse_collate.h"
#include "parser/parse_cte.h"
+#include "parser/parse_expr.h"
+#include "parser/parse_func.h"
#include "parser/parse_oper.h"
#include "parser/parse_param.h"
#include "parser/parse_relation.h"
ExplainStmt *stmt);
static Query *transformCreateTableAsStmt(ParseState *pstate,
CreateTableAsStmt *stmt);
+static Query *transformCallStmt(ParseState *pstate,
+ CallStmt *stmt);
static void transformLockingClause(ParseState *pstate, Query *qry,
LockingClause *lc, bool pushedDown);
#ifdef RAW_EXPRESSION_COVERAGE_TEST
(CreateTableAsStmt *) parseTree);
break;
+ case T_CallStmt:
+ result = transformCallStmt(pstate,
+ (CallStmt *) parseTree);
+
default:
/*
return result;
}
+/*
+ * transform a CallStmt
+ *
+ * We need to do parse analysis on the procedure call and its arguments.
+ */
+static Query *
+transformCallStmt(ParseState *pstate, CallStmt *stmt)
+{
+ List *targs;
+ ListCell *lc;
+ Node *node;
+ Query *result;
+
+ targs = NIL;
+ foreach(lc, stmt->funccall->args)
+ {
+ targs = lappend(targs, transformExpr(pstate,
+ (Node *) lfirst(lc),
+ EXPR_KIND_CALL_ARGUMENT));
+ }
+
+ node = ParseFuncOrColumn(pstate,
+ stmt->funccall->funcname,
+ targs,
+ pstate->p_last_srf,
+ stmt->funccall,
+ true,
+ stmt->funccall->location);
+
+ stmt->funcexpr = castNode(FuncExpr, node);
+
+ result = makeNode(Query);
+ result->commandType = CMD_UTILITY;
+ result->utilityStmt = (Node *) stmt;
+
+ return result;
+}
/*
* Produce a string representation of a LockClauseStrength value.
break;
case T_CallStmt:
- ExecuteCallStmt(pstate, castNode(CallStmt, parsetree),
+ ExecuteCallStmt(castNode(CallStmt, parsetree), params,
(context != PROCESS_UTILITY_TOPLEVEL || IsTransactionBlock()));
break;
#define DEFREM_H
#include "catalog/objectaddress.h"
+#include "nodes/params.h"
#include "nodes/parsenodes.h"
#include "utils/array.h"
extern void IsThereFunctionInNamespace(const char *proname, int pronargs,
oidvector *proargtypes, Oid nspOid);
extern void ExecuteDoStmt(DoStmt *stmt, bool atomic);
-extern void ExecuteCallStmt(ParseState *pstate, CallStmt *stmt, bool atomic);
+extern void ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic);
extern Oid get_cast_oid(Oid sourcetypeid, Oid targettypeid, bool missing_ok);
extern Oid get_transform_oid(Oid type_id, Oid lang_id, bool missing_ok);
extern void interpret_function_parameter_list(ParseState *pstate,
typedef struct CallStmt
{
NodeTag type;
- FuncCall *funccall;
+ FuncCall *funccall; /* from the parser */
+ FuncExpr *funcexpr; /* transformed */
} CallStmt;
typedef struct CallContext
55
(1 row)
+-- nested CALL
+TRUNCATE TABLE test1;
+CREATE PROCEDURE test_proc4(y int)
+LANGUAGE plpgsql
+AS $$
+BEGIN
+ CALL test_proc3(y);
+ CALL test_proc3($1);
+END;
+$$;
+CALL test_proc4(66);
+SELECT * FROM test1;
+ a
+----
+ 66
+ 66
+(2 rows)
+
DROP PROCEDURE test_proc1;
DROP PROCEDURE test_proc2;
DROP PROCEDURE test_proc3;
+DROP PROCEDURE test_proc4;
DROP TABLE test1;
SELECT * FROM test1;
+-- nested CALL
+TRUNCATE TABLE test1;
+
+CREATE PROCEDURE test_proc4(y int)
+LANGUAGE plpgsql
+AS $$
+BEGIN
+ CALL test_proc3(y);
+ CALL test_proc3($1);
+END;
+$$;
+
+CALL test_proc4(66);
+
+SELECT * FROM test1;
+
+
DROP PROCEDURE test_proc1;
DROP PROCEDURE test_proc2;
DROP PROCEDURE test_proc3;
+DROP PROCEDURE test_proc4;
DROP TABLE test1;
SELECT 5;
$$;
CALL ptest2();
+-- nested CALL
+TRUNCATE cp_test;
+CREATE PROCEDURE ptest3(y text)
+LANGUAGE SQL
+AS $$
+CALL ptest1(y);
+CALL ptest1($1);
+$$;
+CALL ptest3('b');
+SELECT * FROM cp_test;
+ a | b
+---+---
+ 1 | b
+ 1 | b
+(2 rows)
+
-- various error cases
CALL version(); -- error: not a procedure
ERROR: version() is not a procedure
CALL ptest2();
+-- nested CALL
+TRUNCATE cp_test;
+
+CREATE PROCEDURE ptest3(y text)
+LANGUAGE SQL
+AS $$
+CALL ptest1(y);
+CALL ptest1($1);
+$$;
+
+CALL ptest3('b');
+
+SELECT * FROM cp_test;
+
+
-- various error cases
CALL version(); -- error: not a procedure