Skip to content

Commit

Permalink
Support for Instead of Trigger On Views in Babelfish
Browse files Browse the repository at this point in the history
Currently Postgres does not support Instead of Trigger
On Views for DML queries.

On running such a query on VIEW, query rewriting substitutes
view with underlying base table.
Added a hook for skipping the substitution for DML
query on the VIEW.

This change will add support for Instaed of Triggers
for DML queries when using Babelfish.

Task: BABEL-2170

Signed-off-by: Deepakshi Mittal <[email protected]>
  • Loading branch information
deepakshi-mittal committed Oct 9, 2023
1 parent 818bf34 commit 34c3d17
Show file tree
Hide file tree
Showing 7 changed files with 340 additions and 0 deletions.
35 changes: 35 additions & 0 deletions contrib/babelfishpg_tsql/src/hooks.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ static void pltsql_ExecutorStart(QueryDesc *queryDesc, int eflags);
static void pltsql_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once);
static void pltsql_ExecutorFinish(QueryDesc *queryDesc);
static void pltsql_ExecutorEnd(QueryDesc *queryDesc);
static bool pltsql_ViewInsteadStmtTrigger(Relation view, CmdType event);

static bool plsql_TriggerRecursiveCheck(ResultRelInfo *resultRelInfo);
static bool bbf_check_rowcount_hook(int es_processed);
Expand Down Expand Up @@ -201,6 +202,7 @@ static ExecutorFinish_hook_type prev_ExecutorFinish = NULL;
static ExecutorEnd_hook_type prev_ExecutorEnd = NULL;
static GetNewObjectId_hook_type prev_GetNewObjectId_hook = NULL;
static inherit_view_constraints_from_table_hook_type prev_inherit_view_constraints_from_table = NULL;
static ViewInsteadStmtTrigger_hook_type prev_ViewInsteadStmtTrigger = NULL;
static detect_numeric_overflow_hook_type prev_detect_numeric_overflow_hook = NULL;
static match_pltsql_func_call_hook_type prev_match_pltsql_func_call_hook = NULL;
static insert_pltsql_function_defaults_hook_type prev_insert_pltsql_function_defaults_hook = NULL;
Expand Down Expand Up @@ -314,6 +316,9 @@ InstallExtendedHooks(void)
inherit_view_constraints_from_table_hook = preserve_view_constraints_from_base_table;
TriggerRecuresiveCheck_hook = plsql_TriggerRecursiveCheck;

prev_ViewInsteadStmtTrigger = ViewInsteadStmtTrigger_hook;
ViewInsteadStmtTrigger_hook = pltsql_ViewInsteadStmtTrigger;

prev_detect_numeric_overflow_hook = detect_numeric_overflow_hook;
detect_numeric_overflow_hook = pltsql_detect_numeric_overflow;

Expand Down Expand Up @@ -421,6 +426,7 @@ UninstallExtendedHooks(void)
ExecutorEnd_hook = prev_ExecutorEnd;
GetNewObjectId_hook = prev_GetNewObjectId_hook;
inherit_view_constraints_from_table_hook = prev_inherit_view_constraints_from_table;
ViewInsteadStmtTrigger_hook = prev_ViewInsteadStmtTrigger;
detect_numeric_overflow_hook = prev_detect_numeric_overflow_hook;
match_pltsql_func_call_hook = prev_match_pltsql_func_call_hook;
insert_pltsql_function_defaults_hook = prev_insert_pltsql_function_defaults_hook;
Expand Down Expand Up @@ -699,6 +705,35 @@ plsql_TriggerRecursiveCheck(ResultRelInfo *resultRelInfo)
return false;
}

/**
* To allow rewriting view with base table if the view has an instead of trigger at statement level in BBF
*/
static bool
pltsql_ViewInsteadStmtTrigger(Relation view, CmdType event)
{
TriggerDesc *trigDesc = view->trigdesc;

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
Expand Down
21 changes: 21 additions & 0 deletions test/JDBC/expected/BABEL-2170-vu-cleanup.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
DROP TRIGGER IF EXISTS babel_2170_vu_employees_view_iot_insert;
GO

DROP TRIGGER IF EXISTS babel_2170_vu_employees_view_iot_update;
GO

DROP TRIGGER IF EXISTS babel_2170_vu_employees_view_iot_delete;
GO

DROP VIEW IF EXISTS babel_2170_vu_employees_view;
GO

DROP TABLE IF EXISTS babel_2170_vu_employees;
GO

SELECT name FROM sys.sysobjects WHERE name LIKE 'babel_2170%' ORDER BY name;
GO
~~START~~
varchar
~~END~~

31 changes: 31 additions & 0 deletions test/JDBC/expected/BABEL-2170-vu-prepare.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
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');
INSERT INTO babel_2170_vu_employees VALUES(3, 'ana', '1st Street', '3000');
INSERT INTO babel_2170_vu_employees VALUES(4, 'adam', '1st Street', '4000');
GO
~~ROW COUNT: 1~~

~~ROW COUNT: 1~~

~~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
138 changes: 138 additions & 0 deletions test/JDBC/expected/BABEL-2170-vu-verify.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
-- 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
UPDATE babel_2170_vu_employees SET EmployeeAddress = 'New Street' WHERE EmployeeID = 3;
END
GO

INSERT INTO babel_2170_vu_employees_view VALUES(5, 'alex', '1st Street', '5000');
GO
~~ROW COUNT: 1~~

~~ROW COUNT: 1~~


SELECT COUNT(EmployeeID) FROM babel_2170_vu_employees;
GO
~~START~~
int
4
~~END~~


SELECT COUNT(EmployeeID) FROM babel_2170_vu_employees_view;
GO
~~START~~
int
4
~~END~~


UPDATE babel_2170_vu_employees SET EmployeeAddress = '1st Street' WHERE EmployeeID = 3;
GO
~~ROW COUNT: 1~~


-- 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
UPDATE babel_2170_vu_employees SET MonthSalary = MonthSalary + 100 WHERE EmployeeID = 3;
END
GO

UPDATE babel_2170_vu_employees_view SET MonthSalary = MonthSalary +1 WHERE EmployeeID = 3;
GO
~~ROW COUNT: 1~~

~~ROW COUNT: 1~~


SELECT EmployeeID,EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees WHERE EmployeeID = 3 ORDER BY EmployeeID;
GO
~~START~~
int#!#varchar#!#varchar#!#numeric
3#!#ana#!#1st Street#!#3100.00
~~END~~


UPDATE babel_2170_vu_employees SET MonthSalary = 3000 WHERE EmployeeID = 3;
GO
~~ROW COUNT: 1~~


BEGIN TRANSACTION
UPDATE babel_2170_vu_employees_view SET MonthSalary = MonthSalary +1 WHERE EmployeeID IN (3, 4);
COMMIT TRANSACTION;
GO
~~ROW COUNT: 1~~

~~ROW COUNT: 2~~


SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees WHERE EmployeeID IN (3, 4) ORDER BY EmployeeID;
GO
~~START~~
int#!#varchar#!#varchar#!#numeric
3#!#ana#!#1st Street#!#3100.00
4#!#adam#!#1st Street#!#4000.00
~~END~~


UPDATE babel_2170_vu_employees SET MonthSalary = 3000 WHERE EmployeeID = 3;
GO
~~ROW COUNT: 1~~


-- 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
UPDATE babel_2170_vu_employees SET MonthSalary = MonthSalary + 100 WHERE EmployeeID = 3;
END
GO

BEGIN TRANSACTION
DELETE FROM babel_2170_vu_employees_view WHERE EmployeeID IN (1, 2);
COMMIT TRANSACTION;
GO
~~ROW COUNT: 1~~

~~ROW COUNT: 2~~


SELECT COUNT(EmployeeID) FROM babel_2170_vu_employees_view;
GO
~~START~~
int
4
~~END~~


SELECT COUNT(EmployeeID) FROM babel_2170_vu_employees;
GO
~~START~~
int
4
~~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
3#!#ana#!#1st Street#!#3100.00
4#!#adam#!#1st Street#!#4000.00
~~END~~


UPDATE babel_2170_vu_employees SET MonthSalary = 3000 WHERE EmployeeID = 3;
GO
~~ROW COUNT: 1~~

17 changes: 17 additions & 0 deletions test/JDBC/input/triggers/BABEL-2170-vu-cleanup.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
DROP TRIGGER IF EXISTS babel_2170_vu_employees_view_iot_insert;
GO

DROP TRIGGER IF EXISTS babel_2170_vu_employees_view_iot_update;
GO

DROP TRIGGER IF EXISTS babel_2170_vu_employees_view_iot_delete;
GO

DROP VIEW IF EXISTS babel_2170_vu_employees_view;
GO

DROP TABLE IF EXISTS babel_2170_vu_employees;
GO

SELECT name FROM sys.sysobjects WHERE name LIKE 'babel_2170%' ORDER BY name;
GO
23 changes: 23 additions & 0 deletions test/JDBC/input/triggers/BABEL-2170-vu-prepare.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
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');
INSERT INTO babel_2170_vu_employees VALUES(3, 'ana', '1st Street', '3000');
INSERT INTO babel_2170_vu_employees VALUES(4, 'adam', '1st Street', '4000');
GO

CREATE VIEW babel_2170_vu_employees_view AS
SELECT EmployeeID,
EmployeeName,
EmployeeAddress,
MonthSalary
FROM babel_2170_vu_employees
WHERE EmployeeName LIKE 'a%';
GO
75 changes: 75 additions & 0 deletions test/JDBC/input/triggers/BABEL-2170-vu-verify.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
-- 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
UPDATE babel_2170_vu_employees SET EmployeeAddress = 'New Street' WHERE EmployeeID = 3;
END
GO

INSERT INTO babel_2170_vu_employees_view VALUES(5, 'alex', '1st Street', '5000');
GO

SELECT COUNT(EmployeeID) FROM babel_2170_vu_employees;
GO

SELECT COUNT(EmployeeID) FROM babel_2170_vu_employees_view;
GO

UPDATE babel_2170_vu_employees SET EmployeeAddress = '1st Street' WHERE EmployeeID = 3;
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
UPDATE babel_2170_vu_employees SET MonthSalary = MonthSalary + 100 WHERE EmployeeID = 3;
END
GO

UPDATE babel_2170_vu_employees_view SET MonthSalary = MonthSalary +1 WHERE EmployeeID = 3;
GO

SELECT EmployeeID,EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees WHERE EmployeeID = 3 ORDER BY EmployeeID;
GO

UPDATE babel_2170_vu_employees SET MonthSalary = 3000 WHERE EmployeeID = 3;
GO

BEGIN TRANSACTION
UPDATE babel_2170_vu_employees_view SET MonthSalary = MonthSalary +1 WHERE EmployeeID IN (3, 4);
COMMIT TRANSACTION;
GO

SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees WHERE EmployeeID IN (3, 4) ORDER BY EmployeeID;
GO

UPDATE babel_2170_vu_employees SET MonthSalary = 3000 WHERE EmployeeID = 3;
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
UPDATE babel_2170_vu_employees SET MonthSalary = MonthSalary + 100 WHERE EmployeeID = 3;
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

UPDATE babel_2170_vu_employees SET MonthSalary = 3000 WHERE EmployeeID = 3;
GO

0 comments on commit 34c3d17

Please sign in to comment.