Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions contrib/file_fdw/expected/ivy_file_fdw.out
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
--
-- Test foreign-data wrapper file_fdw.
--
\set EXECUTE_RUN_PREPARE on
-- directory paths are passed to us in environment variables
\getenv abs_srcdir PG_ABS_SRCDIR
-- Clean up in case a prior regression run failed
Expand Down
1 change: 1 addition & 0 deletions contrib/file_fdw/sql/ivy_file_fdw.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
-- Test foreign-data wrapper file_fdw.
--

\set EXECUTE_RUN_PREPARE on
-- directory paths are passed to us in environment variables
\getenv abs_srcdir PG_ABS_SRCDIR

Expand Down
2 changes: 1 addition & 1 deletion contrib/ivorysql_ora/src/sysview/sysview--1.0.sql
Original file line number Diff line number Diff line change
Expand Up @@ -1086,7 +1086,7 @@ SELECT
decode(bitand(s.flags, 16), 16, 'Y', 'N') AS scale_flag,
decode(bitand(s.flags, 2048), 2048, 'Y', 'N') AS extend_flag,null AS shared_flag,
decode(bitand(s.flags, 64), 64, 'Y', 'N') AS session_flag,null AS keep_value
FROM PG_SEQUENCE s,pg_class c where s.seqrelid = c.oid and c.relowner::regrole = current_user::regrole;
FROM PG_SEQUENCE s,pg_class c where s.seqrelid = c.oid and pg_get_userbyid(c.relowner) = current_user;

CREATE OR REPLACE VIEW SYS.DBA_VIEWS AS
SELECT
Expand Down
1 change: 1 addition & 0 deletions contrib/pg_stat_statements/expected/ivy_squashing.out
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
--
-- Const squashing functionality
--
\set EXECUTE_RUN_PREPARE on
CREATE EXTENSION pg_stat_statements;
--
-- Simple Lists
Expand Down
1 change: 1 addition & 0 deletions contrib/pg_stat_statements/expected/ivy_utility.out
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
--
-- Utility commands
--
\set EXECUTE_RUN_PREPARE on
-- These tests require track_utility to be enabled.
SET pg_stat_statements.track_utility = TRUE;
SELECT pg_stat_statements_reset() IS NOT NULL AS t;
Expand Down
1 change: 1 addition & 0 deletions contrib/pg_stat_statements/expected/planning.out
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
--
-- Information related to planning
--
\set EXECUTE_RUN_PREPARE on
-- These tests require track_planning to be enabled.
SET pg_stat_statements.track_planning = TRUE;
SELECT pg_stat_statements_reset() IS NOT NULL AS t;
Expand Down
1 change: 1 addition & 0 deletions contrib/pg_stat_statements/expected/select.out
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
--
-- SELECT statements
--
\set EXECUTE_RUN_PREPARE on
CREATE EXTENSION pg_stat_statements;
SET pg_stat_statements.track_utility = FALSE;
SET pg_stat_statements.track_planning = TRUE;
Expand Down
1 change: 1 addition & 0 deletions contrib/pg_stat_statements/sql/ivy_squashing.sql
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
--
-- Const squashing functionality
--
\set EXECUTE_RUN_PREPARE on
CREATE EXTENSION pg_stat_statements;

--
Expand Down
1 change: 1 addition & 0 deletions contrib/pg_stat_statements/sql/ivy_utility.sql
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
--
-- Utility commands
--
\set EXECUTE_RUN_PREPARE on

-- These tests require track_utility to be enabled.
SET pg_stat_statements.track_utility = TRUE;
Expand Down
1 change: 1 addition & 0 deletions contrib/pg_stat_statements/sql/planning.sql
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
--
-- Information related to planning
--
\set EXECUTE_RUN_PREPARE on

-- These tests require track_planning to be enabled.
SET pg_stat_statements.track_planning = TRUE;
Expand Down
1 change: 1 addition & 0 deletions contrib/pg_stat_statements/sql/select.sql
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
--
-- SELECT statements
--
\set EXECUTE_RUN_PREPARE on

CREATE EXTENSION pg_stat_statements;
SET pg_stat_statements.track_utility = FALSE;
Expand Down
1 change: 1 addition & 0 deletions src/backend/commands/functioncmds.c
Original file line number Diff line number Diff line change
Expand Up @@ -2865,6 +2865,7 @@ ExecuteDoStmt(ParseState *pstate, DoStmt *stmt, bool atomic,
codeblock->langOid = languageStruct->oid;
codeblock->langIsTrusted = languageStruct->lanpltrusted;
codeblock->atomic = atomic;
codeblock->do_from_call = stmt->do_from_call;

if (languageStruct->lanpltrusted)
{
Expand Down
3 changes: 2 additions & 1 deletion src/backend/nodes/params.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,11 @@ makeParamList(int numParams)
retval->numParams = numParams;
retval->outparamSetup = NULL;

/* set all params mode to be IN */
/* Initialize all parameters to IN mode with typmod -1 */
for (i = 0; i < numParams; i++)
{
retval->params[i].pmode = PROARGMODE_IN;
retval->params[i].ptypmod = -1;
}

retval->outctext = NULL;
Expand Down
52 changes: 50 additions & 2 deletions src/backend/oracle_parser/ora_gram.y
Original file line number Diff line number Diff line change
Expand Up @@ -652,10 +652,12 @@ static void determineLanguage(List *options);
%type <list> hash_partbound
%type <defelt> hash_partbound_elem

%type <node> param_mode
%type <node> param_mode_item
%type <list> param_mode_list
%type <list> params_length_list
%type <str> opt_param_name
%type <node> param_mode
%type <boolean> opt_do_from_where

%type <list> identity_clause identity_options drop_identity
%type <boolean> opt_with opt_by
Expand Down Expand Up @@ -847,6 +849,8 @@ static void determineLanguage(List *options);
BINARY_DOUBLE_NAN BINARY_DOUBLE_INFINITY
%token <keyword> NAN_P INFINITE_P

%token <keyword> PARAMSLENGTH

%type <node> CreatePackageStmt CreatePackageBodyStmt AlterPackageStmt
%type <node> package_proper_item
%type <list> package_proper package_proper_list package_names package_names_list
Expand Down Expand Up @@ -1253,6 +1257,21 @@ CallStmt: CALL func_application
n->funccall = castNode(FuncCall, $2);
$$ = (Node *) n;
}
| CALL func_application INTO ORAPARAM
{
CallStmt *n = makeNode(CallStmt);
OraParamRef *hostvar = makeNode(OraParamRef);
char *callstr = NULL;
n->funccall = castNode(FuncCall, $2);
hostvar->number = 0;
hostvar->location = @4;
hostvar->name = $4;
n->hostvariable = hostvar;
callstr = pnstrdup(pg_yyget_extra(yyscanner)->core_yy_extra.scanbuf + @2, @3 - @2);
n->callinto = psprintf("%s := %s;", $4, callstr);
pfree(callstr);
$$ = (Node *)n;
}
Comment on lines +1260 to +1274
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Guard scanbuf slicing and sanitize the constructed assignment

Building n->callinto via pnstrdup(scanbuf + @2, @3 - @2) assumes valid locations. If @2 is -1 or @3 <= @2 (comments/whitespace/lexer quirks), this can underflow or slice garbage. Also, the captured text may include trailing spaces.

  • Add bounds checks and trim the substring (e.g., skip trailing whitespace before psprintf).
  • Consider using updateRawStmtEnd-style logic (already present below) for consistency.

Example:

- callstr = pnstrdup(pg_yyget_extra(yyscanner)->core_yy_extra.scanbuf + @2, @3 - @2);
+ if (@2 >= 0 && @3 > @2) {
+   const char *base = pg_yyget_extra(yyscanner)->core_yy_extra.scanbuf;
+   int len = @3 - @2;
+   while (len > 0 && isspace((unsigned char)base[@2 + len - 1])) len--;
+   callstr = pnstrdup(base + @2, len);
+ } else {
+   ereport(ERROR,
+           (errcode(ERRCODE_SYNTAX_ERROR),
+            errmsg("cannot construct CALL INTO assignment"),
+            parser_errposition(@3)));
+ }

Also verify OraParamRef has all fields initialized (indicator, datatype, etc.) or zeroed by makeNode to avoid uninitialized reads downstream.


🏁 Script executed:

#!/bin/bash
# Find struct definitions for OraParamRef, DoStmt, CallStmt
echo "=== Searching for OraParamRef definition ==="
rg -n "struct\s+OraParamRef|typedef.*OraParamRef" --type=c --type=h

echo -e "\n=== Searching for DoStmt definition ==="
rg -n "struct\s+DoStmt|typedef.*DoStmt" --type=c --type=h

echo -e "\n=== Searching for CallStmt definition ==="
rg -n "struct\s+CallStmt|typedef.*CallStmt" --type=c --type=h

Length of output: 308


🏁 Script executed:

#!/bin/bash
# Search for downstream usage of new fields: paramslen, do_from_call, hostvariable, callinto
echo "=== Usage of DoStmt.paramslen ==="
rg -n "paramslen" --type=c --type=h

echo -e "\n=== Usage of DoStmt.do_from_call ==="
rg -n "do_from_call" --type=c --type=h

echo -e "\n=== Usage of CallStmt.hostvariable ==="
rg -n "hostvariable" --type=c --type=h

echo -e "\n=== Usage of CallStmt.callinto ==="
rg -n "callinto" --type=c --type=h

Length of output: 3991


🏁 Script executed:

#!/bin/bash
# Check grammar file for %expect directive and conflict count
echo "=== Checking ora_gram.y for %expect and conflict status ==="
rg -n "%expect" src/backend/oracle_parser/ora_gram.y

echo -e "\n=== Looking for grammar test/build output if available ==="
find . -name "*.output" -o -name "*gram.output" | head -5

Length of output: 133


🏁 Script executed:

#!/bin/bash
# Verify location validity patterns and scanbuf usage elsewhere
echo "=== Existing scanbuf slicing patterns in ora_gram.y ==="
rg -n "scanbuf.*@" src/backend/oracle_parser/ora_gram.y -A 2 -B 2

echo -e "\n=== Looking for location validation patterns ==="
rg -n "location.*>=.*0|@.*>=.*0|-1.*location" src/backend/oracle_parser/ --type=c --type=h

Length of output: 828


🏁 Script executed:

#!/bin/bash
# Examine the actual ora_gram.y file around the target lines
echo "=== Content around lines 1260-1274 ==="
sed -n '1250,1280p' src/backend/oracle_parser/ora_gram.y

echo -e "\n=== Looking for OraParamRef initialization patterns ==="
rg -n "OraParamRef.*makeNode|makeNode.*OraParamRef" src/backend/oracle_parser/ --type=c --type=h -A 3

Length of output: 986


🏁 Script executed:

#!/bin/bash
# Examine struct definitions to verify field completeness
echo "=== OraParamRef struct definition ==="
sed -n '332,360p' src/include/nodes/parsenodes.h

echo -e "\n=== DoStmt struct definition ==="
sed -n '3609,3640p' src/include/nodes/parsenodes.h

echo -e "\n=== CallStmt struct definition ==="
sed -n '3642,3660p' src/include/nodes/parsenodes.h

Length of output: 2917


🏁 Script executed:

#!/bin/bash
# Check how makeNode is defined and whether it zeroes memory
echo "=== makeNode macro definition ==="
rg -n "define.*makeNode|#define.*makeNode" --type=c --type=h -A 5

echo -e "\n=== palloc0 usage (zero allocation) ==="
rg -n "palloc0.*Node|makeNode.*palloc" --type=c --type=h | head -20

Length of output: 1619


🏁 Script executed:

#!/bin/bash
# Compare other scanbuf slicing for consistency
echo "=== Context around line 12521 (stmt_literal pattern 1) ==="
sed -n '12515,12530p' src/backend/oracle_parser/ora_gram.y

echo -e "\n=== Context around line 12545 (stmt_literal pattern 2) ==="
sed -n '12540,12555p' src/backend/oracle_parser/ora_gram.y

Length of output: 1309


🏁 Script executed:

#!/bin/bash
# Search for any bounds validation on parser locations
echo "=== Any @N < 0 or location < 0 checks in ora_gram.y ==="
rg -n "@.*<.*0|location.*<.*0" src/backend/oracle_parser/ora_gram.y

echo -e "\n=== Any error handling on location/-1 in backend ==="
rg -n "location.*==.*-1|yylloc.*invalid|-1.*location" src/backend/ --type=c --type=h -C 2 | head -40

Length of output: 853


🏁 Script executed:

#!/bin/bash
# Verify param_mode and params_length_list handling
echo "=== param_mode rule in ora_gram.y ==="
rg -n "param_mode\s*:" src/backend/oracle_parser/ora_gram.y -A 10 | head -30

echo -e "\n=== params_length_list rule in ora_gram.y ==="
rg -n "params_length_list\s*:" src/backend/oracle_parser/ora_gram.y -A 10 | head -30

Length of output: 773


Fix scanbuf slicing bounds checking; verify grammar conflicts remain at 0; OraParamRef field initialization is complete but fragile

Bounds on @2 and @3 are not validated before slicing. Parser locations can be -1 (indicating unknown position), which would cause pnstrdup(base + (-1), len) to underflow. The same unguarded pattern appears at lines 12521 and 12545 for stmt_literal. Add validation:

- callstr = pnstrdup(pg_yyget_extra(yyscanner)->core_yy_extra.scanbuf + @2, @3 - @2);
+ if (@2 >= 0 && @3 > @2) {
+   const char *base = pg_yyget_extra(yyscanner)->core_yy_extra.scanbuf;
+   int len = @3 - @2;
+   while (len > 0 && isspace((unsigned char)base[@2 + len - 1])) len--;
+   callstr = pnstrdup(base + @2, len);
+ } else {
+   ereport(ERROR,
+           (errcode(ERRCODE_SYNTAX_ERROR),
+            errmsg("cannot construct CALL INTO assignment"),
+            parser_errposition(@3)));
+ }

Apply the same fix to lines 12521 and 12545. OraParamRef initialization (lines 1263–1268) is complete for all struct fields but the pattern is fragile; consider initializing all fields explicitly in future. Verify %expect 0 still holds after grammar changes via build output.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
| CALL func_application INTO ORAPARAM
{
CallStmt *n = makeNode(CallStmt);
OraParamRef *hostvar = makeNode(OraParamRef);
char *callstr = NULL;
n->funccall = castNode(FuncCall, $2);
hostvar->number = 0;
hostvar->location = @4;
hostvar->name = $4;
n->hostvariable = hostvar;
callstr = pnstrdup(pg_yyget_extra(yyscanner)->core_yy_extra.scanbuf + @2, @3 - @2);
n->callinto = psprintf("%s := %s;", $4, callstr);
pfree(callstr);
$$ = (Node *)n;
}
| CALL func_application INTO ORAPARAM
{
CallStmt *n = makeNode(CallStmt);
OraParamRef *hostvar = makeNode(OraParamRef);
char *callstr = NULL;
n->funccall = castNode(FuncCall, $2);
hostvar->number = 0;
hostvar->location = @4;
hostvar->name = $4;
n->hostvariable = hostvar;
if (@2 >= 0 && @3 > @2) {
const char *base = pg_yyget_extra(yyscanner)->core_yy_extra.scanbuf;
int len = @3 - @2;
while (len > 0 && isspace((unsigned char)base[@2 + len - 1])) len--;
callstr = pnstrdup(base + @2, len);
} else {
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("cannot construct CALL INTO assignment"),
parser_errposition(@3)));
}
n->callinto = psprintf("%s := %s;", $4, callstr);
pfree(callstr);
$$ = (Node *)n;
}
🤖 Prompt for AI Agents
In src/backend/oracle_parser/ora_gram.y around lines 1260 to 1274, the code uses
@2 and @3 to slice the scanner buffer without validating their values which can
be -1 and cause pointer underflow; change the logic to check that @2 and @3 are
non-negative and that @3 > @2 before computing the slice (fall back to an empty
string or a safe default when positions are invalid), and free/assign
accordingly; apply the identical bounds checks and safe-fallback behavior to the
same pnstrdup usages at lines ~12521 and ~12545 (stmt_literal locations);
additionally keep the OraParamRef initialization as-is now but consider
switching to explicit zero-initialization of all fields in future; after making
these edits rebuild and confirm the parser reports “%expect 0” (no conflicts).

| EXEC exec_func_application
{
CallStmt *n = makeNode(CallStmt);
Expand Down Expand Up @@ -9416,7 +9435,7 @@ func_arg_with_default:
$$ = $1;
$$->defexpr = $3;
}
| func_arg '=' a_expr
| func_arg plassign_equals a_expr
{
$$ = $1;
$$->defexpr = $3;
Expand Down Expand Up @@ -10243,6 +10262,18 @@ DoStmt: DO dostmt_opt_list
DoStmt *n = makeNode(DoStmt);
n->args = $2;
n->paramsmode = $4;
n->paramslen = NIL;
determineLanguage(n->args);
$$ = (Node *)n;
}

| DO dostmt_opt_list USING param_mode_list PARAMSLENGTH params_length_list opt_do_from_where
{
DoStmt *n = makeNode(DoStmt);
n->args = $2;
n->paramsmode = $4;
n->paramslen = $6;
n->do_from_call = $7;
determineLanguage(n->args);
$$ = (Node *)n;
}
Expand Down Expand Up @@ -10310,6 +10341,21 @@ param_mode:
| IN_P OUT_P { $$ = (Node *) makeString("inout"); }
;

params_length_list:
SignedIconst
{
$$ = list_make1(makeInteger($1));
}
| params_length_list ',' SignedIconst
{
$$ = lappend($1, makeInteger($3));
}
;

opt_do_from_where:
GENERATED FROM CALL { $$ = true; }
| /*EMPTY*/ { $$ = false; }
;

/*****************************************************************************
*
Expand Down Expand Up @@ -20285,6 +20331,7 @@ unreserved_keyword:
| PARALLEL
| PARALLEL_ENABLE
| PARAMETER
| PARAMSLENGTH
| PARSER
| PARTIAL
| PARTITION
Expand Down Expand Up @@ -20991,6 +21038,7 @@ bare_label_keyword:
| PARALLEL
| PARALLEL_ENABLE
| PARAMETER
| PARAMSLENGTH
| PARSER
| PARTIAL
| PARTITION
Expand Down
27 changes: 20 additions & 7 deletions src/backend/parser/analyze.c
Original file line number Diff line number Diff line change
Expand Up @@ -3015,13 +3015,26 @@ transformPLAssignStmt(ParseState *pstate, PLAssignStmt *stmt)
*/
Node *orig_expr = (Node *) tle->expr;

tle->expr = (Expr *)
coerce_to_target_type(pstate,
orig_expr, type_id,
targettype, targettypmod,
COERCION_PLPGSQL,
COERCE_IMPLICIT_CAST,
-1);
if (pstate->do_from_call &&
(((type_id == ORACHARCHAROID || type_id == ORACHARBYTEOID) &&
(targettype == ORACHARCHAROID || targettype == ORACHARBYTEOID)) ||
((targettype == ORAVARCHARCHAROID || targettype == ORAVARCHARBYTEOID))))
tle->expr = (Expr *)
coerce_to_target_type(pstate,
orig_expr, type_id,
targettype, targettypmod,
COERCION_EXPLICIT,
COERCE_IMPLICIT_CAST,
-1);
else
/* End - ReqID:SRS-SQL-CALL */
tle->expr = (Expr *)
coerce_to_target_type(pstate,
orig_expr, type_id,
targettype, targettypmod,
COERCION_PLPGSQL,
COERCE_IMPLICIT_CAST,
-1);
/* With COERCION_PLPGSQL, this error is probably unreachable */
if (tle->expr == NULL)
ereport(ERROR,
Expand Down
40 changes: 38 additions & 2 deletions src/backend/parser/parse_param.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ static bool IsParseDynDoStmt = true;
static bool HasPgParam = false;
static bool DoStmtCheckVar = false;
static bool IsBindByName = false;
static bool IsDynCallStmt = false;

/*
* store the OraParam name and position
Expand Down Expand Up @@ -575,6 +576,7 @@ push_oraparam_stack(void)
IsParseDynDoStmt = true;
HasPgParam = false;
DoStmtCheckVar = false;
IsDynCallStmt = false;
new->level = 1;
}
else
Expand Down Expand Up @@ -657,8 +659,14 @@ calculate_oraparamnumber(const char* name)
for (i = 0; i < CurrentOraParamNode->param_count; ++i)
{
if (strcmp(CurrentOraParamNode->params[i].name, name) == 0)
{
return CurrentOraParamNode->params[i].number;
{
/* ORA-06578: output parameter cannot be a duplicate bind */
if (IsDynCallStmt)
ereport(ERROR,
(errcode(ERRCODE_AMBIGUOUS_PARAMETER),
errmsg("output parameter cannot be a duplicate bind")));
else
return CurrentOraParamNode->params[i].number;
}
}
}
Expand Down Expand Up @@ -689,6 +697,15 @@ calculate_oraparamnumbers(List *parsetree_list)
{
Node *parsetree = (Node *)lfirst(parsetree_item);

if (nodeTag(parsetree) == T_RawStmt &&
nodeTag(((RawStmt *)parsetree)->stmt) == T_CallStmt &&
CurrentOraParamNode &&
CurrentOraParamNode->param_count == 0)
setdynamic_callparser(true);
else
/* In any case, it should't affect other statements in the list */
setdynamic_callparser(false);

Comment on lines +700 to +708
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Avoid global parser state for CallStmt detection; scope per-walk.

IsDynCallStmt is toggled globally per top-level node. This can leak across nested parses or subsequent items. Prefer computing a local “isCallCtx” based on the node being walked and pass it via walker state, or push it on the existing OraParam stack.

Minimal fix: limit the scope by setting/restoring the previous value within this loop.

-        if (nodeTag(parsetree) == T_RawStmt &&
+        bool prev = IsDynCallStmt;
+        if (nodeTag(parsetree) == T_RawStmt &&
             nodeTag(((RawStmt *)parsetree)->stmt) == T_CallStmt &&
             CurrentOraParamNode &&
             CurrentOraParamNode->param_count == 0)
             setdynamic_callparser(true);
         else
             /* In any case, it should't affect other statements in the list */
             setdynamic_callparser(false);
+        (void)0; /* walk */
         if (calculate_oraparamnumbers_walker(parsetree, NULL) == true)
             return true;
+        /* restore */
+        setdynamic_callparser(prev);

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/backend/parser/parse_param.c around lines 700 to 708, the code toggles
the global IsDynCallStmt via setdynamic_callparser based solely on the current
top-level node, which can leak state across nested walks or subsequent list
items; modify it to save the current IsDynCallStmt, set it to the new value for
the duration of processing this node, then restore the saved value immediately
after processing (or use the existing OraParam stack/walker state to carry an
isCallCtx flag) so the dynamic call parser flag is confined to this node's scope
and cannot affect other nodes.

if (calculate_oraparamnumbers_walker(parsetree, NULL) == true)
return true;
}
Expand Down Expand Up @@ -2491,6 +2508,16 @@ raw_calculate_oraparamnumbers_walker(Node *node,
return true;
}
break;
case T_CallStmt:
{
CallStmt *callstmt = (CallStmt *)node;

if (walker(callstmt->funccall, context))
return true;
if (walker(callstmt->hostvariable, context))
return true;
}
break;

default:
break;
Expand Down Expand Up @@ -2584,6 +2611,15 @@ get_bindByName(void)
return IsBindByName;
}

/*
* set dynamic CallStmt parser status
*/
void
setdynamic_callparser(bool value)
{
IsDynCallStmt = value;
}

int
calculate_oraparamname_position(Node *parsetree, char ***paramnames)
{
Expand Down
Loading