summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/commands/functioncmds.c25
-rw-r--r--src/backend/nodes/copyfuncs.c1
-rw-r--r--src/backend/nodes/equalfuncs.c1
-rw-r--r--src/backend/parser/analyze.c45
-rw-r--r--src/backend/tcop/utility.c2
-rw-r--r--src/include/commands/defrem.h3
-rw-r--r--src/include/nodes/parsenodes.h3
-rw-r--r--src/pl/plpgsql/src/expected/plpgsql_call.out19
-rw-r--r--src/pl/plpgsql/src/sql/plpgsql_call.sql18
-rw-r--r--src/test/regress/expected/create_procedure.out16
-rw-r--r--src/test/regress/sql/create_procedure.sql15
11 files changed, 124 insertions, 24 deletions
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index a027b19744a..abdfa249c01 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -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;
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 82255b0d1da..266a3ef8ef6 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -3231,6 +3231,7 @@ _copyCallStmt(const CallStmt *from)
CallStmt *newnode = makeNode(CallStmt);
COPY_NODE_FIELD(funccall);
+ COPY_NODE_FIELD(funcexpr);
return newnode;
}
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index b9bc8e38d74..bbffc878423 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1206,6 +1206,7 @@ static bool
_equalCallStmt(const CallStmt *a, const CallStmt *b)
{
COMPARE_NODE_FIELD(funccall);
+ COMPARE_NODE_FIELD(funcexpr);
return true;
}
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 5b3a610cf9f..c3a9617f67f 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -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.
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 8c23ee53e2b..f78efdf359a 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -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;
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index f510f40945b..c829abfea7e 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -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,
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index c7a43b8933f..ac292bc6e7a 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -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
diff --git a/src/pl/plpgsql/src/expected/plpgsql_call.out b/src/pl/plpgsql/src/expected/plpgsql_call.out
index d0f35163bce..e2442c603cd 100644
--- a/src/pl/plpgsql/src/expected/plpgsql_call.out
+++ b/src/pl/plpgsql/src/expected/plpgsql_call.out
@@ -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;
diff --git a/src/pl/plpgsql/src/sql/plpgsql_call.sql b/src/pl/plpgsql/src/sql/plpgsql_call.sql
index 38fd220e8fa..321ed43af8e 100644
--- a/src/pl/plpgsql/src/sql/plpgsql_call.sql
+++ b/src/pl/plpgsql/src/sql/plpgsql_call.sql
@@ -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;
diff --git a/src/test/regress/expected/create_procedure.out b/src/test/regress/expected/create_procedure.out
index e7bede24faa..182b325ea1c 100644
--- a/src/test/regress/expected/create_procedure.out
+++ b/src/test/regress/expected/create_procedure.out
@@ -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
diff --git a/src/test/regress/sql/create_procedure.sql b/src/test/regress/sql/create_procedure.sql
index 774c12ee34b..52318bf2a69 100644
--- a/src/test/regress/sql/create_procedure.sql
+++ b/src/test/regress/sql/create_procedure.sql
@@ -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