]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Add API of sorts for transition table handling in trigger.c
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Fri, 11 Mar 2022 23:40:03 +0000 (20:40 -0300)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Fri, 11 Mar 2022 23:40:03 +0000 (20:40 -0300)
Preparatory patch for further additions in this area, particularly to
allow MERGE to have separate transition tables for each action.

Author: Pavan Deolasee <pavan.deolasee@gmail.com>
Reviewed-by: Álvaro Herrera <alvherre@alvh.no-ip.org>
Discussion: https://postgr.es/m/CABOikdNj+8HEJ5D8tu56mrPkjHVRrBb2_cdKWwpiYNcjXgDw8g@mail.gmail.com
Discussion: https://postgr.es/m/20201231134736.GA25392@alvherre.pgsql

src/backend/commands/trigger.c

index 1a9c1ac2904f3baedfcb8369b83281e99e8e4249..e08bd9a370f3820e0492ed5ab6bc10f81a1f9435 100644 (file)
@@ -3772,6 +3772,16 @@ static AfterTriggersTableData *GetAfterTriggersTableData(Oid relid,
                                                                                                                 CmdType cmdType);
 static TupleTableSlot *GetAfterTriggersStoreSlot(AfterTriggersTableData *table,
                                                                                                 TupleDesc tupdesc);
+static Tuplestorestate *GetAfterTriggersTransitionTable(int event,
+                                                                                                               TupleTableSlot *oldslot,
+                                                                                                               TupleTableSlot *newslot,
+                                                                                                               TransitionCaptureState *transition_capture);
+static void TransitionTableAddTuple(EState *estate,
+                                                                       TransitionCaptureState *transition_capture,
+                                                                       ResultRelInfo *relinfo,
+                                                                       TupleTableSlot *slot,
+                                                                       TupleTableSlot *original_insert_tuple,
+                                                                       Tuplestorestate *tuplestore);
 static void AfterTriggerFreeQuery(AfterTriggersQueryData *qs);
 static SetConstraintState SetConstraintStateCreate(int numalloc);
 static SetConstraintState SetConstraintStateCopy(SetConstraintState state);
@@ -5158,6 +5168,92 @@ AfterTriggerEndSubXact(bool isCommit)
        }
 }
 
+/*
+ * Get the transition table for the given event and depending on whether we are
+ * processing the old or the new tuple.
+ */
+static Tuplestorestate *
+GetAfterTriggersTransitionTable(int event,
+                                                               TupleTableSlot *oldslot,
+                                                               TupleTableSlot *newslot,
+                                                               TransitionCaptureState *transition_capture)
+{
+       Tuplestorestate *tuplestore = NULL;
+       bool            delete_old_table = transition_capture->tcs_delete_old_table;
+       bool            update_old_table = transition_capture->tcs_update_old_table;
+       bool            update_new_table = transition_capture->tcs_update_new_table;
+       bool            insert_new_table = transition_capture->tcs_insert_new_table;
+
+       /*
+        * For INSERT events NEW should be non-NULL, for DELETE events OLD should
+        * be non-NULL, whereas for UPDATE events normally both OLD and NEW are
+        * non-NULL.  But for UPDATE events fired for capturing transition tuples
+        * during UPDATE partition-key row movement, OLD is NULL when the event is
+        * for a row being inserted, whereas NEW is NULL when the event is for a
+        * row being deleted.
+        */
+       Assert(!(event == TRIGGER_EVENT_DELETE && delete_old_table &&
+                        TupIsNull(oldslot)));
+       Assert(!(event == TRIGGER_EVENT_INSERT && insert_new_table &&
+                        TupIsNull(newslot)));
+
+       if (!TupIsNull(oldslot))
+       {
+               Assert(TupIsNull(newslot));
+               if (event == TRIGGER_EVENT_DELETE && delete_old_table)
+                       tuplestore = transition_capture->tcs_private->old_tuplestore;
+               else if (event == TRIGGER_EVENT_UPDATE && update_old_table)
+                       tuplestore = transition_capture->tcs_private->old_tuplestore;
+       }
+       else if (!TupIsNull(newslot))
+       {
+               Assert(TupIsNull(oldslot));
+               if (event == TRIGGER_EVENT_INSERT && insert_new_table)
+                       tuplestore = transition_capture->tcs_private->new_tuplestore;
+               else if (event == TRIGGER_EVENT_UPDATE && update_new_table)
+                       tuplestore = transition_capture->tcs_private->new_tuplestore;
+       }
+
+       return tuplestore;
+}
+
+/*
+ * Add the given heap tuple to the given tuplestore, applying the conversion
+ * map if necessary.
+ *
+ * If original_insert_tuple is given, we can add that tuple without conversion.
+ */
+static void
+TransitionTableAddTuple(EState *estate,
+                                               TransitionCaptureState *transition_capture,
+                                               ResultRelInfo *relinfo,
+                                               TupleTableSlot *slot,
+                                               TupleTableSlot *original_insert_tuple,
+                                               Tuplestorestate *tuplestore)
+{
+       TupleConversionMap *map;
+
+       /*
+        * Nothing needs to be done if we don't have a tuplestore.
+        */
+       if (tuplestore == NULL)
+               return;
+
+       if (original_insert_tuple)
+               tuplestore_puttupleslot(tuplestore, original_insert_tuple);
+       else if ((map = ExecGetChildToRootMap(relinfo)) != NULL)
+       {
+               AfterTriggersTableData *table = transition_capture->tcs_private;
+               TupleTableSlot *storeslot;
+
+               storeslot = GetAfterTriggersStoreSlot(table, map->outdesc);
+               execute_attr_map_slot(map->attrMap, slot, storeslot);
+               tuplestore_puttupleslot(tuplestore, storeslot);
+       }
+       else
+               tuplestore_puttupleslot(tuplestore, slot);
+}
+
 /* ----------
  * AfterTriggerEnlargeQueryState()
  *
@@ -5650,7 +5746,6 @@ AfterTriggerPendingOnRel(Oid relid)
        return false;
 }
 
-
 /* ----------
  * AfterTriggerSaveEvent()
  *
@@ -5709,68 +5804,39 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
         */
        if (row_trigger && transition_capture != NULL)
        {
-               TupleTableSlot *original_insert_tuple = transition_capture->tcs_original_insert_tuple;
-               TupleConversionMap *map = ExecGetChildToRootMap(relinfo);
-               bool            delete_old_table = transition_capture->tcs_delete_old_table;
-               bool            update_old_table = transition_capture->tcs_update_old_table;
-               bool            update_new_table = transition_capture->tcs_update_new_table;
-               bool            insert_new_table = transition_capture->tcs_insert_new_table;
 
                /*
-                * For INSERT events NEW should be non-NULL, for DELETE events OLD
-                * should be non-NULL, whereas for UPDATE events normally both OLD and
-                * NEW are non-NULL.  But for UPDATE events fired for capturing
-                * transition tuples during UPDATE partition-key row movement, OLD is
-                * NULL when the event is for a row being inserted, whereas NEW is
-                * NULL when the event is for a row being deleted.
+                * Capture the old tuple in the appropriate transition table based on
+                * the event.
                 */
-               Assert(!(event == TRIGGER_EVENT_DELETE && delete_old_table &&
-                                TupIsNull(oldslot)));
-               Assert(!(event == TRIGGER_EVENT_INSERT && insert_new_table &&
-                                TupIsNull(newslot)));
-
-               if (!TupIsNull(oldslot) &&
-                       ((event == TRIGGER_EVENT_DELETE && delete_old_table) ||
-                        (event == TRIGGER_EVENT_UPDATE && update_old_table)))
+               if (!TupIsNull(oldslot))
                {
                        Tuplestorestate *old_tuplestore;
 
-                       old_tuplestore = transition_capture->tcs_private->old_tuplestore;
-
-                       if (map != NULL)
-                       {
-                               AfterTriggersTableData *table = transition_capture->tcs_private;
-                               TupleTableSlot *storeslot;
-
-                               storeslot = GetAfterTriggersStoreSlot(table, map->outdesc);
-                               execute_attr_map_slot(map->attrMap, oldslot, storeslot);
-                               tuplestore_puttupleslot(old_tuplestore, storeslot);
-                       }
-                       else
-                               tuplestore_puttupleslot(old_tuplestore, oldslot);
+                       old_tuplestore = GetAfterTriggersTransitionTable(event,
+                                                                                                                        oldslot,
+                                                                                                                        NULL,
+                                                                                                                        transition_capture);
+                       TransitionTableAddTuple(estate, transition_capture, relinfo,
+                                                                       oldslot, NULL, old_tuplestore);
                }
-               if (!TupIsNull(newslot) &&
-                       ((event == TRIGGER_EVENT_INSERT && insert_new_table) ||
-                        (event == TRIGGER_EVENT_UPDATE && update_new_table)))
+
+               /*
+                * Capture the new tuple in the appropriate transition table based on
+                * the event.
+                */
+               if (!TupIsNull(newslot))
                {
                        Tuplestorestate *new_tuplestore;
 
-                       new_tuplestore = transition_capture->tcs_private->new_tuplestore;
-
-                       if (original_insert_tuple != NULL)
-                               tuplestore_puttupleslot(new_tuplestore,
-                                                                               original_insert_tuple);
-                       else if (map != NULL)
-                       {
-                               AfterTriggersTableData *table = transition_capture->tcs_private;
-                               TupleTableSlot *storeslot;
-
-                               storeslot = GetAfterTriggersStoreSlot(table, map->outdesc);
-                               execute_attr_map_slot(map->attrMap, newslot, storeslot);
-                               tuplestore_puttupleslot(new_tuplestore, storeslot);
-                       }
-                       else
-                               tuplestore_puttupleslot(new_tuplestore, newslot);
+                       new_tuplestore = GetAfterTriggersTransitionTable(event,
+                                                                                                                        NULL,
+                                                                                                                        newslot,
+                                                                                                                        transition_capture);
+                       TransitionTableAddTuple(estate, transition_capture, relinfo,
+                                                                       newslot,
+                                                                       transition_capture->tcs_original_insert_tuple,
+                                                                       new_tuplestore);
                }
 
                /*