Hope that execMain.c good merged.
authorVadim B. Mikheev
Fri, 29 Jan 1999 11:56:01 +0000 (11:56 +0000)
committerVadim B. Mikheev
Fri, 29 Jan 1999 11:56:01 +0000 (11:56 +0000)
Fix for BEFORE ROW UPDATE triggers: result tuple may be different
(due to concurrent update) from one initially produced by top level plan.

src/backend/commands/trigger.c
src/backend/executor/execMain.c
src/pl/plpgsql/src/gram.c

index a5e27227cf2ca63321bd237f47ab5e98e256bd31..aac9f2599f52cecd69f71739af94bb848f0bcc9f 100644 (file)
@@ -42,7 +42,7 @@ void      FreeTriggerDesc(Relation relation);
 
 static void DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger);
 static HeapTuple GetTupleForTrigger(EState *estate, ItemPointer tid,
-                  bool before);
+                  TupleTableSlot **newSlot);
 
 extern GlobalMemory CacheCxt;
 
@@ -664,9 +664,10 @@ ExecBRDeleteTriggers(EState *estate, ItemPointer tupleid)
    Trigger       **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_DELETE];
    HeapTuple       trigtuple;
    HeapTuple       newtuple = NULL;
+   TupleTableSlot *newSlot;
    int             i;
 
-   trigtuple = GetTupleForTrigger(estate, tupleid, true);
+   trigtuple = GetTupleForTrigger(estate, tupleid, &newSlot);
    if (trigtuple == NULL)
        return false;
 
@@ -701,7 +702,7 @@ ExecARDeleteTriggers(EState *estate, ItemPointer tupleid)
    HeapTuple   trigtuple;
    int         i;
 
-   trigtuple = GetTupleForTrigger(estate, tupleid, false);
+   trigtuple = GetTupleForTrigger(estate, tupleid, NULL);
    Assert(trigtuple != NULL);
 
    SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData));
@@ -732,12 +733,20 @@ ExecBRUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
    HeapTuple       trigtuple;
    HeapTuple       oldtuple;
    HeapTuple       intuple = newtuple;
+   TupleTableSlot *newSlot;
    int             i;
 
-   trigtuple = GetTupleForTrigger(estate, tupleid, true);
+   trigtuple = GetTupleForTrigger(estate, tupleid, &newSlot);
    if (trigtuple == NULL)
        return NULL;
 
+   /*
+    * In READ COMMITTED isolevel it's possible that newtuple
+    * was changed due to concurrent update.
+    */
+   if (newSlot != NULL)
+       intuple = newtuple = ExecRemoveJunk(estate->es_junkFilter, newSlot);
+
    SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData));
    SaveTriggerData->tg_event =
        TRIGGER_EVENT_UPDATE | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE;
@@ -770,7 +779,7 @@ ExecARUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
    HeapTuple   trigtuple;
    int         i;
 
-   trigtuple = GetTupleForTrigger(estate, tupleid, false);
+   trigtuple = GetTupleForTrigger(estate, tupleid, NULL);
    Assert(trigtuple != NULL);
 
    SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData));
@@ -794,20 +803,21 @@ ExecARUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
 extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti, ItemPointer tid);
 
 static HeapTuple
-GetTupleForTrigger(EState *estate, ItemPointer tid, bool before)
+GetTupleForTrigger(EState *estate, ItemPointer tid, TupleTableSlot **newSlot)
 {
    Relation        relation = estate->es_result_relation_info->ri_RelationDesc;
    HeapTupleData   tuple;
    HeapTuple       result;
    Buffer          buffer;
 
-   if (before)
+   if (newSlot != NULL)
    {
        int     test;
 
        /*
         *  mark tuple for update
         */
+       *newSlot = NULL;
        tuple.t_self = *tid;
 ltrmark:;
        test = heap_mark4update(relation, &tuple, &buffer);
@@ -826,13 +836,14 @@ ltrmark:;
                    elog(ERROR, "Can't serialize access due to concurrent update");
                else if (!(ItemPointerEquals(&(tuple.t_self), tid)))
                {
-                   TupleTableSlot *slot = EvalPlanQual(estate, 
+                   TupleTableSlot *epqslot = EvalPlanQual(estate, 
                        estate->es_result_relation_info->ri_RangeTableIndex, 
                        &(tuple.t_self));
 
-                   if (!(TupIsNull(slot)))
+                   if (!(TupIsNull(epqslot)))
                    {
                        *tid = tuple.t_self;
+                       *newSlot = epqslot;
                        goto ltrmark;
                    }
                }
index ba4d09eaa38ff5439e9c6e0a93090aa29c70cb70..f074ce951fd7cf4e65496529a9b0e840764737a2 100644 (file)
@@ -26,7 +26,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.67 1999/01/29 10:15:09 vadim Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.68 1999/01/29 11:56:00 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -66,7 +66,7 @@ static void EndPlan(Plan *plan, EState *estate);
 static TupleTableSlot *ExecutePlan(EState *estate, Plan *plan,
            CmdType operation, int numberTuples, ScanDirection direction,
            DestReceiver *destfunc);
-static void ExecRetrieve(TupleTableSlot *slot, 
+static void ExecRetrieve(TupleTableSlot *slot,
                         DestReceiver *destfunc,
                         EState *estate);
 static void ExecAppend(TupleTableSlot *slot, ItemPointer tupleid,
@@ -170,11 +170,11 @@ ExecutorStart(QueryDesc *queryDesc, EState *estate)
 TupleTableSlot *
 ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
 {
-   CmdType     operation;
-   Plan       *plan;
+   CmdType         operation;
+   Plan           *plan;
    TupleTableSlot *result;
-   CommandDest dest;
-   void        (*destination) ();
+   CommandDest     dest;
+   DestReceiver   *destfunc;
 
    /******************
     *  sanity checks
@@ -190,10 +190,19 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
    operation = queryDesc->operation;
    plan = queryDesc->plantree;
    dest = queryDesc->dest;
-   destination = (void (*) ()) DestToFunction(dest);
+   destfunc = DestToFunction(dest);
    estate->es_processed = 0;
    estate->es_lastoid = InvalidOid;
 
+   /******************
+    *  FIXME: the dest setup function ought to be handed the tuple desc
+    *  for the tuples to be output, but I'm not quite sure how to get that
+    *  info at this point.  For now, passing NULL is OK because no existing
+    *  dest setup function actually uses the pointer.
+    ******************
+    */
+   (*destfunc->setup) (destfunc, (TupleDesc) NULL);
+
    switch (feature)
    {
 
@@ -203,7 +212,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
                                 operation,
                                 ALL_TUPLES,
                                 ForwardScanDirection,
-                                destination);
+                                destfunc);
            break;
        case EXEC_FOR:
            result = ExecutePlan(estate,
@@ -211,7 +220,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
                                 operation,
                                 count,
                                 ForwardScanDirection,
-                                destination);
+                                destfunc);
            break;
 
            /******************
@@ -224,7 +233,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
                                 operation,
                                 count,
                                 BackwardScanDirection,
-                                destination);
+                                destfunc);
            break;
 
            /******************
@@ -238,7 +247,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
                                 operation,
                                 ONE_TUPLE,
                                 ForwardScanDirection,
-                                destination);
+                                destfunc);
            break;
        default:
            result = NULL;
@@ -246,6 +255,8 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
            break;
    }
 
+   (*destfunc->cleanup) (destfunc);
+
    return result;
 }
 
@@ -756,7 +767,7 @@ ExecutePlan(EState *estate,
            CmdType operation,
            int numberTuples,
            ScanDirection direction,
-           DestReceiver *destfunc)
+           DestReceiverdestfunc)
 {
    JunkFilter *junkfilter;
 
@@ -941,7 +952,7 @@ lmark:;
        {
            case CMD_SELECT:
                ExecRetrieve(slot,      /* slot containing tuple */
-                            destfunc,  /* print function */
+                            destfunc,  /* destination's tuple-receiver obj */
                             estate);   /* */
                result = slot;
                break;
@@ -1024,7 +1035,7 @@ ExecRetrieve(TupleTableSlot *slot,
     *  send the tuple to the front end (or the screen)
     ******************
     */
-   (*printfunc) (tuple, attrtype);
+   (*destfunc->receiveTuple) (tuple, attrtype, destfunc);
    IncrRetrieved();
    (estate->es_processed)++;
 }
index 2d4ef46a1b14382f66b533452f43a648f69b72e6..2ca9936c32e927c7522a72e484e16f90563b69f4 100644 (file)
@@ -65,7 +65,7 @@
  *           procedural language
  *
  * IDENTIFICATION
- *    $Header: /cvsroot/pgsql/src/pl/plpgsql/src/Attic/gram.c,v 1.3 1999/01/28 11:50:41 wieck Exp $
+ *    $Header: /cvsroot/pgsql/src/pl/plpgsql/src/Attic/gram.c,v 1.4 1999/01/29 11:56:01 vadim Exp $
  *
  *    This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -414,7 +414,7 @@ static const short yycheck[] = {    21,
    152,    62
 };
 /* -*-C-*-  Note some compilers choke on comments on `#line' lines.  */
-#line 3 "/usr/share/bison.simple"
+#line 3 "/usr/share/misc/bison.simple"
 
 /* Skeleton output parser for bison,
    Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc.
@@ -467,16 +467,6 @@ void *alloca ();
 #endif /* not GNU C.  */
 #endif /* alloca not defined.  */
 
-#ifdef __cplusplus
-extern "C" {
-  void yyerror(char *);
-  int yylex();
-};
-#else
-  extern void yyerror(char *);
-  extern int yylex();
-#endif
-
 /* This is the parser code that is written into each bison parser
   when the %semantic_parser declaration is not specified in the grammar.
   It was written by Richard Stallman by simplifying the hairy parser
@@ -573,13 +563,9 @@ int yydebug;           /*  nonzero means print parse trace */
 #define YYMAXDEPTH 10000
 #endif
 
-#ifndef YYPARSE_RETURN_TYPE
-#define YYPARSE_RETURN_TYPE int
-#endif
-
 /* Prevent warning if -Wstrict-prototypes.  */
 #ifdef __GNUC__
-YYPARSE_RETURN_TYPE yyparse (void);
+int yyparse (void);
 #endif
 \f
 #if __GNUC__ > 1       /* GNU C and GNU C++ define this.  */
@@ -621,7 +607,7 @@ __yy_memcpy (char *to, char *from, int count)
 #endif
 #endif
 \f
-#line 196 "/usr/share/bison.simple"
+#line 196 "/usr/share/misc/bison.simple"
 
 /* The user can define YYPARSE_PARAM as the name of an argument to be passed
    into yyparse.  The argument should have type void *.
@@ -642,7 +628,7 @@ __yy_memcpy (char *to, char *from, int count)
 #define YYPARSE_PARAM_DECL
 #endif /* not YYPARSE_PARAM */
 
-YYPARSE_RETURN_TYPE
+int
 yyparse(YYPARSE_PARAM_ARG)
      YYPARSE_PARAM_DECL
 {
@@ -1905,7 +1891,7 @@ case 105:
     break;}
 }
    /* the action file gets copied in in place of this dollarsign */
-#line 498 "/usr/share/bison.simple"
+#line 498 "/usr/share/misc/bison.simple"
 \f
   yyvsp -= yylen;
   yyssp -= yylen;