diff --git a/contrib/babelfishpg_tsql/src/hooks.c b/contrib/babelfishpg_tsql/src/hooks.c index dfbed9aae77..40e4b6a2e65 100644 --- a/contrib/babelfishpg_tsql/src/hooks.c +++ b/contrib/babelfishpg_tsql/src/hooks.c @@ -713,6 +713,60 @@ plsql_TriggerRecursiveCheck(ResultRelInfo *resultRelInfo) return false; } +/** + * Hook function to skip rewriting VIEW with base table if the VIEW has an instead of trigger + * Checks if view have an INSTEAD OF trigger at statement level + * If it does, we don't want to treat it as auto-updatable. + * Reference - src/backend/rewrite/rewriteHandler.c view_has_instead_trigger +*/ +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) + { + case CMD_INSERT: + if(trigDesc && trigDesc->trig_insert_instead_statement) + return true; + break; + case CMD_UPDATE: + if (trigDesc && trigDesc->trig_update_instead_statement) + return true; + break; + case CMD_DELETE: + if (trigDesc && trigDesc->trig_delete_instead_statement) + return true; + break; + default: + elog(ERROR, "unrecognized CmdType: %d", (int) event); + break; + } + return false; +} + /* * Wrapper function that calls the initilization function. * Calls the pre function call hook on the procname diff --git a/test/JDBC/expected/BABEL-2170-vu-verify.out b/test/JDBC/expected/BABEL-2170-vu-verify.out new file mode 100644 index 00000000000..06f834bcb6a --- /dev/null +++ b/test/JDBC/expected/BABEL-2170-vu-verify.out @@ -0,0 +1,636 @@ +USE db1_BABEL2170; +GO + +-- Instead of Insert Trigger on View +CREATE TRIGGER babel_2170_vu_employees_view_iot_insert ON babel_2170_vu_employees_view +INSTEAD OF INSERT +AS +BEGIN + SELECT 'Trigger db1_BABEL2170.dbo.babel_2170_vu_employees_view_iot_insert Invoked' +END +GO + +INSERT INTO babel_2170_vu_employees_view VALUES(3, 'adam', '1st Street', '3000'); +GO +~~START~~ +varchar +Trigger db1_BABEL2170.dbo.babel_2170_vu_employees_view_iot_insert Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +SELECT COUNT(EmployeeID) FROM babel_2170_vu_employees; +GO +~~START~~ +int +2 +~~END~~ + + +SELECT COUNT(EmployeeID) FROM babel_2170_vu_employees_view; +GO +~~START~~ +int +2 +~~END~~ + + +-- Instead of Update Trigger on View +CREATE TRIGGER babel_2170_vu_employees_view_iot_update ON babel_2170_vu_employees_view +INSTEAD OF UPDATE +AS +BEGIN + SELECT 'Trigger db1_BABEL2170.dbo.babel_2170_vu_employees_view_iot_update Invoked' +END +GO + +UPDATE babel_2170_vu_employees_view SET MonthSalary = MonthSalary +1 WHERE EmployeeID = 2; +GO +~~START~~ +varchar +Trigger db1_BABEL2170.dbo.babel_2170_vu_employees_view_iot_update Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +SELECT EmployeeID,EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees WHERE EmployeeID = 2; +GO +~~START~~ +int#!#varchar#!#varchar#!#numeric +2#!#angel#!#1st Street#!#2000.00 +~~END~~ + + +BEGIN TRANSACTION + UPDATE babel_2170_vu_employees_view SET MonthSalary = MonthSalary +1 WHERE EmployeeID IN (1, 2); +COMMIT TRANSACTION; +GO +~~START~~ +varchar +Trigger db1_BABEL2170.dbo.babel_2170_vu_employees_view_iot_update Invoked +~~END~~ + +~~ROW COUNT: 2~~ + + +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees WHERE EmployeeID IN (1, 2) ORDER BY EmployeeID; +GO +~~START~~ +int#!#varchar#!#varchar#!#numeric +1#!#amber#!#1st Street#!#1000.00 +2#!#angel#!#1st Street#!#2000.00 +~~END~~ + + +-- Instead of Delete Trigger on View +CREATE TRIGGER babel_2170_vu_employees_view_iot_delete ON babel_2170_vu_employees_view +INSTEAD OF DELETE +AS +BEGIN + SELECT 'Trigger db1_BABEL2170.dbo.babel_2170_vu_employees_view_iot_delete Invoked' +END +GO + +BEGIN TRANSACTION + DELETE FROM babel_2170_vu_employees_view WHERE EmployeeID IN (1, 2); +COMMIT TRANSACTION; +GO +~~START~~ +varchar +Trigger db1_BABEL2170.dbo.babel_2170_vu_employees_view_iot_delete Invoked +~~END~~ + +~~ROW COUNT: 2~~ + + +SELECT COUNT(EmployeeID) FROM babel_2170_vu_employees_view; +GO +~~START~~ +int +2 +~~END~~ + + +SELECT COUNT(EmployeeID) FROM babel_2170_vu_employees; +GO +~~START~~ +int +2 +~~END~~ + + +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees_view ORDER BY EmployeeID; +GO +~~START~~ +int#!#varchar#!#varchar#!#numeric +1#!#amber#!#1st Street#!#1000.00 +2#!#angel#!#1st Street#!#2000.00 +~~END~~ + + +--- Tests multiple insert queries and check if inserted table can be accessed and trigger is working fine. +CREATE TRIGGER babel_2170_vu_employees_view_iot_bulkinsert ON babel_2170_vu_employees_view_bulkinsert +INSTEAD OF INSERT +AS + SELECT * FROM INSERTED; +GO + +BEGIN TRANSACTION +DECLARE @i int = 1 + WHILE @i <= 3 + BEGIN + INSERT INTO babel_2170_vu_employees_view_bulkinsert VALUES(@i, 'bob', '1st Street', '1000'); + SET @i = @i + 1 + END +COMMIT TRANSACTION +GO +~~START~~ +int#!#varchar#!#varchar#!#numeric +1#!#bob#!#1st Street#!#1000.00 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#varchar#!#varchar#!#numeric +2#!#bob#!#1st Street#!#1000.00 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#varchar#!#varchar#!#numeric +3#!#bob#!#1st Street#!#1000.00 +~~END~~ + +~~ROW COUNT: 1~~ + + +-- Same trigger name on different View created on Same table in same schema +CREATE TRIGGER babel_2170_vu_employees_view_iot_update ON babel_2170_vu_employees_view_2 +INSTEAD OF INSERT +AS +BEGIN + SELECT 'Trigger db1_BABEL2170.dbo.babel_2170_vu_employees_view2_iot_update Invoked' +END +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: trigger "babel_2170_vu_employees_view_iot_update" already exists in the database)~~ + + +-- Same trigger name on a Table in same schema +CREATE TRIGGER babel_2170_vu_employees_view_iot_update ON babel_2170_vu_employees +INSTEAD OF INSERT +AS +BEGIN + SELECT 'Trigger db1_BABEL2170.dbo.babel_2170_vu_employees__table_iot_update Invoked' +END +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: trigger "babel_2170_vu_employees_view_iot_update" already exists in the database)~~ + + + +-- Test Instead of Update trigger in same db but cross schema +-- Cleanup default dbo schema IO Update trigger +DROP TRIGGER IF EXISTS [dbo].[babel_2170_vu_employees_view_iot_update]; +GO + +CREATE TRIGGER [schema_2170].[babel_2170_vu_employees_view_iot_update] ON [schema_2170].[babel_2170_vu_employees_view] +INSTEAD OF UPDATE +AS + SELECT 'Trigger db1_BABEL2170.schema_2170.babel_2170_vu_employees_view_iot_update Invoked' +GO + +CREATE TRIGGER [babel_2170_vu_employees_view_iot_update] ON [babel_2170_vu_employees_view] +INSTEAD OF UPDATE +AS + SELECT 'Trigger db1_BABEL2170.dbo.babel_2170_vu_employees_view_iot_update Invoked' +GO + +UPDATE [schema_2170].[babel_2170_vu_employees_view] SET MonthSalary = MonthSalary +1 WHERE EmployeeID = 2; +GO +~~START~~ +varchar +Trigger db1_BABEL2170.schema_2170.babel_2170_vu_employees_view_iot_update Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM [schema_2170].[babel_2170_vu_employees_view] ORDER BY EmployeeID; +GO +~~START~~ +int#!#varchar#!#varchar#!#numeric +1#!#amber#!#1st Street#!#1000.00 +2#!#angel#!#1st Street#!#2000.00 +~~END~~ + + +UPDATE [dbo].[babel_2170_vu_employees_view] SET MonthSalary = MonthSalary +1 WHERE EmployeeID = 2; +GO +~~START~~ +varchar +Trigger db1_BABEL2170.dbo.babel_2170_vu_employees_view_iot_update Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM [dbo].[babel_2170_vu_employees_view] ORDER BY EmployeeID; +GO +~~START~~ +int#!#varchar#!#varchar#!#numeric +1#!#amber#!#1st Street#!#1000.00 +2#!#angel#!#1st Street#!#2000.00 +~~END~~ + + +-- drop dbo schema trigger and test that schema_2170.update trigger is not dropped +DROP TRIGGER IF EXISTS [dbo].[babel_2170_vu_employees_view_iot_update]; +GO + +UPDATE [schema_2170].[babel_2170_vu_employees_view] SET MonthSalary = MonthSalary +1 WHERE EmployeeID = 2; +GO +~~START~~ +varchar +Trigger db1_BABEL2170.schema_2170.babel_2170_vu_employees_view_iot_update Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +-- schema_2170 object cleanup +DROP TRIGGER IF EXISTS [schema_2170].babel_2170_vu_employees_view_iot_update; +GO + +DROP VIEW IF EXISTS [schema_2170].babel_2170_vu_employees_view; +GO + +DROP TABLE IF EXISTS [schema_2170].babel_2170_vu_employees; +GO + +DROP SCHEMA IF EXISTS schema_2170; +GO + +-- Test Transaction Commit and Rollback inside Instead of triggers +CREATE TRIGGER babel_2170_vu_employees_view_iot_txn_update ON babel_2170_vu_employees_view_txn +INSTEAD OF UPDATE +AS + BEGIN + BEGIN TRAN; + INSERT INTO babel_2170_vu_employees_view_txn VALUES(3, 'adam', '1st Street', '3000'); + COMMIT tran; + END +GO + +UPDATE babel_2170_vu_employees_view_txn 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_txn ORDER BY EmployeeID; +GO +~~START~~ +int#!#varchar#!#varchar#!#numeric +1#!#amber#!#1st Street#!#1000.00 +2#!#angel#!#1st Street#!#2000.00 +3#!#adam#!#1st Street#!#3000.00 +~~END~~ + + +DROP TRIGGER IF EXISTS babel_2170_vu_employees_view_iot_txn_update; +GO + +CREATE TRIGGER babel_2170_vu_employees_view_iot_txn_update ON babel_2170_vu_employees_view_txn +INSTEAD OF UPDATE +AS + BEGIN + BEGIN TRAN; + INSERT INTO babel_2170_vu_employees_view_txn VALUES(3, 'adam', '1st Street', '3000'); + ROLLBACK tran; + END +GO + +UPDATE babel_2170_vu_employees_view_txn SET MonthSalary = MonthSalary +1 WHERE EmployeeID = 2; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 3609)~~ + +~~ERROR (Message: The transaction ended in the trigger. The batch has been aborted.)~~ + + +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees_view_txn ORDER BY EmployeeID; +GO +~~START~~ +int#!#varchar#!#varchar#!#numeric +1#!#amber#!#1st Street#!#1000.00 +2#!#angel#!#1st Street#!#2000.00 +3#!#adam#!#1st Street#!#3000.00 +~~END~~ + + +DROP TRIGGER IF EXISTS babel_2170_vu_employees_view_iot_txn_update; +GO + +CREATE TRIGGER babel_2170_vu_employees_view_iot_txn_insert ON babel_2170_vu_employees_view_txn INSTEAD OF INSERT AS +BEGIN TRAN; +UPDATE babel_2170_vu_employees_view_txn SET MonthSalary = MonthSalary +1 WHERE EmployeeID = 2; +COMMIT; +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees_view_txn ORDER BY EmployeeID; +SELECT * FROM inserted; +GO + +BEGIN TRAN; +GO +INSERT INTO babel_2170_vu_employees_view_txn VALUES(4, 'ana', '1st Street', '4000'); +GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#varchar#!#varchar#!#numeric +1#!#amber#!#1st Street#!#1000.00 +2#!#angel#!#1st Street#!#2001.00 +3#!#adam#!#1st Street#!#3000.00 +~~END~~ + +~~START~~ +int#!#varchar#!#varchar#!#numeric +4#!#ana#!#1st Street#!#4000.00 +~~END~~ + +~~ROW COUNT: 1~~ + +COMMIT; +GO + +BEGIN TRAN +GO +INSERT INTO babel_2170_vu_employees_view_txn VALUES(4, 'ana', '1st Street', '4000'); +GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#varchar#!#varchar#!#numeric +1#!#amber#!#1st Street#!#1000.00 +2#!#angel#!#1st Street#!#2002.00 +3#!#adam#!#1st Street#!#3000.00 +~~END~~ + +~~START~~ +int#!#varchar#!#varchar#!#numeric +4#!#ana#!#1st Street#!#4000.00 +~~END~~ + +~~ROW COUNT: 1~~ + +IF (@@trancount > 0) ROLLBACK; +GO + +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees_view_txn ORDER BY EmployeeID; +GO +~~START~~ +int#!#varchar#!#varchar#!#numeric +1#!#amber#!#1st Street#!#1000.00 +2#!#angel#!#1st Street#!#2001.00 +3#!#adam#!#1st Street#!#3000.00 +~~END~~ + + +DROP TRIGGER IF EXISTS babel_2170_vu_employees_view_iot_txn_insert; +GO + +CREATE TRIGGER babel_2170_vu_employees_view_iot_txn_update ON babel_2170_vu_employees_view_txn INSTEAD OF UPDATE AS +SAVE TRAN sp1; +SAVE TRAN sp2; +DELETE FROM babel_2170_vu_employees_view_txn where EmployeeID =2; +ROLLBACK TRAN sp1; +GO + +BEGIN TRAN +GO +SELECT @@trancount; +UPDATE babel_2170_vu_employees_view_txn SET MonthSalary = MonthSalary +1 WHERE EmployeeID = 2; +GO +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +IF (@@trancount > 0) ROLLBACK; +GO + +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees_view_txn ORDER BY EmployeeID; +GO +~~START~~ +int#!#varchar#!#varchar#!#numeric +1#!#amber#!#1st Street#!#1000.00 +2#!#angel#!#1st Street#!#2001.00 +3#!#adam#!#1st Street#!#3000.00 +~~END~~ + + +DROP TRIGGER IF EXISTS babel_2170_vu_employees_view_iot_txn_update; +GO + +CREATE TRIGGER babel_2170_vu_employees_view_iot_txn_delete ON babel_2170_vu_employees_view_txn INSTEAD OF DELETE AS +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees_view_txn ORDER BY EmployeeID; +INSERT INTO babel_2170_vu_employees_view_txn VALUES(5, 'ash', '1st Street', '5000'); +SELECT * FROM deleted; +GO + +DELETE FROM babel_2170_vu_employees_view_txn where EmployeeID =1; +GO +~~START~~ +int#!#varchar#!#varchar#!#numeric +1#!#amber#!#1st Street#!#1000.00 +2#!#angel#!#1st Street#!#2001.00 +3#!#adam#!#1st Street#!#3000.00 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#varchar#!#varchar#!#numeric +1#!#amber#!#1st Street#!#1000.00 +~~END~~ + +~~ROW COUNT: 1~~ + + +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees_view_txn ORDER BY EmployeeID; +GO +~~START~~ +int#!#varchar#!#varchar#!#numeric +1#!#amber#!#1st Street#!#1000.00 +2#!#angel#!#1st Street#!#2001.00 +3#!#adam#!#1st Street#!#3000.00 +5#!#ash#!#1st Street#!#5000.00 +~~END~~ + + +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 +~~START~~ +text +jdbc_user +~~END~~ + + +SELECT set_config('babelfishpg_tsql.migration_mode', 'multi-db', false); +GO +~~START~~ +text +multi-db +~~END~~ + + +CREATE DATABASE db2_BABEL2170; +GO + +USE db2_BABEL2170; +GO + +CREATE TABLE babel_2170_vu_employees +( + EmployeeID int NOT NULL, + EmployeeName VARCHAR(50), + EmployeeAddress VARCHAR(50), + MonthSalary NUMERIC(10, 2) +) +GO + +INSERT INTO babel_2170_vu_employees VALUES(1, 'amber', '1st Street', '1000'); +INSERT INTO babel_2170_vu_employees VALUES(2, 'angel', '1st Street', '2000'); +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +CREATE VIEW babel_2170_vu_employees_view AS +SELECT EmployeeID, + EmployeeName, + EmployeeAddress, + MonthSalary +FROM babel_2170_vu_employees +WHERE EmployeeName LIKE 'a%'; +GO + +-- create same name Instead of Insert trigger in second db to test Cross db behavior +CREATE TRIGGER babel_2170_vu_employees_view_iot_insert ON babel_2170_vu_employees_view +INSTEAD OF INSERT +AS +BEGIN + SELECT 'Trigger db2_BABEL2170.dbo.babel_2170_vu_employees_view_iot_insert Invoked' +END +GO + +-- should fire IOT trigger of second db +INSERT INTO babel_2170_vu_employees_view VALUES(3, 'adam', '1st Street db2_BABEL2170', '3000'); +GO +~~START~~ +varchar +Trigger db2_BABEL2170.dbo.babel_2170_vu_employees_view_iot_insert Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees_view ORDER BY EmployeeID; +GO +~~START~~ +int#!#varchar#!#varchar#!#numeric +1#!#amber#!#1st Street#!#1000.00 +2#!#angel#!#1st Street#!#2000.00 +~~END~~ + + +-- clean all objects in second database +DROP TRIGGER IF EXISTS babel_2170_vu_employees_view_iot_insert; +GO + +DROP VIEW IF EXISTS babel_2170_vu_employees_view; +GO + +DROP TABLE IF EXISTS babel_2170_vu_employees; +GO + +USE MASTER; +GO + +DROP DATABASE IF EXISTS db2_BABEL2170; +GO diff --git a/test/JDBC/input/triggers/BABEL-2170-vu-verify.sql b/test/JDBC/input/triggers/BABEL-2170-vu-verify.sql new file mode 100644 index 00000000000..18b63fa2364 --- /dev/null +++ b/test/JDBC/input/triggers/BABEL-2170-vu-verify.sql @@ -0,0 +1,361 @@ +USE db1_BABEL2170; +GO + +-- Instead of Insert Trigger on View +CREATE TRIGGER babel_2170_vu_employees_view_iot_insert ON babel_2170_vu_employees_view +INSTEAD OF INSERT +AS +BEGIN + SELECT 'Trigger db1_BABEL2170.dbo.babel_2170_vu_employees_view_iot_insert Invoked' +END +GO + +INSERT INTO babel_2170_vu_employees_view VALUES(3, 'adam', '1st Street', '3000'); +GO + +SELECT COUNT(EmployeeID) FROM babel_2170_vu_employees; +GO + +SELECT COUNT(EmployeeID) FROM babel_2170_vu_employees_view; +GO + +-- Instead of Update Trigger on View +CREATE TRIGGER babel_2170_vu_employees_view_iot_update ON babel_2170_vu_employees_view +INSTEAD OF UPDATE +AS +BEGIN + SELECT 'Trigger db1_BABEL2170.dbo.babel_2170_vu_employees_view_iot_update Invoked' +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 WHERE EmployeeID = 2; +GO + +BEGIN TRANSACTION + UPDATE babel_2170_vu_employees_view SET MonthSalary = MonthSalary +1 WHERE EmployeeID IN (1, 2); +COMMIT TRANSACTION; +GO + +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees WHERE EmployeeID IN (1, 2) ORDER BY EmployeeID; +GO + +-- Instead of Delete Trigger on View +CREATE TRIGGER babel_2170_vu_employees_view_iot_delete ON babel_2170_vu_employees_view +INSTEAD OF DELETE +AS +BEGIN + SELECT 'Trigger db1_BABEL2170.dbo.babel_2170_vu_employees_view_iot_delete Invoked' +END +GO + +BEGIN TRANSACTION + DELETE FROM babel_2170_vu_employees_view WHERE EmployeeID IN (1, 2); +COMMIT TRANSACTION; +GO + +SELECT COUNT(EmployeeID) FROM babel_2170_vu_employees_view; +GO + +SELECT COUNT(EmployeeID) FROM babel_2170_vu_employees; +GO + +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees_view ORDER BY EmployeeID; +GO + +--- Tests multiple insert queries and check if inserted table can be accessed and trigger is working fine. +CREATE TRIGGER babel_2170_vu_employees_view_iot_bulkinsert ON babel_2170_vu_employees_view_bulkinsert +INSTEAD OF INSERT +AS + SELECT * FROM INSERTED; +GO + +BEGIN TRANSACTION +DECLARE @i int = 1 + WHILE @i <= 3 + BEGIN + INSERT INTO babel_2170_vu_employees_view_bulkinsert VALUES(@i, 'bob', '1st Street', '1000'); + SET @i = @i + 1 + END +COMMIT TRANSACTION +GO + +-- Same trigger name on different View created on Same table in same schema +CREATE TRIGGER babel_2170_vu_employees_view_iot_update ON babel_2170_vu_employees_view_2 +INSTEAD OF INSERT +AS +BEGIN + SELECT 'Trigger db1_BABEL2170.dbo.babel_2170_vu_employees_view2_iot_update Invoked' +END +GO + +-- Same trigger name on a Table in same schema +CREATE TRIGGER babel_2170_vu_employees_view_iot_update ON babel_2170_vu_employees +INSTEAD OF INSERT +AS +BEGIN + SELECT 'Trigger db1_BABEL2170.dbo.babel_2170_vu_employees__table_iot_update Invoked' +END +GO + +-- Test Instead of Update trigger in same db but cross schema + +-- Cleanup default dbo schema IO Update trigger +DROP TRIGGER IF EXISTS [dbo].[babel_2170_vu_employees_view_iot_update]; +GO + +CREATE TRIGGER [schema_2170].[babel_2170_vu_employees_view_iot_update] ON [schema_2170].[babel_2170_vu_employees_view] +INSTEAD OF UPDATE +AS + SELECT 'Trigger db1_BABEL2170.schema_2170.babel_2170_vu_employees_view_iot_update Invoked' +GO + +CREATE TRIGGER [babel_2170_vu_employees_view_iot_update] ON [babel_2170_vu_employees_view] +INSTEAD OF UPDATE +AS + SELECT 'Trigger db1_BABEL2170.dbo.babel_2170_vu_employees_view_iot_update Invoked' +GO + +UPDATE [schema_2170].[babel_2170_vu_employees_view] SET MonthSalary = MonthSalary +1 WHERE EmployeeID = 2; +GO + +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM [schema_2170].[babel_2170_vu_employees_view] ORDER BY EmployeeID; +GO + +UPDATE [dbo].[babel_2170_vu_employees_view] SET MonthSalary = MonthSalary +1 WHERE EmployeeID = 2; +GO + +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM [dbo].[babel_2170_vu_employees_view] ORDER BY EmployeeID; +GO + +-- drop dbo schema trigger and test that schema_2170.update trigger is not dropped +DROP TRIGGER IF EXISTS [dbo].[babel_2170_vu_employees_view_iot_update]; +GO + +UPDATE [schema_2170].[babel_2170_vu_employees_view] SET MonthSalary = MonthSalary +1 WHERE EmployeeID = 2; +GO + +-- schema_2170 object cleanup +DROP TRIGGER IF EXISTS [schema_2170].babel_2170_vu_employees_view_iot_update; +GO + +DROP VIEW IF EXISTS [schema_2170].babel_2170_vu_employees_view; +GO + +DROP TABLE IF EXISTS [schema_2170].babel_2170_vu_employees; +GO + +DROP SCHEMA IF EXISTS schema_2170; +GO + +-- Test Transaction Commit and Rollback inside Instead of triggers +CREATE TRIGGER babel_2170_vu_employees_view_iot_txn_update ON babel_2170_vu_employees_view_txn +INSTEAD OF UPDATE +AS + BEGIN + BEGIN TRAN; + INSERT INTO babel_2170_vu_employees_view_txn VALUES(3, 'adam', '1st Street', '3000'); + COMMIT tran; + END +GO + +UPDATE babel_2170_vu_employees_view_txn SET MonthSalary = MonthSalary +1 WHERE EmployeeID = 2; +GO + +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees_view_txn ORDER BY EmployeeID; +GO + +DROP TRIGGER IF EXISTS babel_2170_vu_employees_view_iot_txn_update; +GO + +CREATE TRIGGER babel_2170_vu_employees_view_iot_txn_update ON babel_2170_vu_employees_view_txn +INSTEAD OF UPDATE +AS + BEGIN + BEGIN TRAN; + INSERT INTO babel_2170_vu_employees_view_txn VALUES(3, 'adam', '1st Street', '3000'); + ROLLBACK tran; + END +GO + +UPDATE babel_2170_vu_employees_view_txn SET MonthSalary = MonthSalary +1 WHERE EmployeeID = 2; +GO + +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees_view_txn ORDER BY EmployeeID; +GO + +DROP TRIGGER IF EXISTS babel_2170_vu_employees_view_iot_txn_update; +GO + +CREATE TRIGGER babel_2170_vu_employees_view_iot_txn_insert ON babel_2170_vu_employees_view_txn INSTEAD OF INSERT AS +BEGIN TRAN; +UPDATE babel_2170_vu_employees_view_txn SET MonthSalary = MonthSalary +1 WHERE EmployeeID = 2; +COMMIT; +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees_view_txn ORDER BY EmployeeID; +SELECT * FROM inserted; +GO + +BEGIN TRAN; +GO +INSERT INTO babel_2170_vu_employees_view_txn VALUES(4, 'ana', '1st Street', '4000'); +GO +COMMIT; +GO + +BEGIN TRAN +GO +INSERT INTO babel_2170_vu_employees_view_txn VALUES(4, 'ana', '1st Street', '4000'); +GO +IF (@@trancount > 0) ROLLBACK; +GO + +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees_view_txn ORDER BY EmployeeID; +GO + +DROP TRIGGER IF EXISTS babel_2170_vu_employees_view_iot_txn_insert; +GO + +CREATE TRIGGER babel_2170_vu_employees_view_iot_txn_update ON babel_2170_vu_employees_view_txn INSTEAD OF UPDATE AS +SAVE TRAN sp1; +SAVE TRAN sp2; +DELETE FROM babel_2170_vu_employees_view_txn where EmployeeID =2; +ROLLBACK TRAN sp1; +GO + +BEGIN TRAN +GO +SELECT @@trancount; +UPDATE babel_2170_vu_employees_view_txn SET MonthSalary = MonthSalary +1 WHERE EmployeeID = 2; +GO +IF (@@trancount > 0) ROLLBACK; +GO + +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees_view_txn ORDER BY EmployeeID; +GO + +DROP TRIGGER IF EXISTS babel_2170_vu_employees_view_iot_txn_update; +GO + +CREATE TRIGGER babel_2170_vu_employees_view_iot_txn_delete ON babel_2170_vu_employees_view_txn INSTEAD OF DELETE AS +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees_view_txn ORDER BY EmployeeID; +INSERT INTO babel_2170_vu_employees_view_txn VALUES(5, 'ash', '1st Street', '5000'); +SELECT * FROM deleted; +GO + +DELETE FROM babel_2170_vu_employees_view_txn where EmployeeID =1; +GO + +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees_view_txn ORDER BY EmployeeID; +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 + +SELECT set_config('babelfishpg_tsql.migration_mode', 'multi-db', false); +GO + +CREATE DATABASE db2_BABEL2170; +GO + +USE db2_BABEL2170; +GO + +CREATE TABLE babel_2170_vu_employees +( + EmployeeID int NOT NULL, + EmployeeName VARCHAR(50), + EmployeeAddress VARCHAR(50), + MonthSalary NUMERIC(10, 2) +) +GO + +INSERT INTO babel_2170_vu_employees VALUES(1, 'amber', '1st Street', '1000'); +INSERT INTO babel_2170_vu_employees VALUES(2, 'angel', '1st Street', '2000'); +GO + +CREATE VIEW babel_2170_vu_employees_view AS +SELECT EmployeeID, + EmployeeName, + EmployeeAddress, + MonthSalary +FROM babel_2170_vu_employees +WHERE EmployeeName LIKE 'a%'; +GO + +-- create same name Instead of Insert trigger in second db to test Cross db behavior +CREATE TRIGGER babel_2170_vu_employees_view_iot_insert ON babel_2170_vu_employees_view +INSTEAD OF INSERT +AS +BEGIN + SELECT 'Trigger db2_BABEL2170.dbo.babel_2170_vu_employees_view_iot_insert Invoked' +END +GO + +-- should fire IOT trigger of second db +INSERT INTO babel_2170_vu_employees_view VALUES(3, 'adam', '1st Street db2_BABEL2170', '3000'); +GO + +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees_view ORDER BY EmployeeID; +GO + +-- clean all objects in second database +DROP TRIGGER IF EXISTS babel_2170_vu_employees_view_iot_insert; +GO + +DROP VIEW IF EXISTS babel_2170_vu_employees_view; +GO + +DROP TABLE IF EXISTS babel_2170_vu_employees; +GO + +USE MASTER; +GO + +DROP DATABASE IF EXISTS db2_BABEL2170; +GO \ No newline at end of file