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.
This commit is contained in:
parent
a6a80134e3
commit
76b6aa41f4
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user