Commit 76b6aa41 authored by Peter Eisentraut's avatar Peter Eisentraut

Support parameters in CALL

To support parameters in CALL, move the parse analysis of the procedure
and arguments into the global transformation phase, so that the parser
hooks can be applied.  And then at execution time pass the parameters
from ProcessUtility on to ExecuteCallStmt.
parent a6a80134
...@@ -2212,11 +2212,9 @@ ExecuteDoStmt(DoStmt *stmt, bool atomic) ...@@ -2212,11 +2212,9 @@ ExecuteDoStmt(DoStmt *stmt, bool atomic)
* commits that might occur inside the procedure. * commits that might occur inside the procedure.
*/ */
void void
ExecuteCallStmt(ParseState *pstate, CallStmt *stmt, bool atomic) ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic)
{ {
List *targs;
ListCell *lc; ListCell *lc;
Node *node;
FuncExpr *fexpr; FuncExpr *fexpr;
int nargs; int nargs;
int i; int i;
...@@ -2228,24 +2226,8 @@ ExecuteCallStmt(ParseState *pstate, CallStmt *stmt, bool atomic) ...@@ -2228,24 +2226,8 @@ ExecuteCallStmt(ParseState *pstate, CallStmt *stmt, bool atomic)
ExprContext *econtext; ExprContext *econtext;
HeapTuple tp; HeapTuple tp;
/* We need to do parse analysis on the procedure call and its arguments */ fexpr = stmt->funcexpr;
targs = NIL; Assert(fexpr);
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);
aclresult = pg_proc_aclcheck(fexpr->funcid, GetUserId(), ACL_EXECUTE); aclresult = pg_proc_aclcheck(fexpr->funcid, GetUserId(), ACL_EXECUTE);
if (aclresult != ACLCHECK_OK) if (aclresult != ACLCHECK_OK)
...@@ -2289,6 +2271,7 @@ ExecuteCallStmt(ParseState *pstate, CallStmt *stmt, bool atomic) ...@@ -2289,6 +2271,7 @@ ExecuteCallStmt(ParseState *pstate, CallStmt *stmt, bool atomic)
* we can't free this context till the procedure returns. * we can't free this context till the procedure returns.
*/ */
estate = CreateExecutorState(); estate = CreateExecutorState();
estate->es_param_list_info = params;
econtext = CreateExprContext(estate); econtext = CreateExprContext(estate);
i = 0; i = 0;
......
...@@ -3231,6 +3231,7 @@ _copyCallStmt(const CallStmt *from) ...@@ -3231,6 +3231,7 @@ _copyCallStmt(const CallStmt *from)
CallStmt *newnode = makeNode(CallStmt); CallStmt *newnode = makeNode(CallStmt);
COPY_NODE_FIELD(funccall); COPY_NODE_FIELD(funccall);
COPY_NODE_FIELD(funcexpr);
return newnode; return newnode;
} }
......
...@@ -1206,6 +1206,7 @@ static bool ...@@ -1206,6 +1206,7 @@ static bool
_equalCallStmt(const CallStmt *a, const CallStmt *b) _equalCallStmt(const CallStmt *a, const CallStmt *b)
{ {
COMPARE_NODE_FIELD(funccall); COMPARE_NODE_FIELD(funccall);
COMPARE_NODE_FIELD(funcexpr);
return true; return true;
} }
......
...@@ -36,6 +36,8 @@ ...@@ -36,6 +36,8 @@
#include "parser/parse_coerce.h" #include "parser/parse_coerce.h"
#include "parser/parse_collate.h" #include "parser/parse_collate.h"
#include "parser/parse_cte.h" #include "parser/parse_cte.h"
#include "parser/parse_expr.h"
#include "parser/parse_func.h"
#include "parser/parse_oper.h" #include "parser/parse_oper.h"
#include "parser/parse_param.h" #include "parser/parse_param.h"
#include "parser/parse_relation.h" #include "parser/parse_relation.h"
...@@ -74,6 +76,8 @@ static Query *transformExplainStmt(ParseState *pstate, ...@@ -74,6 +76,8 @@ static Query *transformExplainStmt(ParseState *pstate,
ExplainStmt *stmt); ExplainStmt *stmt);
static Query *transformCreateTableAsStmt(ParseState *pstate, static Query *transformCreateTableAsStmt(ParseState *pstate,
CreateTableAsStmt *stmt); CreateTableAsStmt *stmt);
static Query *transformCallStmt(ParseState *pstate,
CallStmt *stmt);
static void transformLockingClause(ParseState *pstate, Query *qry, static void transformLockingClause(ParseState *pstate, Query *qry,
LockingClause *lc, bool pushedDown); LockingClause *lc, bool pushedDown);
#ifdef RAW_EXPRESSION_COVERAGE_TEST #ifdef RAW_EXPRESSION_COVERAGE_TEST
...@@ -318,6 +322,10 @@ transformStmt(ParseState *pstate, Node *parseTree) ...@@ -318,6 +322,10 @@ transformStmt(ParseState *pstate, Node *parseTree)
(CreateTableAsStmt *) parseTree); (CreateTableAsStmt *) parseTree);
break; break;
case T_CallStmt:
result = transformCallStmt(pstate,
(CallStmt *) parseTree);
default: default:
/* /*
...@@ -2571,6 +2579,43 @@ transformCreateTableAsStmt(ParseState *pstate, CreateTableAsStmt *stmt) ...@@ -2571,6 +2579,43 @@ transformCreateTableAsStmt(ParseState *pstate, CreateTableAsStmt *stmt)
return result; 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. * Produce a string representation of a LockClauseStrength value.
......
...@@ -660,7 +660,7 @@ standard_ProcessUtility(PlannedStmt *pstmt, ...@@ -660,7 +660,7 @@ standard_ProcessUtility(PlannedStmt *pstmt,
break; break;
case T_CallStmt: case T_CallStmt:
ExecuteCallStmt(pstate, castNode(CallStmt, parsetree), ExecuteCallStmt(castNode(CallStmt, parsetree), params,
(context != PROCESS_UTILITY_TOPLEVEL || IsTransactionBlock())); (context != PROCESS_UTILITY_TOPLEVEL || IsTransactionBlock()));
break; break;
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#define DEFREM_H #define DEFREM_H
#include "catalog/objectaddress.h" #include "catalog/objectaddress.h"
#include "nodes/params.h"
#include "nodes/parsenodes.h" #include "nodes/parsenodes.h"
#include "utils/array.h" #include "utils/array.h"
...@@ -61,7 +62,7 @@ extern void DropTransformById(Oid transformOid); ...@@ -61,7 +62,7 @@ extern void DropTransformById(Oid transformOid);
extern void IsThereFunctionInNamespace(const char *proname, int pronargs, extern void IsThereFunctionInNamespace(const char *proname, int pronargs,
oidvector *proargtypes, Oid nspOid); oidvector *proargtypes, Oid nspOid);
extern void ExecuteDoStmt(DoStmt *stmt, bool atomic); 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_cast_oid(Oid sourcetypeid, Oid targettypeid, bool missing_ok);
extern Oid get_transform_oid(Oid type_id, Oid lang_id, 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, extern void interpret_function_parameter_list(ParseState *pstate,
......
...@@ -2814,7 +2814,8 @@ typedef struct InlineCodeBlock ...@@ -2814,7 +2814,8 @@ typedef struct InlineCodeBlock
typedef struct CallStmt typedef struct CallStmt
{ {
NodeTag type; NodeTag type;
FuncCall *funccall; FuncCall *funccall; /* from the parser */
FuncExpr *funcexpr; /* transformed */
} CallStmt; } CallStmt;
typedef struct CallContext typedef struct CallContext
......
...@@ -35,7 +35,26 @@ SELECT * FROM test1; ...@@ -35,7 +35,26 @@ SELECT * FROM test1;
55 55
(1 row) (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_proc1;
DROP PROCEDURE test_proc2; DROP PROCEDURE test_proc2;
DROP PROCEDURE test_proc3; DROP PROCEDURE test_proc3;
DROP PROCEDURE test_proc4;
DROP TABLE test1; DROP TABLE test1;
...@@ -40,8 +40,26 @@ CALL test_proc3(55); ...@@ -40,8 +40,26 @@ CALL test_proc3(55);
SELECT * FROM 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_proc1;
DROP PROCEDURE test_proc2; DROP PROCEDURE test_proc2;
DROP PROCEDURE test_proc3; DROP PROCEDURE test_proc3;
DROP PROCEDURE test_proc4;
DROP TABLE test1; DROP TABLE test1;
...@@ -55,6 +55,22 @@ AS $$ ...@@ -55,6 +55,22 @@ AS $$
SELECT 5; SELECT 5;
$$; $$;
CALL ptest2(); 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 -- various error cases
CALL version(); -- error: not a procedure CALL version(); -- error: not a procedure
ERROR: version() is not a procedure ERROR: version() is not a procedure
......
...@@ -31,6 +31,21 @@ $$; ...@@ -31,6 +31,21 @@ $$;
CALL ptest2(); 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 -- various error cases
CALL version(); -- error: not a procedure CALL version(); -- error: not a procedure
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment