From f9ab2ad80f261baf37fb6fca592ada7c33c0946b Mon Sep 17 00:00:00 2001 From: Deepakshi Mittal <78574784+deepakshi-mittal@users.noreply.github.com> Date: Wed, 22 Nov 2023 14:58:55 -0800 Subject: [PATCH] Fix Crash when Instead of View Trigger calls itself (#1970) This change will fix crashes when an Instead of Trigger on View calls itself directly and indirectly Task: BABEL-2170 Signed-off-by: Deepakshi Mittal --- contrib/babelfishpg_tsql/src/hooks.c | 22 +++++++ test/JDBC/expected/BABEL-2170-vu-verify.out | 60 ++++++++++++++++++- .../input/triggers/BABEL-2170-vu-verify.sql | 42 ++++++++++++- 3 files changed, 122 insertions(+), 2 deletions(-) diff --git a/contrib/babelfishpg_tsql/src/hooks.c b/contrib/babelfishpg_tsql/src/hooks.c index 9bc52464efe..47cf2741709 100644 --- a/contrib/babelfishpg_tsql/src/hooks.c +++ b/contrib/babelfishpg_tsql/src/hooks.c @@ -730,6 +730,28 @@ static bool pltsql_bbfViewHasInsteadofTrigger(Relation view, CmdType event) { TriggerDesc *trigDesc = view->trigdesc; + if (triggerOids) + { + int i; + for (i = 0; i < trigDesc->numtriggers; i++) + { + Trigger *trigger = &trigDesc->triggers[i]; + Oid current_tgoid = trigger->tgoid; + Oid prev_tgoid = InvalidOid; + prev_tgoid = lfirst_oid(list_tail(triggerOids)); + if (prev_tgoid == current_tgoid) + { + return false; /** Direct recursive trigger case*/ + } + else if (list_member_oid(triggerOids, current_tgoid)) + { + /** Indirect recursive trigger case*/ + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("Maximum stored procedure, function, trigger, or view nesting level exceeded (limit 32)"))); + } + } + } switch (event) { diff --git a/test/JDBC/expected/BABEL-2170-vu-verify.out b/test/JDBC/expected/BABEL-2170-vu-verify.out index 94e3ee9a167..06f834bcb6a 100644 --- a/test/JDBC/expected/BABEL-2170-vu-verify.out +++ b/test/JDBC/expected/BABEL-2170-vu-verify.out @@ -55,7 +55,7 @@ Trigger db1_BABEL2170.dbo.babel_2170_vu_employees_view_iot_update Invoked ~~ROW COUNT: 1~~ -SELECT EmployeeID,EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees WHERE EmployeeID = 2 ORDER BY EmployeeID; +SELECT EmployeeID,EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees WHERE EmployeeID = 2; GO ~~START~~ int#!#varchar#!#varchar#!#numeric @@ -483,6 +483,64 @@ int#!#varchar#!#varchar#!#numeric DROP TRIGGER IF EXISTS babel_2170_vu_employees_view_iot_txn_delete; GO +DROP TRIGGER IF EXISTS babel_2170_vu_employees_view_iot_update; +GO + +-- Transition table join test +CREATE TRIGGER babel_2170_vu_employees_view_transition ON babel_2170_vu_employees_view +INSTEAD OF UPDATE +AS +BEGIN + UPDATE babel_2170_vu_employees_view set MonthSalary = i.MonthSalary + 15 FROM inserted as i + JOIN babel_2170_vu_employees_view AS v ON v.EmployeeID = i.EmployeeID +END +GO + +UPDATE babel_2170_vu_employees_view SET MonthSalary = 5 WHERE EmployeeID = 2; +GO +~~ROW COUNT: 2~~ + +~~ROW COUNT: 1~~ + + +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees_view WHERE EmployeeID = 2; +GO +~~START~~ +int#!#varchar#!#varchar#!#numeric +2#!#angel#!#1st Street#!#2015.00 +~~END~~ + + +DROP TRIGGER IF EXISTS babel_2170_vu_employees_view_transition; +GO + +-- Recursive Trigger test Direct Recursion Trigger calling itself trigger 1 -> trigger 1 +CREATE TRIGGER babel_2170_vu_employees_view_iot_update ON babel_2170_vu_employees_view +INSTEAD OF UPDATE +AS +BEGIN + UPDATE babel_2170_vu_employees_view SET MonthSalary = MonthSalary +100 WHERE EmployeeID = 2; +END +GO + +UPDATE babel_2170_vu_employees_view SET MonthSalary = MonthSalary +1 WHERE EmployeeID = 2; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees_view WHERE EmployeeID = 2; +GO +~~START~~ +int#!#varchar#!#varchar#!#numeric +2#!#angel#!#1st Street#!#2115.00 +~~END~~ + + +DROP TRIGGER IF EXISTS babel_2170_vu_employees_view_iot_update; +GO + -- test multi-db mode SELECT set_config('role', 'jdbc_user', false); GO diff --git a/test/JDBC/input/triggers/BABEL-2170-vu-verify.sql b/test/JDBC/input/triggers/BABEL-2170-vu-verify.sql index c7802b6db5c..18b63fa2364 100644 --- a/test/JDBC/input/triggers/BABEL-2170-vu-verify.sql +++ b/test/JDBC/input/triggers/BABEL-2170-vu-verify.sql @@ -31,7 +31,7 @@ GO UPDATE babel_2170_vu_employees_view SET MonthSalary = MonthSalary +1 WHERE EmployeeID = 2; GO -SELECT EmployeeID,EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees WHERE EmployeeID = 2 ORDER BY EmployeeID; +SELECT EmployeeID,EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees WHERE EmployeeID = 2; GO BEGIN TRANSACTION @@ -253,6 +253,46 @@ GO DROP TRIGGER IF EXISTS babel_2170_vu_employees_view_iot_txn_delete; GO +DROP TRIGGER IF EXISTS babel_2170_vu_employees_view_iot_update; +GO + +-- Transition table join test +CREATE TRIGGER babel_2170_vu_employees_view_transition ON babel_2170_vu_employees_view +INSTEAD OF UPDATE +AS +BEGIN + UPDATE babel_2170_vu_employees_view set MonthSalary = i.MonthSalary + 15 FROM inserted as i + JOIN babel_2170_vu_employees_view AS v ON v.EmployeeID = i.EmployeeID +END +GO + +UPDATE babel_2170_vu_employees_view SET MonthSalary = 5 WHERE EmployeeID = 2; +GO + +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees_view WHERE EmployeeID = 2; +GO + +DROP TRIGGER IF EXISTS babel_2170_vu_employees_view_transition; +GO + +-- Recursive Trigger test Direct Recursion Trigger calling itself trigger 1 -> trigger 1 +CREATE TRIGGER babel_2170_vu_employees_view_iot_update ON babel_2170_vu_employees_view +INSTEAD OF UPDATE +AS +BEGIN + UPDATE babel_2170_vu_employees_view SET MonthSalary = MonthSalary +100 WHERE EmployeeID = 2; +END +GO + +UPDATE babel_2170_vu_employees_view SET MonthSalary = MonthSalary +1 WHERE EmployeeID = 2; +GO + +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees_view WHERE EmployeeID = 2; +GO + +DROP TRIGGER IF EXISTS babel_2170_vu_employees_view_iot_update; +GO + -- test multi-db mode SELECT set_config('role', 'jdbc_user', false); GO