BEFORE/AFTER ROW INSERT triggers startup from CopyFrom()
authorVadim B. Mikheev
Mon, 1 Sep 1997 07:59:06 +0000 (07:59 +0000)
committerVadim B. Mikheev
Mon, 1 Sep 1997 07:59:06 +0000 (07:59 +0000)
RelationBuildTriggers() & FreeTriggerDesc() in trigger.c

src/backend/commands/copy.c
src/backend/commands/trigger.c

index 5fb94874256c17ed3ec49d5572f0d425c26c34a5..4aa9e6896d3032b8caf4de001f6a7a1017ed051c 100644 (file)
@@ -6,7 +6,7 @@
  *
  *
  * IDENTIFICATION
- *    $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.27 1997/08/22 14:22:09 vadim Exp $
+ *    $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.28 1997/09/01 07:59:04 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -34,6 +34,7 @@
 #include 
 #include 
 #include 
+#include "commands/trigger.h"
 #include 
 
 #define ISOCTAL(c) (((c) >= '0') && ((c) <= '7'))
@@ -334,6 +335,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
     InsertIndexResult indexRes;
     TupleDesc tupDesc;
     Oid loaded_oid;
+    bool skip_tuple = false;
     
     tupDesc = RelationGetTupleDescriptor(rel);
     attr = tupDesc->attrs;
@@ -602,41 +604,65 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
         tuple = heap_formtuple(tupDesc, values, nulls);
         if (oids)
             tuple->t_oid = loaded_oid;
-
-   /* ----------------
-    * Check the constraints of a tuple
-    * ----------------
-    */
-   
-       if ( rel->rd_att->constr )
+       
+       skip_tuple = false;
+       /* BEFORE ROW INSERT Triggers */
+       if ( rel->trigdesc && 
+           rel->trigdesc->n_before_row[TRIGGER_ACTION_INSERT] > 0 )
        {
            HeapTuple newtuple;
        
-           newtuple = ExecConstraints ("CopyFrom", rel, tuple);
-           
-           if ( newtuple != tuple )
+           newtuple = ExecBRInsertTriggers (rel, tuple);
+       
+           if ( newtuple == NULL )     /* "do nothing" */
+               skip_tuple = true;
+           else if ( newtuple != tuple )   /* modified by Trigger(s) */
            {
                pfree (tuple);
                tuple = newtuple;
            }
        }
+       
+       if ( !skip_tuple )
+       {
+       /* ----------------
+        * Check the constraints of a tuple
+        * ----------------
+        */
    
-        heap_insert(rel, tuple);
+           if ( rel->rd_att->constr )
+           {
+               HeapTuple newtuple;
+       
+               newtuple = ExecConstraints ("CopyFrom", rel, tuple);
+           
+               if ( newtuple != tuple )
+               {
+                   pfree (tuple);
+                   tuple = newtuple;
+               }
+           }
+   
+            heap_insert(rel, tuple);
             
-        if (has_index) {
-            for (i = 0; i < n_indices; i++) {
-                if (indexPred[i] != NULL) {
+            if (has_index) 
+            {
+               for (i = 0; i < n_indices; i++) 
+               {
+                    if (indexPred[i] != NULL) 
+                    {
 #ifndef OMIT_PARTIAL_INDEX
-                    /* if tuple doesn't satisfy predicate,
-                     * don't update index
-                     */
-                    slot->val = tuple;
-                    /*SetSlotContents(slot, tuple); */
-                    if (ExecQual((List*)indexPred[i], econtext) == false)
-                        continue;
+                       /* 
+                        * if tuple doesn't satisfy predicate,
+                        * don't update index
+                        */
+                       slot->val = tuple;
+                       /*SetSlotContents(slot, tuple); */
+                       if (ExecQual((List*)indexPred[i], econtext) == false)
+                            continue;
 #endif /* OMIT_PARTIAL_INDEX */         
-                }
-                FormIndexDatum(indexNatts[i],
+                    }
+                    FormIndexDatum(indexNatts[i],
                                (AttrNumber *)&(pgIndexP[i]->indkey[0]),
                                tuple,
                                tupDesc,
@@ -644,12 +670,17 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
                                idatum,
                                index_nulls,
                                finfoP[i]);
-                indexRes = index_insert(index_rels[i], idatum, index_nulls,
+                    indexRes = index_insert(index_rels[i], idatum, index_nulls,
                                         &(tuple->t_ctid), rel);
-                if (indexRes) pfree(indexRes);
+                    if (indexRes) pfree(indexRes);
+               }
             }
+           /* AFTER ROW INSERT Triggers */
+           if ( rel->trigdesc && 
+                   rel->trigdesc->n_after_row[TRIGGER_ACTION_INSERT] > 0 )
+               ExecARInsertTriggers (rel, tuple);
         }
-            
+        
         if (binary) pfree(string);
             
         for (i = 0; i < attr_count; i++) {
index a4b5647e02a7d1ac8773aa5c07bed1c931be956e..2c07e49f21e7adb25be34eb07173c053f905ab5e 100644 (file)
@@ -5,13 +5,24 @@
  *
  *-------------------------------------------------------------------------
  */
+#include 
 #include "postgres.h"
 
 #include "nodes/parsenodes.h"
 #include "commands/trigger.h"
+#include "catalog/catname.h"
+#include "catalog/indexing.h"
+#include "catalog/pg_proc.h"
+#include "catalog/pg_language.h"
 #include "catalog/pg_trigger.h"
+#include "access/genam.h"
+#include "access/heapam.h"
+#include "storage/bufmgr.h"
 #include "utils/builtins.h"
 
+void RelationBuildTriggers (Relation relation);
+void FreeTriggerDesc (Relation relation);
+
 void
 CreateTrigger (CreateTrigStmt *stmt)
 {
@@ -25,3 +36,248 @@ DropTrigger (DropTrigStmt *stmt)
 
     return;
 }
+
+void
+RelationBuildTriggers (Relation relation)
+{
+    TriggerDesc *trigdesc = (TriggerDesc *) palloc (sizeof (TriggerDesc));
+    int ntrigs = relation->rd_rel->reltriggers;
+    Trigger *triggers = NULL;
+    Trigger *build;
+    Relation tgrel;
+    Form_pg_trigger pg_trigger;
+    Relation irel;
+    ScanKeyData skey;
+    HeapTuple tuple;
+    IndexScanDesc sd;
+    RetrieveIndexResult indexRes;
+    Buffer buffer;
+    ItemPointer iptr;
+    struct varlena *val;
+    bool isnull;
+    int found;
+    
+    memset (trigdesc, 0, sizeof (TriggerDesc));
+    
+    ScanKeyEntryInitialize(&skey,
+              (bits16)0x0,
+              (AttrNumber)1,
+              (RegProcedure)ObjectIdEqualRegProcedure,
+              ObjectIdGetDatum(relation->rd_id));
+    
+    tgrel = heap_openr(TriggerRelationName);
+    irel = index_openr(TriggerRelidIndex);
+    sd = index_beginscan(irel, false, 1, &skey);
+    
+    for (found = 0; ; )
+    {
+   indexRes = index_getnext(sd, ForwardScanDirection);
+   if (!indexRes)
+       break;
+       
+   iptr = &indexRes->heap_iptr;
+   tuple = heap_fetch(tgrel, NowTimeQual, iptr, &buffer);
+   pfree(indexRes);
+       if (!HeapTupleIsValid(tuple))
+           continue;
+       if ( found == ntrigs )
+           elog (WARN, "RelationBuildTriggers: unexpected record found for rel %.*s",
+                       NAMEDATALEN, relation->rd_rel->relname.data);
+       
+       pg_trigger = (Form_pg_trigger) GETSTRUCT (tuple);
+       
+       if ( triggers == NULL )
+           triggers = (Trigger *) palloc (sizeof (Trigger));
+       else
+           triggers = (Trigger *) repalloc (triggers, (found + 1) * sizeof (Trigger));
+       build = &(triggers[found]);
+       
+       build->tgname = nameout (&(pg_trigger->tgname));
+       build->tgfunc = nameout (&(pg_trigger->tgfunc));
+       build->tglang = pg_trigger->tglang;
+       if ( build->tglang != ClanguageId )
+           elog (WARN, "RelationBuildTriggers: unsupported language %u for trigger %s of rel %.*s",
+               build->tglang, build->tgname, NAMEDATALEN, relation->rd_rel->relname.data);
+       build->tgtype = pg_trigger->tgtype;
+       build->tgnargs = pg_trigger->tgnargs;
+       memcpy (build->tgattr, &(pg_trigger->tgattr), 8 * sizeof (int16));
+       val = (struct varlena*) fastgetattr (tuple, 
+                               Anum_pg_trigger_tgtext,
+                               tgrel->rd_att, &isnull);
+       if ( isnull )
+           elog (WARN, "RelationBuildTriggers: tgtext IS NULL for rel %.*s",
+                   NAMEDATALEN, relation->rd_rel->relname.data);
+       build->tgtext = byteaout (val);
+       val = (struct varlena*) fastgetattr (tuple, 
+                               Anum_pg_trigger_tgargs,
+                               tgrel->rd_att, &isnull);
+       if ( isnull )
+           elog (WARN, "RelationBuildTriggers: tgargs IS NULL for rel %.*s",
+                   NAMEDATALEN, relation->rd_rel->relname.data);
+       if (  build->tgnargs > 0 )
+       {
+           char *p;
+           int i;
+           
+           val = (struct varlena*) fastgetattr (tuple, 
+                               Anum_pg_trigger_tgargs,
+                               tgrel->rd_att, &isnull);
+           if ( isnull )
+               elog (WARN, "RelationBuildTriggers: tgargs IS NULL for rel %.*s",
+                   NAMEDATALEN, relation->rd_rel->relname.data);
+           p = (char *) VARDATA (val);
+           build->tgargs = (char**) palloc (build->tgnargs * sizeof (char*));
+           for (i = 0; i < build->tgnargs; i++)
+           {
+               build->tgargs[i] = (char*) palloc (strlen (p) + 1);
+               strcpy (build->tgargs[i], p);
+               p += strlen (p) + 1;
+           }
+       }
+       val = (struct varlena*) fastgetattr (tuple, 
+                               Anum_pg_trigger_tgwhen,
+                               tgrel->rd_att, &isnull);
+       if ( !isnull )
+           build->tgwhen = textout (val);
+       else
+           build->tgwhen = NULL;
+       
+       found++;
+   ReleaseBuffer(buffer);
+    }
+    
+    if ( found < ntrigs )
+       elog (WARN, "RelationBuildTriggers: %d record not found for rel %.*s",
+                       ntrigs - found,
+                       NAMEDATALEN, relation->rd_rel->relname.data);
+    
+    index_endscan (sd);
+    pfree (sd);
+    index_close (irel);
+    heap_close (tgrel);
+    
+    /* Build trigdesc */
+    trigdesc->triggers = triggers;
+    for (found = 0; found < ntrigs; found++)
+    {
+       uint16 *n;
+       Trigger ***t, ***tp;
+       
+       build = &(triggers[found]);
+       
+       if ( TRIGGER_FOR_ROW (build->tgtype) )  /* Is ROW/STATEMENT trigger */
+       {
+           if ( TRIGGER_FOR_BEFORE (build->tgtype) )
+           {
+               n = trigdesc->n_before_row;
+               t = trigdesc->tg_before_row;
+           }
+           else
+           {
+               n = trigdesc->n_after_row;
+               t = trigdesc->tg_after_row;
+           }
+       }
+       else                    /* STATEMENT (NI) */
+       {
+           if ( TRIGGER_FOR_BEFORE (build->tgtype) )
+           {
+               n = trigdesc->n_before_statement;
+               t = trigdesc->tg_before_statement;
+           }
+           else
+           {
+               n = trigdesc->n_after_statement;
+               t = trigdesc->tg_after_statement;
+           }
+       }
+       
+       if ( TRIGGER_FOR_INSERT (build->tgtype) )
+       {
+           tp = &(t[TRIGGER_ACTION_INSERT]);
+           if ( *tp == NULL )
+               *tp = (Trigger **) palloc (sizeof (Trigger *));
+           else
+               *tp = (Trigger **) repalloc (*tp, (n[TRIGGER_ACTION_INSERT] + 1) * 
+                               sizeof (Trigger *));
+           (*tp)[n[TRIGGER_ACTION_INSERT]] = build;
+           (n[TRIGGER_ACTION_INSERT])++;
+       }
+       
+       if ( TRIGGER_FOR_DELETE (build->tgtype) )
+       {
+           tp = &(t[TRIGGER_ACTION_DELETE]);
+           if ( *tp == NULL )
+               *tp = (Trigger **) palloc (sizeof (Trigger *));
+           else
+               *tp = (Trigger **) repalloc (*tp, (n[TRIGGER_ACTION_DELETE] + 1) * 
+                               sizeof (Trigger *));
+           (*tp)[n[TRIGGER_ACTION_DELETE]] = build;
+           (n[TRIGGER_ACTION_DELETE])++;
+       }
+       
+       if ( TRIGGER_FOR_UPDATE (build->tgtype) )
+       {
+           tp = &(t[TRIGGER_ACTION_UPDATE]);
+           if ( *tp == NULL )
+               *tp = (Trigger **) palloc (sizeof (Trigger *));
+           else
+               *tp = (Trigger **) repalloc (*tp, (n[TRIGGER_ACTION_UPDATE] + 1) * 
+                               sizeof (Trigger *));
+           (*tp)[n[TRIGGER_ACTION_UPDATE]] = build;
+           (n[TRIGGER_ACTION_UPDATE])++;
+       }
+    }
+       
+    relation->trigdesc = trigdesc;
+    
+}
+
+void 
+FreeTriggerDesc (Relation relation)
+{
+    
+    return;
+}
+
+HeapTuple 
+ExecBRInsertTriggers (Relation rel, HeapTuple tuple)
+{
+    
+    return (tuple);
+}
+
+void
+ExecARInsertTriggers (Relation rel, HeapTuple tuple)
+{
+    
+    return;
+}
+
+bool
+ExecBRDeleteTriggers (Relation rel, ItemPointer tupleid)
+{
+    
+    return (true);
+}
+
+void
+ExecARDeleteTriggers (Relation rel, ItemPointer tupleid)
+{
+    
+    return;
+}
+
+HeapTuple
+ExecBRUpdateTriggers (Relation rel, ItemPointer tupleid, HeapTuple tuple)
+{
+    
+    return (tuple);
+}
+
+void
+ExecARUpdateTriggers (Relation rel, ItemPointer tupleid, HeapTuple tuple)
+{
+    
+    return;
+}