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)
* 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;
......@@ -2228,24 +2226,8 @@ ExecuteCallStmt(ParseState *pstate, CallStmt *stmt, bool atomic)
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)
......@@ -2289,6 +2271,7 @@ ExecuteCallStmt(ParseState *pstate, CallStmt *stmt, bool atomic)
* we can't free this context till the procedure returns.
*/
estate = CreateExecutorState();
estate->es_param_list_info = params;
econtext = CreateExprContext(estate);
i = 0;
......
......@@ -3231,6 +3231,7 @@ _copyCallStmt(const CallStmt *from)
CallStmt *newnode = makeNode(CallStmt);
COPY_NODE_FIELD(funccall);
COPY_NODE_FIELD(funcexpr);
return newnode;
}
......
......@@ -1206,6 +1206,7 @@ static bool
_equalCallStmt(const CallStmt *a, const CallStmt *b)
{
COMPARE_NODE_FIELD(funccall);
COMPARE_NODE_FIELD(funcexpr);
return true;
}
......
......@@ -36,6 +36,8 @@
#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"
......@@ -74,6 +76,8 @@ static Query *transformExplainStmt(ParseState *pstate,
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
......@@ -318,6 +322,10 @@ transformStmt(ParseState *pstate, Node *parseTree)
(CreateTableAsStmt *) parseTree);
break;
case T_CallStmt:
result = transformCallStmt(pstate,
(CallStmt *) parseTree);
default:
/*
......@@ -2571,6 +2579,43 @@ transformCreateTableAsStmt(ParseState *pstate, CreateTableAsStmt *stmt)
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.
......
......@@ -660,7 +660,7 @@ standard_ProcessUtility(PlannedStmt *pstmt,
break;
case T_CallStmt:
ExecuteCallStmt(pstate, castNode(CallStmt, parsetree),
ExecuteCallStmt(castNode(CallStmt, parsetree), params,
(context != PROCESS_UTILITY_TOPLEVEL || IsTransactionBlock()));
break;
......
......@@ -15,6 +15,7 @@
#define DEFREM_H
#include "catalog/objectaddress.h"
#include "nodes/params.h"
#include "nodes/parsenodes.h"
#include "utils/array.h"
......@@ -61,7 +62,7 @@ extern void DropTransformById(Oid transformOid);
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,
......
......@@ -2814,7 +2814,8 @@ typedef struct InlineCodeBlock
typedef struct CallStmt
{
NodeTag type;
FuncCall *funccall;
FuncCall *funccall; /* from the parser */
FuncExpr *funcexpr; /* transformed */
} CallStmt;
typedef struct CallContext
......
......@@ -35,7 +35,26 @@ SELECT * FROM test1;
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;
......@@ -40,8 +40,26 @@ CALL test_proc3(55);
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;
......@@ -55,6 +55,22 @@ AS $$
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
......
......@@ -31,6 +31,21 @@ $$;
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
......
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