Skip to content

Commit

Permalink
Fix Improper Plan Invalidation for Fkey Integrity check queries (babe…
Browse files Browse the repository at this point in the history
…lfish-for-postgresql#3528)

Introduce a hook , that checks whether the hashed plan for Referential integrity queries is valid or not , as in case for Babelfish there can be change in search path due to for example table variables etc , if the search path doesn't match we discard the plan, and replan this query.

Added Test Cases To verify complex test cases involving DELETE ACTIONS and triggers

Task: BABEL-5270

Engine PR babelfish-for-postgresql/postgresql_modified_for_babelfish#539

Signed-off-by: Nirmit Shah [email protected]
  • Loading branch information
shah-nirmit authored Feb 27, 2025
1 parent 46630f2 commit 0a03c22
Show file tree
Hide file tree
Showing 7 changed files with 458 additions and 1 deletion.
23 changes: 22 additions & 1 deletion contrib/babelfishpg_tsql/src/hooks.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
#include "commands/view.h"
#include "common/logging.h"
#include "executor/execExpr.h"
#include "executor/spi.h"
#include "executor/spi_priv.h"
#include "funcapi.h"
#include "libpq/libpq.h"
#include "miscadmin.h"
Expand Down Expand Up @@ -201,6 +203,7 @@ static void is_function_pg_stat_valid(FunctionCallInfo fcinfo,
char prokind, bool finalize);
static AclResult pltsql_ExecFuncProc_AclCheck(Oid funcid);
static bool allow_storing_init_privs(Oid objoid, Oid classoid, int objsubid);
static bool pltsql_validateCachedPlanSearchPath(SPIPlanPtr plan);

/*****************************************
* Replication Hooks
Expand Down Expand Up @@ -309,6 +312,7 @@ static pltsql_is_partitioned_table_reloptions_allowed_hook_type prev_pltsql_is_p
static ExecFuncProc_AclCheck_hook_type prev_ExecFuncProc_AclCheck_hook = NULL;
static bbf_execute_grantstmt_as_dbsecadmin_hook_type prev_bbf_execute_grantstmt_as_dbsecadmin_hook = NULL;
static bbf_check_member_has_direct_priv_to_grant_role_hook_type prev_bbf_check_member_has_direct_priv_to_grant_role_hook = NULL;
static validateCachedPlanSearchPath_hook_type prev_validateCachedPlanSearchPath_hook = NULL;

/*****************************************
* Install / Uninstall
Expand Down Expand Up @@ -536,6 +540,8 @@ InstallExtendedHooks(void)

pltsql_allow_storing_init_privs_hook = allow_storing_init_privs;

prev_validateCachedPlanSearchPath_hook = validateCachedPlanSearchPath_hook;
validateCachedPlanSearchPath_hook = pltsql_validateCachedPlanSearchPath;
is_bbf_tds_connection_hook = is_bbf_tds_connection;
}

Expand Down Expand Up @@ -607,7 +613,7 @@ UninstallExtendedHooks(void)
ExecFuncProc_AclCheck_hook = prev_ExecFuncProc_AclCheck_hook;
bbf_execute_grantstmt_as_dbsecadmin_hook = prev_bbf_execute_grantstmt_as_dbsecadmin_hook;
bbf_check_member_has_direct_priv_to_grant_role_hook = prev_bbf_check_member_has_direct_priv_to_grant_role_hook;

validateCachedPlanSearchPath_hook = prev_validateCachedPlanSearchPath_hook;

bbf_InitializeParallelDSM_hook = NULL;
bbf_ParallelWorkerMain_hook = NULL;
Expand Down Expand Up @@ -6028,3 +6034,18 @@ is_bbf_tds_connection(void)
{
return IS_TDS_CONN();
}
static bool
pltsql_validateCachedPlanSearchPath(SPIPlanPtr plan)
{
ListCell *lc;

foreach(lc, plan->plancache_list)
{
CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);

if (!SearchPathMatchesCurrentEnvironment(plansource->search_path))
return false;
}
return true;

}
21 changes: 21 additions & 0 deletions test/JDBC/expected/fk_trigger_temp-vu-cleanup.out
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ DROP TRIGGER IF EXISTS [trg_i_COD]
DROP TRIGGER IF EXISTS tr_UniqueChild_Insert;
DROP TRIGGER IF EXISTS tr_UniqueChild_Update;
DROP TRIGGER IF EXISTS tr_UniqueChild_ComplexInsert;
DROP TRIGGER IF EXISTS Cascade_Delete_TransitionTbl_Trig1;
DROP TRIGGER IF EXISTS Cascade_Delete_TransitionTbl_Trig2;
DROP TRIGGER IF EXISTS Cascade_Delete_TransitionTbl_Trig3;
DROP TRIGGER IF EXISTS Cascade_Update_TransitionTbl_Trig1;
DROP TRIGGER IF EXISTS Cascade_Update_TransitionTbl_Trig2;
DROP TRIGGER IF EXISTS Cascade_Update_TransitionTbl_Trig3;
DROP TRIGGER IF EXISTS Del_Cascade_trig1;
GO

-- constraints
Expand Down Expand Up @@ -47,4 +54,18 @@ DROP TABLE IF EXISTS [dbo].[OrderItem]
DROP TABLE IF EXISTS [order]
DROP TABLE IF EXISTS UniqueChild;
DROP TABLE IF EXISTS UniqueParent;
DROP TABLE IF EXISTS Cascade_Delete_TransitionTbl6;
DROP TABLE IF EXISTS Cascade_Delete_TransitionTbl5;
DROP TABLE IF EXISTS Cascade_Delete_TransitionTbl4;
DROP TABLE IF EXISTS Cascade_Delete_TransitionTbl3;
DROP TABLE IF EXISTS Cascade_Delete_TransitionTbl2;
DROP TABLE IF EXISTS Cascade_Delete_TransitionTbl1;
DROP TABLE IF EXISTS Cascade_Update_TransitionTbl6;
DROP TABLE IF EXISTS Cascade_Update_TransitionTbl5;
DROP TABLE IF EXISTS Cascade_Update_TransitionTbl4;
DROP TABLE IF EXISTS Cascade_Update_TransitionTbl3;
DROP TABLE IF EXISTS Cascade_Update_TransitionTbl2;
DROP TABLE IF EXISTS Cascade_Update_TransitionTbl1;
DROP TABLE IF EXISTS Del_Cascade_child;
DROP TABLE IF EXISTS Del_Cascade_parent;
GO
135 changes: 135 additions & 0 deletions test/JDBC/expected/fk_trigger_temp-vu-prepare.out
Original file line number Diff line number Diff line change
Expand Up @@ -246,3 +246,138 @@ INSERT INTO ChildSetDefault (ChildID, ParentID, ChildName) VALUES (1, 1, 'ChildS
GO
~~ROW COUNT: 2~~


-- checking transition tables in delete triggers
CREATE TABLE Cascade_Delete_TransitionTbl1 (id INT PRIMARY KEY)
GO

CREATE TABLE Cascade_Delete_TransitionTbl2 ( t_id INT, FOREIGN KEY (t_id) REFERENCES Cascade_Delete_TransitionTbl1(id) ON DELETE CASCADE);
GO

CREATE TRIGGER Cascade_Delete_TransitionTbl_Trig1 ON Cascade_Delete_TransitionTbl2 AFTER DELETE AS SELECT * FROM DELETED; SELECT * FROM INSERTED;
GO

INSERT INTO Cascade_Delete_TransitionTbl1 VALUES (1)
INSERT INTO Cascade_Delete_TransitionTbl2 VALUES (1)
GO
~~ROW COUNT: 1~~

~~ROW COUNT: 1~~


CREATE TABLE Cascade_Delete_TransitionTbl3 (id INT PRIMARY KEY)
GO

CREATE TABLE Cascade_Delete_TransitionTbl4 ( t_id INT, FOREIGN KEY (t_id) REFERENCES Cascade_Delete_TransitionTbl3(id) ON DELETE SET NULL);
GO

CREATE TRIGGER Cascade_Delete_TransitionTbl_Trig2 ON Cascade_Delete_TransitionTbl4 AFTER DELETE AS SELECT * FROM DELETED; SELECT * FROM INSERTED;
GO

INSERT INTO Cascade_Delete_TransitionTbl3 VALUES (1)
INSERT INTO Cascade_Delete_TransitionTbl4 VALUES (1)
GO
~~ROW COUNT: 1~~

~~ROW COUNT: 1~~


CREATE TABLE Cascade_Delete_TransitionTbl5 (id INT PRIMARY KEY)
GO

CREATE TABLE Cascade_Delete_TransitionTbl6 ( t_id INT, FOREIGN KEY (t_id) REFERENCES Cascade_Delete_TransitionTbl5(id) ON DELETE SET DEFAULT);
GO

CREATE TRIGGER Cascade_Delete_TransitionTbl_Trig3 ON Cascade_Delete_TransitionTbl6 AFTER DELETE AS SELECT * FROM DELETED; SELECT * FROM INSERTED;
GO

INSERT INTO Cascade_Delete_TransitionTbl5 VALUES (1)
INSERT INTO Cascade_Delete_TransitionTbl6 VALUES (1)
GO
~~ROW COUNT: 1~~

~~ROW COUNT: 1~~


-- checking transition tables in cascade update
CREATE TABLE Cascade_Update_TransitionTbl1 (id INT PRIMARY KEY)
GO

CREATE TABLE Cascade_Update_TransitionTbl2 ( t_id INT, FOREIGN KEY (t_id) REFERENCES Cascade_Update_TransitionTbl1(id) ON UPDATE CASCADE);
GO

CREATE TRIGGER Cascade_Update_TransitionTbl_Trig1 ON Cascade_Update_TransitionTbl2 AFTER UPDATE AS SELECT * FROM DELETED; SELECT * FROM INSERTED;
GO

INSERT INTO Cascade_Update_TransitionTbl1 VALUES (1)
INSERT INTO Cascade_Update_TransitionTbl2 VALUES (1)
GO
~~ROW COUNT: 1~~

~~ROW COUNT: 1~~


CREATE TABLE Cascade_Update_TransitionTbl3 (id INT PRIMARY KEY)
GO

CREATE TABLE Cascade_Update_TransitionTbl4 ( t_id INT, FOREIGN KEY (t_id) REFERENCES Cascade_Update_TransitionTbl3(id) ON UPDATE SET DEFAULT);
GO

CREATE TRIGGER Cascade_Update_TransitionTbl_Trig2 ON Cascade_Update_TransitionTbl4 AFTER UPDATE AS SELECT * FROM DELETED; SELECT * FROM INSERTED;
GO

INSERT INTO Cascade_Update_TransitionTbl3 VALUES (1)
INSERT INTO Cascade_Update_TransitionTbl4 VALUES (1)
GO
~~ROW COUNT: 1~~

~~ROW COUNT: 1~~


CREATE TABLE Cascade_Update_TransitionTbl5 (id INT PRIMARY KEY)
GO

CREATE TABLE Cascade_Update_TransitionTbl6 ( t_id INT, FOREIGN KEY (t_id) REFERENCES Cascade_Update_TransitionTbl5(id) ON UPDATE SET NULL);
GO

CREATE TRIGGER Cascade_Update_TransitionTbl_Trig3 ON Cascade_Update_TransitionTbl6 AFTER UPDATE AS SELECT * FROM DELETED; SELECT * FROM INSERTED;
GO

INSERT INTO Cascade_Update_TransitionTbl5 VALUES (1)
INSERT INTO Cascade_Update_TransitionTbl6 VALUES (1)
GO
~~ROW COUNT: 1~~

~~ROW COUNT: 1~~


create table Del_Cascade_parent(a int primary key)
go

create table Del_Cascade_child(b int, foreign key (b) REFERENCES Del_Cascade_parent(a) ON DELETE CASCADE)
GO




create trigger Del_Cascade_trig1 on Del_Cascade_child AFTER DELETE AS BEGIN
DECLARE @test TABLE
(
pkOrderItem INT NOT NULL , /**/ PRIMARY KEY ( pkOrderItem )
)
INSERT INTO @test
( pkOrderItem )
SELECT b
FROM deleted
SELECT TOP 1 * from @test
END
GO

INSERT INTO Del_Cascade_parent VALUES (generate_series(1,10))
GO
~~ROW COUNT: 10~~

INSERT INTO Del_Cascade_child VALUES (generate_series(1,10))
GO
~~ROW COUNT: 10~~

115 changes: 115 additions & 0 deletions test/JDBC/expected/fk_trigger_temp-vu-verify.out
Original file line number Diff line number Diff line change
Expand Up @@ -459,3 +459,118 @@ GO

~~ERROR (Message: insert or update on table "childsetdefault" violates foreign key constraint "fk_childsetdefault_parent")~~


-- tsql user=jdbc_user password=12345678
-- Case 13: DELETE CASCADE/SET NULL/SET DEFAULT
-- Should Pass
DELETE FROM Cascade_Delete_TransitionTbl1;
GO
~~START~~
int
1
~~END~~

~~START~~
int
~~END~~

~~ROW COUNT: 1~~

-- Should Pass
DELETE FROM Cascade_Delete_TransitionTbl3;
GO
~~ROW COUNT: 1~~

-- Should Pass
DELETE FROM Cascade_Delete_TransitionTbl5;
GO
~~ROW COUNT: 1~~


-- tsql user=jdbc_user password=12345678
-- Case 14: UPDATE CASCADE/SET NULL/SET DEFAULT
-- Should Pass
Update Cascade_Update_TransitionTbl1 set id = 2 where id=1;
GO
~~START~~
int
1
~~END~~

~~START~~
int
2
~~END~~

~~ROW COUNT: 1~~

-- Should Pass
Update Cascade_Update_TransitionTbl3 set id = 2 where id=1;
GO
~~START~~
int
1
~~END~~

~~START~~
int
<NULL>
~~END~~

~~ROW COUNT: 1~~

-- Should Pass
Update Cascade_Update_TransitionTbl5 set id = 2 where id=1;
GO
~~START~~
int
1
~~END~~

~~START~~
int
<NULL>
~~END~~

~~ROW COUNT: 1~~


-- tsql user=jdbc_user password=12345678
-- Case 15: Delete Cascade with search path changing
DELETE FROM Del_Cascade_parent WHERE a = 1
GO
~~ROW COUNT: 1~~

~~START~~
int
1
~~END~~

~~ROW COUNT: 1~~

USE tempdb
GO
DELETE FROM master.dbo.Del_Cascade_parent WHERE a = 2
GO
~~ROW COUNT: 1~~

~~START~~
int
2
~~END~~

~~ROW COUNT: 1~~

USE master
GO
DELETE FROM master.dbo.Del_Cascade_parent WHERE a = 3
GO
~~ROW COUNT: 1~~

~~START~~
int
3
~~END~~

~~ROW COUNT: 1~~

21 changes: 21 additions & 0 deletions test/JDBC/input/fk_trigger_temp-vu-cleanup.mix
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ DROP TRIGGER IF EXISTS [trg_i_COD]
DROP TRIGGER IF EXISTS tr_UniqueChild_Insert;
DROP TRIGGER IF EXISTS tr_UniqueChild_Update;
DROP TRIGGER IF EXISTS tr_UniqueChild_ComplexInsert;
DROP TRIGGER IF EXISTS Cascade_Delete_TransitionTbl_Trig1;
DROP TRIGGER IF EXISTS Cascade_Delete_TransitionTbl_Trig2;
DROP TRIGGER IF EXISTS Cascade_Delete_TransitionTbl_Trig3;
DROP TRIGGER IF EXISTS Cascade_Update_TransitionTbl_Trig1;
DROP TRIGGER IF EXISTS Cascade_Update_TransitionTbl_Trig2;
DROP TRIGGER IF EXISTS Cascade_Update_TransitionTbl_Trig3;
DROP TRIGGER IF EXISTS Del_Cascade_trig1;
GO

-- constraints
Expand Down Expand Up @@ -47,4 +54,18 @@ DROP TABLE IF EXISTS [dbo].[OrderItem]
DROP TABLE IF EXISTS [order]
DROP TABLE IF EXISTS UniqueChild;
DROP TABLE IF EXISTS UniqueParent;
DROP TABLE IF EXISTS Cascade_Delete_TransitionTbl6;
DROP TABLE IF EXISTS Cascade_Delete_TransitionTbl5;
DROP TABLE IF EXISTS Cascade_Delete_TransitionTbl4;
DROP TABLE IF EXISTS Cascade_Delete_TransitionTbl3;
DROP TABLE IF EXISTS Cascade_Delete_TransitionTbl2;
DROP TABLE IF EXISTS Cascade_Delete_TransitionTbl1;
DROP TABLE IF EXISTS Cascade_Update_TransitionTbl6;
DROP TABLE IF EXISTS Cascade_Update_TransitionTbl5;
DROP TABLE IF EXISTS Cascade_Update_TransitionTbl4;
DROP TABLE IF EXISTS Cascade_Update_TransitionTbl3;
DROP TABLE IF EXISTS Cascade_Update_TransitionTbl2;
DROP TABLE IF EXISTS Cascade_Update_TransitionTbl1;
DROP TABLE IF EXISTS Del_Cascade_child;
DROP TABLE IF EXISTS Del_Cascade_parent;
GO
Loading

0 comments on commit 0a03c22

Please sign in to comment.