Skip to content

Commit

Permalink
Support Instead of Trigger On Views (#272)
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 Instead of Triggers
for DML queries when using Babelfish.

Task: BABEL-2170/BABEL-4532/BABEL-4514
Signed-off-by: Deepakshi Mittal <[email protected]>
  • Loading branch information
deepakshi-mittal authored Jan 3, 2024
1 parent 4b6d741 commit e00cbef
Show file tree
Hide file tree
Showing 6 changed files with 22 additions and 9 deletions.
5 changes: 4 additions & 1 deletion src/backend/commands/trigger.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ int SessionReplicationRole = SESSION_REPLICATION_ROLE_ORIGIN;

/* How many levels deep into trigger execution are we? */
static int MyTriggerDepth = 0;
List *triggerInvocationSequence = NIL; /* List to store all oids for triggers called*/

/* Local function prototypes */
static void renametrig_internal(Relation tgrel, Relation targetrel,
Expand Down Expand Up @@ -489,7 +490,7 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
RelationGetRelationName(rel)),
errdetail("Triggers on foreign tables cannot have transition tables.")));

if (rel->rd_rel->relkind == RELKIND_VIEW)
if (rel->rd_rel->relkind == RELKIND_VIEW && sql_dialect != SQL_DIALECT_TSQL)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is a view",
Expand Down Expand Up @@ -2571,11 +2572,13 @@ ExecCallTriggerFunc(TriggerData *trigdata,
MyTriggerDepth++;
PG_TRY();
{
triggerInvocationSequence = lappend_oid(triggerInvocationSequence, trigdata->tg_trigger->tgoid);
result = FunctionCallInvoke(fcinfo);
}
PG_FINALLY();
{
MyTriggerDepth--;
triggerInvocationSequence = list_delete_last(triggerInvocationSequence);
}
PG_END_TRY();

Expand Down
6 changes: 3 additions & 3 deletions src/backend/executor/execMain.c
Original file line number Diff line number Diff line change
Expand Up @@ -1031,23 +1031,23 @@ CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation)
switch (operation)
{
case CMD_INSERT:
if (!trigDesc || (!trigDesc->trig_insert_instead_row))
if (!trigDesc || (!trigDesc->trig_insert_instead_row && (sql_dialect == SQL_DIALECT_TSQL && !trigDesc->trig_insert_instead_statement)))
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("cannot insert into view \"%s\"",
RelationGetRelationName(resultRel)),
errhint("To enable inserting into the view, provide an INSTEAD OF INSERT trigger or an unconditional ON INSERT DO INSTEAD rule.")));
break;
case CMD_UPDATE:
if (!trigDesc || (!trigDesc->trig_update_instead_row))
if (!trigDesc || (!trigDesc->trig_update_instead_row && (sql_dialect == SQL_DIALECT_TSQL && !trigDesc->trig_update_instead_statement)))
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("cannot update view \"%s\"",
RelationGetRelationName(resultRel)),
errhint("To enable updating the view, provide an INSTEAD OF UPDATE trigger or an unconditional ON UPDATE DO INSTEAD rule.")));
break;
case CMD_DELETE:
if (!trigDesc || (!trigDesc->trig_delete_instead_row))
if (!trigDesc || (!trigDesc->trig_delete_instead_row && (sql_dialect == SQL_DIALECT_TSQL && !trigDesc->trig_delete_instead_statement)))
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("cannot delete from view \"%s\"",
Expand Down
6 changes: 4 additions & 2 deletions src/backend/executor/nodeModifyTable.c
Original file line number Diff line number Diff line change
Expand Up @@ -810,7 +810,8 @@ ExecInsert(ModifyTableContext *context,
return NULL; /* "do nothing" */
}
else if (sql_dialect == SQL_DIALECT_TSQL && resultRelInfo->ri_TrigDesc &&
resultRelInfo->ri_TrigDesc->trig_insert_instead_statement &&
resultRelInfo->ri_TrigDesc->trig_insert_instead_statement &&
bbfViewHasInsteadofTrigger_hook && (bbfViewHasInsteadofTrigger_hook)(resultRelationDesc, CMD_INSERT) &&
isTsqlInsteadofTriggerExecution(estate, resultRelInfo, TRIGGER_EVENT_INSERT))
{
ExecIRInsertTriggersTSQL(estate, resultRelInfo, slot, mtstate->mt_transition_capture);
Expand Down Expand Up @@ -1481,6 +1482,7 @@ ExecDelete(ModifyTableContext *context,
if (resultRelInfo->ri_TrigDesc &&
resultRelInfo->ri_TrigDesc->trig_delete_instead_statement &&
sql_dialect == SQL_DIALECT_TSQL &&
bbfViewHasInsteadofTrigger_hook && (bbfViewHasInsteadofTrigger_hook)(resultRelationDesc, CMD_DELETE) &&
isTsqlInsteadofTriggerExecution(estate, resultRelInfo, TRIGGER_EVENT_DELETE))
{
ExecIRDeleteTriggersTSQL(estate, resultRelInfo, tupleid, oldtuple, context->mtstate->mt_transition_capture);
Expand Down Expand Up @@ -2335,7 +2337,7 @@ ExecUpdate(ModifyTableContext *context, ResultRelInfo *resultRelInfo,

if (resultRelInfo->ri_TrigDesc &&
resultRelInfo->ri_TrigDesc->trig_update_instead_statement &&
sql_dialect == SQL_DIALECT_TSQL &&
sql_dialect == SQL_DIALECT_TSQL && bbfViewHasInsteadofTrigger_hook && (bbfViewHasInsteadofTrigger_hook)(resultRelationDesc, CMD_UPDATE) &&
isTsqlInsteadofTriggerExecution(estate, resultRelInfo, TRIGGER_EVENT_INSTEAD))
{
ExecIRUpdateTriggersTSQL(estate, resultRelInfo, tupleid, oldtuple, slot, context->mtstate->mt_transition_capture);
Expand Down
10 changes: 7 additions & 3 deletions src/backend/rewrite/rewriteHandler.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
#include "nodes/nodeFuncs.h"
#include "optimizer/optimizer.h"
#include "parser/analyze.h"
#include "parser/parser.h"
#include "parser/parser.h"
#include "parser/parse_coerce.h"
#include "parser/parse_relation.h"
#include "parser/parsetree.h"
Expand All @@ -46,6 +46,8 @@
#include "utils/lsyscache.h"
#include "utils/rel.h"

bbfViewHasInsteadofTrigger_hook_type bbfViewHasInsteadofTrigger_hook = NULL; /** BBF Hook to check Instead Of trigger on View */

/* We use a list of these to detect recursion in RewriteQuery */
typedef struct rewrite_event
{
Expand Down Expand Up @@ -1472,7 +1474,8 @@ rewriteValuesRTE(Query *parsetree, RangeTblEntry *rte, int rti,
*/
isAutoUpdatableView = false;
if (target_relation->rd_rel->relkind == RELKIND_VIEW &&
!view_has_instead_trigger(target_relation, CMD_INSERT))
(!view_has_instead_trigger(target_relation, CMD_INSERT) &&
!(sql_dialect == SQL_DIALECT_TSQL && bbfViewHasInsteadofTrigger_hook && (bbfViewHasInsteadofTrigger_hook)(target_relation, CMD_INSERT))))
{
List *locks;
bool hasUpdate;
Expand Down Expand Up @@ -3953,7 +3956,8 @@ RewriteQuery(Query *parsetree, List *rewrite_events, int orig_rt_length)
*/
if (!instead &&
rt_entry_relation->rd_rel->relkind == RELKIND_VIEW &&
!view_has_instead_trigger(rt_entry_relation, event))
(!view_has_instead_trigger(rt_entry_relation, event)
&& !(sql_dialect == SQL_DIALECT_TSQL && bbfViewHasInsteadofTrigger_hook && (bbfViewHasInsteadofTrigger_hook)(rt_entry_relation, event))))
{
/*
* If there were any qualified INSTEAD rules, don't allow the view
Expand Down
1 change: 1 addition & 0 deletions src/include/commands/trigger.h
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@ extern void AfterTriggerEndSubXact(bool isCommit);
extern void AfterTriggerSetState(ConstraintsSetStmt *stmt);
extern bool AfterTriggerPendingOnRel(Oid relid);

extern List *triggerInvocationSequence; /* List to store all oids for triggers called */

/*
* in utils/adt/ri_triggers.c
Expand Down
3 changes: 3 additions & 0 deletions src/include/executor/executor.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ extern PGDLLIMPORT ExecutorCheckPerms_hook_type ExecutorCheckPerms_hook;
typedef bool (*TriggerRecuresiveCheck_hook_type) (ResultRelInfo *resultRelInfo);
extern PGDLLIMPORT TriggerRecuresiveCheck_hook_type TriggerRecuresiveCheck_hook;

typedef bool (*bbfViewHasInsteadofTrigger_hook_type) (Relation view, CmdType event);
extern PGDLLIMPORT bbfViewHasInsteadofTrigger_hook_type bbfViewHasInsteadofTrigger_hook;

typedef bool (*check_rowcount_hook_type) (int es_processed);
extern PGDLLIMPORT check_rowcount_hook_type check_rowcount_hook;

Expand Down

0 comments on commit e00cbef

Please sign in to comment.