]> granicus.if.org Git - postgresql/commitdiff
READ COMMITTED isolevel is implemented and is default now.
authorVadim B. Mikheev <vadim4o@yahoo.com>
Fri, 29 Jan 1999 09:23:17 +0000 (09:23 +0000)
committerVadim B. Mikheev <vadim4o@yahoo.com>
Fri, 29 Jan 1999 09:23:17 +0000 (09:23 +0000)
12 files changed:
src/backend/access/heap/heapam.c
src/backend/access/nbtree/nbtinsert.c
src/backend/access/transam/xact.c
src/backend/commands/trigger.c
src/backend/executor/execMain.c
src/backend/executor/nodeIndexscan.c
src/backend/executor/nodeSeqscan.c
src/backend/nodes/copyfuncs.c
src/backend/parser/gram.c
src/backend/utils/time/tqual.c
src/include/nodes/execnodes.h
src/include/utils/tqual.h

index 8ffd9d4192275242437fdf588ec8467c50bb0418..bfd57b0cff02a733772142cbac65bc86b0357da2 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.39 1998/12/15 12:45:13 vadim Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.40 1999/01/29 09:22:51 vadim Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -1373,6 +1373,7 @@ l3:
        if (result != HeapTupleMayBeUpdated)
        {
                Assert(result == HeapTupleSelfUpdated || result == HeapTupleUpdated);
+               tuple->t_self = tuple->t_data->t_ctid;
                LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
                return result;
        }
index 54ea9ed8abd0e76230e5d650ae5e04403306ef70..01109f564fd15f4422b2347ee2da9e60e63774f7 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.32 1998/12/15 12:45:20 vadim Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.33 1999/01/29 09:22:52 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -134,6 +134,7 @@ l1:
                                         * If this tuple is being updated by other transaction
                                         * then we have to wait for its commit/abort.
                                         */
+                                       ReleaseBuffer(buffer);
                                        if (TransactionIdIsValid(xwait))
                                        {
                                                if (nbuf != InvalidBuffer)
index e6adf442fe6a81558be677c5ab1f63178be88159..ec95398131a7bb78c2e53a48c302a6b387ef5838 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.28 1998/12/18 09:10:18 vadim Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.29 1999/01/29 09:22:53 vadim Exp $
  *
  * NOTES
  *             Transaction aborts can now occur two ways:
@@ -194,7 +194,7 @@ TransactionStateData CurrentTransactionStateData = {
 TransactionState CurrentTransactionState =
 &CurrentTransactionStateData;
 
-int    DefaultXactIsoLevel = XACT_SERIALIZABLE;
+int    DefaultXactIsoLevel = XACT_READ_COMMITTED;
 int    XactIsoLevel;
 
 /* ----------------
index 41bd59ca0d4b30fae3b0fc63b2b700a10d48f34b..a5e27227cf2ca63321bd237f47ab5e98e256bd31 100644 (file)
@@ -28,6 +28,7 @@
 #include "utils/inval.h"
 #include "utils/builtins.h"
 #include "utils/syscache.h"
+#include "executor/executor.h"
 
 #ifndef NO_SECURITY
 #include "miscadmin.h"
@@ -790,6 +791,8 @@ ExecARUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
        return;
 }
 
+extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti, ItemPointer tid);
+
 static HeapTuple
 GetTupleForTrigger(EState *estate, ItemPointer tid, bool before)
 {
@@ -806,6 +809,7 @@ GetTupleForTrigger(EState *estate, ItemPointer tid, bool before)
                 *      mark tuple for update
                 */
                tuple.t_self = *tid;
+ltrmark:;
                test = heap_mark4update(relation, &tuple, &buffer);
                switch (test)
                {
@@ -820,8 +824,23 @@ GetTupleForTrigger(EState *estate, ItemPointer tid, bool before)
                                ReleaseBuffer(buffer);
                                if (XactIsoLevel == XACT_SERIALIZABLE)
                                        elog(ERROR, "Can't serialize access due to concurrent update");
-                               else
-                                       elog(ERROR, "Isolation level %u is not supported", XactIsoLevel);
+                               else if (!(ItemPointerEquals(&(tuple.t_self), tid)))
+                               {
+                                       TupleTableSlot *slot = EvalPlanQual(estate, 
+                                               estate->es_result_relation_info->ri_RangeTableIndex, 
+                                               &(tuple.t_self));
+
+                                       if (!(TupIsNull(slot)))
+                                       {
+                                               *tid = tuple.t_self;
+                                               goto ltrmark;
+                                       }
+                               }
+                               /* 
+                                * if tuple was deleted or PlanQual failed
+                                * for updated tuple - we have not process
+                                * this tuple!
+                                */
                                return(NULL);
 
                        default:
index a48bbe82bae87ce113086b5e9eddcb846d6c8cf2..7623649a4fae76970b76ab223151974e65066b57 100644 (file)
@@ -26,7 +26,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.65 1999/01/27 16:48:20 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.66 1999/01/29 09:22:57 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -64,10 +64,9 @@ static TupleDesc InitPlan(CmdType operation, Query *parseTree,
                 Plan *plan, EState *estate);
 static void EndPlan(Plan *plan, EState *estate);
 static TupleTableSlot *ExecutePlan(EState *estate, Plan *plan,
-                       Query *parseTree, CmdType operation,
-                       int numberTuples, ScanDirection direction,
-                       DestReceiver *destfunc);
-static void ExecRetrieve(TupleTableSlot *slot,
+                       CmdType operation, int numberTuples, ScanDirection direction,
+                       void (*printfunc) ());
+static void ExecRetrieve(TupleTableSlot *slot, 
                                                 DestReceiver *destfunc,
                                                 EState *estate);
 static void ExecAppend(TupleTableSlot *slot, ItemPointer tupleid,
@@ -75,7 +74,11 @@ static void ExecAppend(TupleTableSlot *slot, ItemPointer tupleid,
 static void ExecDelete(TupleTableSlot *slot, ItemPointer tupleid,
                   EState *estate);
 static void ExecReplace(TupleTableSlot *slot, ItemPointer tupleid,
-                       EState *estate, Query *parseTree);
+                       EState *estate);
+
+TupleTableSlot *EvalPlanQual(EState *estate, Index rti, ItemPointer tid);
+static TupleTableSlot *EvalPlanQualNext(EState *estate);
+
 
 /* end of local decls */
 
@@ -168,11 +171,10 @@ TupleTableSlot *
 ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
 {
        CmdType         operation;
-       Query      *parseTree;
        Plan       *plan;
        TupleTableSlot *result;
        CommandDest dest;
-       DestReceiver   *destfunc;
+       void            (*destination) ();
 
        /******************
         *      sanity checks
@@ -186,42 +188,30 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
         ******************
         */
        operation = queryDesc->operation;
-       parseTree = queryDesc->parsetree;
        plan = queryDesc->plantree;
        dest = queryDesc->dest;
-       destfunc = DestToFunction(dest);
+       destination = (void (*) ()) 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)
        {
 
                case EXEC_RUN:
                        result = ExecutePlan(estate,
                                                                 plan,
-                                                                parseTree,
                                                                 operation,
                                                                 ALL_TUPLES,
                                                                 ForwardScanDirection,
-                                                                destfunc);
+                                                                destination);
                        break;
                case EXEC_FOR:
                        result = ExecutePlan(estate,
                                                                 plan,
-                                                                parseTree,
                                                                 operation,
                                                                 count,
                                                                 ForwardScanDirection,
-                                                                destfunc);
+                                                                destination);
                        break;
 
                        /******************
@@ -231,11 +221,10 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
                case EXEC_BACK:
                        result = ExecutePlan(estate,
                                                                 plan,
-                                                                parseTree,
                                                                 operation,
                                                                 count,
                                                                 BackwardScanDirection,
-                                                                destfunc);
+                                                                destination);
                        break;
 
                        /******************
@@ -246,11 +235,10 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
                case EXEC_RETONE:
                        result = ExecutePlan(estate,
                                                                 plan,
-                                                                parseTree,
                                                                 operation,
                                                                 ONE_TUPLE,
                                                                 ForwardScanDirection,
-                                                                destfunc);
+                                                                destination);
                        break;
                default:
                        result = NULL;
@@ -258,8 +246,6 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
                        break;
        }
 
-       (*destfunc->cleanup) (destfunc);
-
        return result;
 }
 
@@ -413,9 +399,18 @@ ExecCheckPerms(CmdType operation,
 typedef struct execRowMark
 {
        Relation        relation;
+       Index           rti;
        char            resname[32];
 } execRowMark;
 
+typedef struct evalPlanQual
+{
+       Plan                               *plan;
+       Index                                   rti;
+       EState                                  estate;
+       struct evalPlanQual        *free;
+} evalPlanQual;
+
 /* ----------------------------------------------------------------
  *             InitPlan
  *
@@ -426,13 +421,12 @@ typedef struct execRowMark
 static TupleDesc
 InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
 {
-       List       *rangeTable;
-       int                     resultRelation;
-       Relation        intoRelationDesc;
-
-       TupleDesc       tupType;
-       List       *targetList;
-       int                     len;
+       List               *rangeTable;
+       int                             resultRelation;
+       Relation                intoRelationDesc;
+       TupleDesc               tupType;
+       List               *targetList;
+       int                             len;
 
        /******************
         *      get information from query descriptor
@@ -537,6 +531,7 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
                                continue;
                        erm = (execRowMark*) palloc(sizeof(execRowMark));
                        erm->relation = relation;
+                       erm->rti = rm->rti;
                        sprintf(erm->resname, "ctid%u", rm->rti);
                        estate->es_rowMark = lappend(estate->es_rowMark, erm);
                }
@@ -669,6 +664,11 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
 
        estate->es_into_relation_descriptor = intoRelationDesc;
 
+       estate->es_origPlan = plan;
+       estate->es_evalPlanQual = NULL;
+       estate->es_evTuple = NULL;
+       estate->es_useEvalPlan = false;
+
        return tupType;
 }
 
@@ -753,11 +753,10 @@ EndPlan(Plan *plan, EState *estate)
 static TupleTableSlot *
 ExecutePlan(EState *estate,
                        Plan *plan,
-                       Query *parseTree,
                        CmdType operation,
                        int numberTuples,
                        ScanDirection direction,
-                       DestReceiver* destfunc)
+                       void (*printfunc) ())
 {
        JunkFilter *junkfilter;
 
@@ -794,7 +793,15 @@ ExecutePlan(EState *estate,
                 ******************
                 */
                /* at the top level, the parent of a plan (2nd arg) is itself */
-               slot = ExecProcNode(plan, plan);
+lnext:;
+               if (estate->es_useEvalPlan)
+               {
+                       slot = EvalPlanQualNext(estate);
+                       if (TupIsNull(slot))
+                               slot = ExecProcNode(plan, plan);
+               }
+               else
+                       slot = ExecProcNode(plan, plan);
 
                /******************
                 *      if the tuple is null, then we assume
@@ -821,8 +828,6 @@ ExecutePlan(EState *estate,
                if ((junkfilter = estate->es_junkFilter) != (JunkFilter *) NULL)
                {
                        Datum           datum;
-
-/*                     NameData        attrName; */
                        HeapTuple       newTuple;
                        bool            isNull;
 
@@ -853,8 +858,10 @@ ExecutePlan(EState *estate,
                                execRowMark        *erm;
                                Buffer                  buffer;
                                HeapTupleData   tuple;
+                               TupleTableSlot *newSlot;
                                int                             test;
 
+lmark:;
                                foreach (l, estate->es_rowMark)
                                {
                                        erm = lfirst(l);
@@ -879,10 +886,27 @@ ExecutePlan(EState *estate,
 
                                                case HeapTupleUpdated:
                                                        if (XactIsoLevel == XACT_SERIALIZABLE)
+                                                       {
                                                                elog(ERROR, "Can't serialize access due to concurrent update");
-                                                       else
-                                                               elog(ERROR, "Isolation level %u is not supported", XactIsoLevel);
-                                                       return(NULL);
+                                                               return(NULL);
+                                                       }
+                                                       else if (!(ItemPointerEquals(&(tuple.t_self), 
+                                                                               (ItemPointer)DatumGetPointer(datum))))
+                                                       {
+                                                               newSlot = EvalPlanQual(estate, erm->rti, &(tuple.t_self));
+                                                               if (!(TupIsNull(newSlot)))
+                                                               {
+                                                                       slot = newSlot;
+                                                                       estate->es_useEvalPlan = true;
+                                                                       goto lmark;
+                                                               }
+                                                       }
+                                                       /* 
+                                                        * if tuple was deleted or PlanQual failed
+                                                        * for updated tuple - we have not return
+                                                        * this tuple!
+                                                        */
+                                                       goto lnext;
 
                                                default:
                                                        elog(ERROR, "Unknown status %u from heap_mark4update", test);
@@ -917,7 +941,7 @@ ExecutePlan(EState *estate,
                {
                        case CMD_SELECT:
                                ExecRetrieve(slot,              /* slot containing tuple */
-                                                        destfunc,      /* destination's tuple-receiver obj */
+                                                        printfunc, /* print function */
                                                         estate);       /* */
                                result = slot;
                                break;
@@ -933,7 +957,7 @@ ExecutePlan(EState *estate,
                                break;
 
                        case CMD_UPDATE:
-                               ExecReplace(slot, tupleid, estate, parseTree);
+                               ExecReplace(slot, tupleid, estate);
                                result = NULL;
                                break;
 
@@ -973,7 +997,7 @@ ExecutePlan(EState *estate,
  */
 static void
 ExecRetrieve(TupleTableSlot *slot,
-                        DestReceiver *destfunc,
+                        void (*printfunc) (),
                         EState *estate)
 {
        HeapTuple       tuple;
@@ -1000,7 +1024,7 @@ ExecRetrieve(TupleTableSlot *slot,
         *      send the tuple to the front end (or the screen)
         ******************
         */
-       (*destfunc->receiveTuple) (tuple, attrtype, destfunc);
+       (*printfunc) (tuple, attrtype);
        IncrRetrieved();
        (estate->es_processed)++;
 }
@@ -1115,7 +1139,8 @@ ExecDelete(TupleTableSlot *slot,
 {
        RelationInfo       *resultRelationInfo;
        Relation                        resultRelationDesc;
-       ItemPointerData         ctid;
+       ItemPointerData         ctid,
+                                               oldtid;
        int                                     result;
 
        /******************
@@ -1140,6 +1165,7 @@ ExecDelete(TupleTableSlot *slot,
        /*
         *      delete the tuple
         */
+ldelete:;
        result = heap_delete(resultRelationDesc, tupleid, &ctid);
        switch (result)
        {
@@ -1152,8 +1178,18 @@ ExecDelete(TupleTableSlot *slot,
                case HeapTupleUpdated:
                        if (XactIsoLevel == XACT_SERIALIZABLE)
                                elog(ERROR, "Can't serialize access due to concurrent update");
-                       else
-                               elog(ERROR, "Isolation level %u is not supported", XactIsoLevel);
+                       else if (!(ItemPointerEquals(tupleid, &ctid)))
+                       {
+                               TupleTableSlot *slot = EvalPlanQual(estate, 
+                                               resultRelationInfo->ri_RangeTableIndex, &ctid);
+
+                               if (!TupIsNull(slot))
+                               {
+                                       tupleid = &oldtid;
+                                       *tupleid = ctid;
+                                       goto ldelete;
+                               }
+                       }
                        return;
 
                default:
@@ -1197,13 +1233,13 @@ ExecDelete(TupleTableSlot *slot,
 static void
 ExecReplace(TupleTableSlot *slot,
                        ItemPointer tupleid,
-                       EState *estate,
-                       Query *parseTree)
+                       EState *estate)
 {
        HeapTuple                       tuple;
        RelationInfo       *resultRelationInfo;
        Relation                        resultRelationDesc;
-       ItemPointerData         ctid;
+       ItemPointerData         ctid,
+                                               oldtid;
        int                                     result;
        int                                     numIndices;
 
@@ -1270,6 +1306,7 @@ ExecReplace(TupleTableSlot *slot,
        /*
         *      replace the heap tuple
         */
+lreplace:;
        result = heap_replace(resultRelationDesc, tupleid, tuple, &ctid);
        switch (result)
        {
@@ -1282,8 +1319,18 @@ ExecReplace(TupleTableSlot *slot,
                case HeapTupleUpdated:
                        if (XactIsoLevel == XACT_SERIALIZABLE)
                                elog(ERROR, "Can't serialize access due to concurrent update");
-                       else
-                               elog(ERROR, "Isolation level %u is not supported", XactIsoLevel);
+                       else if (!(ItemPointerEquals(tupleid, &ctid)))
+                       {
+                               TupleTableSlot *slot = EvalPlanQual(estate, 
+                                               resultRelationInfo->ri_RangeTableIndex, &ctid);
+
+                               if (!TupIsNull(slot))
+                               {
+                                       tupleid = &oldtid;
+                                       *tupleid = ctid;
+                                       goto lreplace;
+                               }
+                       }
                        return;
 
                default:
@@ -1480,3 +1527,256 @@ ExecConstraints(char *caller, Relation rel, HeapTuple tuple)
 
        return;
 }
+
+TupleTableSlot*
+EvalPlanQual(EState *estate, Index rti, ItemPointer tid)
+{
+       evalPlanQual       *epq = (evalPlanQual*) estate->es_evalPlanQual;
+       evalPlanQual       *oldepq;
+       EState                     *epqstate = NULL;
+       Relation                        relation;
+       Buffer                          buffer;
+       HeapTupleData           tuple;
+       bool                            endNode = true;
+
+       Assert(rti != 0);
+
+       if (epq != NULL && epq->rti == 0)
+       {
+               Assert(!(estate->es_useEvalPlan) && 
+                               epq->estate.es_evalPlanQual == NULL);
+               epq->rti = rti;
+               endNode = false;
+       }
+
+       /*
+        * If this is request for another RTE - Ra, - then we have to check
+        * wasn't PlanQual requested for Ra already and if so then Ra' row 
+        * was updated again and we have to re-start old execution for Ra 
+        * and forget all what we done after Ra was suspended. Cool? -:))
+        */
+       if (epq != NULL && epq->rti != rti && 
+               epq->estate.es_evTuple[rti - 1] != NULL)
+       {
+               do
+               {
+                       /* pop previous PlanQual from the stack */
+                       epqstate = &(epq->estate);
+                       oldepq = (evalPlanQual*) epqstate->es_evalPlanQual;
+                       Assert(oldepq->rti != 0);
+                       /* stop execution */
+                       ExecEndNode(epq->plan, epq->plan);
+                       pfree(epqstate->es_evTuple[epq->rti - 1]);
+                       epqstate->es_evTuple[epq->rti - 1] = NULL;
+                       /* push current PQ to freePQ stack */
+                       oldepq->free = epq;
+                       epq = oldepq;
+               } while (epq->rti != rti);
+               estate->es_evalPlanQual = (Pointer) epq;
+       }
+
+       /* 
+        * If we are requested for another RTE then we have to suspend
+        * execution of current PlanQual and start execution for new one.
+        */
+       if (epq == NULL || epq->rti != rti)
+       {
+               /* try to reuse plan used previously */
+               evalPlanQual   *newepq = (epq != NULL) ? epq->free : NULL;
+
+               if (newepq == NULL)
+               {
+                       newepq = (evalPlanQual*) palloc(sizeof(evalPlanQual));
+                       /* Init EState */
+                       epqstate = &(newepq->estate);
+                       memset(epqstate, 0, sizeof(EState));
+                       epqstate->type = T_EState; 
+                       epqstate->es_direction = ForwardScanDirection;
+                       epqstate->es_snapshot = estate->es_snapshot;
+                       epqstate->es_range_table = estate->es_range_table;
+                       epqstate->es_param_list_info = estate->es_param_list_info;
+                       if (estate->es_origPlan->nParamExec > 0)
+                               epqstate->es_param_exec_vals = (ParamExecData *)
+                                                       palloc(estate->es_origPlan->nParamExec * 
+                                                                       sizeof(ParamExecData));
+                       epqstate->es_tupleTable = 
+                               ExecCreateTupleTable(estate->es_tupleTable->size);
+                       epqstate->es_refcount = estate->es_refcount;
+                       /* ... rest */
+                       newepq->plan = copyObject(estate->es_origPlan);
+                       newepq->free = NULL;
+                       if (epq == NULL)
+                       {
+                               epqstate->es_evTuple = (HeapTuple*) 
+                                       palloc(length(estate->es_range_table) * sizeof(HeapTuple));
+                               memset(epqstate->es_evTuple, 0, 
+                                       length(estate->es_range_table) * sizeof(HeapTuple));
+                               epqstate->es_evTupleNull = (bool*) 
+                                       palloc(length(estate->es_range_table) * sizeof(bool));
+                               memset(epqstate->es_evTupleNull, false, 
+                                       length(estate->es_range_table) * sizeof(bool));
+                       }
+                       else
+                       {
+                               epqstate->es_evTuple = epq->estate.es_evTuple;
+                               epqstate->es_evTupleNull = epq->estate.es_evTupleNull;
+                       }
+               }
+               else
+               {
+                       epqstate = &(newepq->estate);
+               }
+               /* push current PQ to the stack */
+               epqstate->es_evalPlanQual = (Pointer) epq;
+               estate->es_evalPlanQual = (Pointer) epq = newepq;
+               epq->rti = rti;
+               endNode = false;
+       }
+
+       epqstate = &(epq->estate);
+
+       /*
+        * Ok - we're requested for the same RTE (-:)).
+        * I'm not sure about ability to use ExecReScan instead of
+        * ExecInitNode, so...
+        */
+       if (endNode)
+               ExecEndNode(epq->plan, epq->plan);
+
+       /* free old RTE' tuple */
+       if (epqstate->es_evTuple[epq->rti - 1] != NULL)
+       {
+               pfree(epqstate->es_evTuple[epq->rti - 1]);
+               epqstate->es_evTuple[epq->rti - 1] = NULL;
+       }
+
+       /* ** fetch tid tuple ** */
+       if (estate->es_result_relation_info != NULL && 
+               estate->es_result_relation_info->ri_RangeTableIndex == rti)
+               relation = estate->es_result_relation_info->ri_RelationDesc;
+       else
+       {
+               List   *l;
+
+               foreach (l, estate->es_rowMark)
+               {
+                       if (((execRowMark*) lfirst(l))->rti == rti)
+                               break;
+               }
+               relation = ((execRowMark*) lfirst(l))->relation;
+       }
+       tuple.t_self = *tid;
+       for ( ; ; )
+       {
+               heap_fetch(relation, SnapshotDirty, &tuple, &buffer);
+               if (tuple.t_data != NULL)
+               {
+                       TransactionId xwait = SnapshotDirty->xmax;
+
+                       if (TransactionIdIsValid(SnapshotDirty->xmin))
+                               elog(ERROR, "EvalPlanQual: t_xmin is uncommitted ?!");
+                       /*
+                        * If tuple is being updated by other transaction then 
+                        * we have to wait for its commit/abort.
+                        */
+                       if (TransactionIdIsValid(xwait))
+                       {
+                               ReleaseBuffer(buffer);
+                               XactLockTableWait(xwait);
+                               continue;
+                       }
+                       /*
+                        * Nice! We got tuple - now copy it.
+                        */
+                       epqstate->es_evTuple[epq->rti - 1] = heap_copytuple(&tuple);
+                       epqstate->es_evTupleNull[epq->rti - 1] = false;
+                       ReleaseBuffer(buffer);
+                       break;
+               }
+               /*
+                * Ops! Invalid tuple. Have to check is it updated or deleted.
+                * Note that it's possible to get invalid SnapshotDirty->tid
+                * if tuple updated by this transaction. Have we to check this ?
+                */
+               if (ItemPointerIsValid(&(SnapshotDirty->tid)) && 
+                       !(ItemPointerEquals(&(tuple.t_self), &(SnapshotDirty->tid))))
+               {
+                       tuple.t_self = SnapshotDirty->tid;      /* updated ... */
+                       continue;
+               }
+               /*
+                * Deleted or updated by this transaction. Do not
+                * (re-)start execution of this PQ. Continue previous PQ.
+                */
+               oldepq = (evalPlanQual*) epqstate->es_evalPlanQual;
+               if (oldepq != NULL)
+               {
+                       Assert(oldepq->rti != 0);
+                       /* push current PQ to freePQ stack */
+                       oldepq->free = epq;
+                       epq = oldepq;
+                       epqstate = &(epq->estate);
+                       estate->es_evalPlanQual = (Pointer) epq;
+               }
+               else
+               {                                                                       /* this is the first (oldest) PQ
+                       epq->rti = 0;                                    * - mark as free and 
+                       estate->es_useEvalPlan = false;  * continue Query execution
+                       return (NULL);                                   */
+               }
+       }
+
+       if (estate->es_origPlan->nParamExec > 0)
+               memset(epqstate->es_param_exec_vals, 0, 
+                               estate->es_origPlan->nParamExec * sizeof(ParamExecData));
+       ExecInitNode(epq->plan, epqstate, NULL);
+
+       /*
+        * For UPDATE/DELETE we have to return tid of actual row
+        * we're executing PQ for.
+        */
+       *tid = tuple.t_self;
+
+       return (EvalPlanQualNext(estate));
+}
+
+static TupleTableSlot* 
+EvalPlanQualNext(EState *estate)
+{
+       evalPlanQual       *epq = (evalPlanQual*) estate->es_evalPlanQual;
+       EState                     *epqstate = &(epq->estate);
+       evalPlanQual       *oldepq;
+       TupleTableSlot     *slot;
+
+       Assert(epq->rti != 0);
+
+lpqnext:;
+       slot = ExecProcNode(epq->plan, epq->plan);
+
+       /*
+        * No more tuples for this PQ. Continue previous one.
+        */
+       if (TupIsNull(slot))
+       {
+               ExecEndNode(epq->plan, epq->plan);
+               pfree(epqstate->es_evTuple[epq->rti - 1]);
+               epqstate->es_evTuple[epq->rti - 1] = NULL;
+               /* pop old PQ from the stack */
+               oldepq = (evalPlanQual*) epqstate->es_evalPlanQual;
+               if (oldepq == (evalPlanQual*) NULL)
+               {                                                                       /* this is the first (oldest) */
+                       epq->rti = 0;                                   /* PQ - mark as free and      */
+                       estate->es_useEvalPlan = false; /* continue Query execution   */
+                       return (NULL);
+               }
+               Assert(oldepq->rti != 0);
+               /* push current PQ to freePQ stack */
+               oldepq->free = epq;
+               epq = oldepq;
+               epqstate = &(epq->estate);
+               estate->es_evalPlanQual = (Pointer) epq;
+               goto lpqnext;
+       }
+
+       return (slot);
+}
index b4a610b7f88e7bdee901ad2d1f0fac7ceca9f23b..97469e9929b25e170b25c5e66e0160e82171790c 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.29 1998/11/27 19:52:03 vadim Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.30 1999/01/29 09:22:58 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -109,6 +109,40 @@ IndexNext(IndexScan *node)
        heapRelation = scanstate->css_currentRelation;
        numIndices = indexstate->iss_NumIndices;
        slot = scanstate->css_ScanTupleSlot;
+
+       /*
+        * Check if we are evaluating PlanQual for tuple of this relation.
+        * Additional checking is not good, but no other way for now.
+        * We could introduce new nodes for this case and handle
+        * IndexScan --> NewNode switching in Init/ReScan plan...
+        */
+       if (estate->es_evTuple != NULL && 
+               estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
+       {
+               int             iptr;
+
+               slot->ttc_buffer = InvalidBuffer;
+               slot->ttc_shouldFree = false;
+               if (estate->es_evTupleNull[node->scan.scanrelid - 1])
+               {
+                       slot->val = NULL;       /* must not free tuple! */
+                       return (slot);
+               }
+               slot->val = estate->es_evTuple[node->scan.scanrelid - 1];
+               for (iptr = 0; iptr < numIndices; iptr++)
+               {
+                       scanstate->cstate.cs_ExprContext->ecxt_scantuple = slot;
+                       if (ExecQual(nth(iptr, node->indxqualorig),
+                                                scanstate->cstate.cs_ExprContext))
+                               break;
+               }
+               if (iptr == numIndices) /* would not be returned by indices */
+                       slot->val = NULL;
+               /* Flag for the next call that no more tuples */
+               estate->es_evTupleNull[node->scan.scanrelid - 1] = true;
+               return (slot);
+       }
+
        tuple = &(indexstate->iss_htup);
 
        /* ----------------
@@ -262,6 +296,14 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
        numScanKeys = indexstate->iss_NumScanKeys;
        indexstate->iss_IndexPtr = 0;
 
+       /* If this is re-scanning of PlanQual ... */
+       if (estate->es_evTuple != NULL && 
+               estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
+       {
+               estate->es_evTupleNull[node->scan.scanrelid - 1] = false;
+               return;
+       }
+
        /* it's possible in subselects */
        if (exprCtxt == NULL)
                exprCtxt = node->scan.scanstate->cstate.cs_ExprContext;
index a9da3e769d274dd711c939f9eccb557b5034245d..b09b94d82a5d88a124f43219f9fca0c253976d5e 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.15 1998/09/25 13:38:32 thomas Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.16 1999/01/29 09:22:58 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -64,6 +64,34 @@ SeqNext(SeqScan *node)
        scanstate = node->scanstate;
        scandesc = scanstate->css_currentScanDesc;
        direction = estate->es_direction;
+       slot = scanstate->css_ScanTupleSlot;
+
+       /*
+        * Check if we are evaluating PlanQual for tuple of this relation.
+        * Additional checking is not good, but no other way for now.
+        * We could introduce new nodes for this case and handle
+        * SeqScan --> NewNode switching in Init/ReScan plan...
+        */
+       if (estate->es_evTuple != NULL && 
+               estate->es_evTuple[node->scanrelid - 1] != NULL)
+       {
+               slot->ttc_buffer = InvalidBuffer;
+               slot->ttc_shouldFree = false;
+               if (estate->es_evTupleNull[node->scanrelid - 1])
+               {
+                       slot->val = NULL;       /* must not free tuple! */
+                       return (slot);
+               }
+               slot->val = estate->es_evTuple[node->scanrelid - 1];
+               /*
+                * Note that unlike IndexScan, SeqScan never use keys
+                * in heap_beginscan (and this is very bad) - so, here
+                * we have not check are keys ok or not.
+                */
+               /* Flag for the next call that no more tuples */
+               estate->es_evTupleNull[node->scanrelid - 1] = true;
+               return (slot);
+       }
 
        /* ----------------
         *      get the next tuple from the access methods
@@ -79,7 +107,6 @@ SeqNext(SeqScan *node)
         *      be pfree()'d.
         * ----------------
         */
-       slot = scanstate->css_ScanTupleSlot;
 
        slot = ExecStoreTuple(tuple,/* tuple to store */
                                                  slot, /* slot to store in */
@@ -374,9 +401,15 @@ ExecSeqReScan(SeqScan *node, ExprContext *exprCtxt, Plan *parent)
                outerPlan = outerPlan((Plan *) node);
                ExecReScan(outerPlan, exprCtxt, parent);
        }
-       else
+       else    /* otherwise, we are scanning a relation */
        {
-               /* otherwise, we are scanning a relation */
+               /* If this is re-scanning of PlanQual ... */
+               if (estate->es_evTuple != NULL && 
+                       estate->es_evTuple[node->scanrelid - 1] != NULL)
+               {
+                       estate->es_evTupleNull[node->scanrelid - 1] = false;
+                       return;
+               }
                rel = scanstate->css_currentRelation;
                scan = scanstate->css_currentScanDesc;
                direction = estate->es_direction;
index a008de72be201c55dd807ec3989b7b7e20430370..7eb2dd34a337441107f344c2281af73d3b7052a6 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.55 1999/01/25 18:02:14 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.56 1999/01/29 09:22:59 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -83,7 +83,6 @@ CopyPlanFields(Plan *from, Plan *newnode)
        newnode->plan_size = from->plan_size;
        newnode->plan_width = from->plan_width;
        newnode->plan_tupperpage = from->plan_tupperpage;
-       newnode->state = from->state;
        newnode->targetlist = copyObject(from->targetlist);
        newnode->qual = copyObject(from->qual);
        newnode->lefttree = copyObject(from->lefttree);
@@ -138,7 +137,6 @@ _copyResult(Result *from)
         * ----------------
         */
        Node_Copy(from, newnode, resconstantqual);
-       Node_Copy(from, newnode, resstate);
 
        return newnode;
 }
@@ -166,7 +164,6 @@ _copyAppend(Append *from)
        Node_Copy(from, newnode, unionrtables);
        newnode->inheritrelid = from->inheritrelid;
        Node_Copy(from, newnode, inheritrtable);
-       Node_Copy(from, newnode, appendstate);
 
        return newnode;
 }
@@ -183,7 +180,6 @@ static void
 CopyScanFields(Scan *from, Scan *newnode)
 {
        newnode->scanrelid = from->scanrelid;
-       Node_Copy(from, newnode, scanstate);
        return;
 }
 
@@ -248,7 +244,6 @@ _copyIndexScan(IndexScan *from)
        newnode->indxid = listCopy(from->indxid);
        Node_Copy(from, newnode, indxqual);
        Node_Copy(from, newnode, indxqualorig);
-       Node_Copy(from, newnode, indxstate);
 
        return newnode;
 }
@@ -304,12 +299,6 @@ _copyNestLoop(NestLoop *from)
        CopyPlanFields((Plan *) from, (Plan *) newnode);
        CopyJoinFields((Join *) from, (Join *) newnode);
 
-       /* ----------------
-        *      copy remainder of node
-        * ----------------
-        */
-       Node_Copy(from, newnode, nlstate);
-
        return newnode;
 }
 
@@ -346,8 +335,6 @@ _copyMergeJoin(MergeJoin *from)
        newnode->mergeleftorder[0] = from->mergeleftorder[0];
        newnode->mergeleftorder[1] = 0;
 
-       Node_Copy(from, newnode, mergestate);
-
        return newnode;
 }
 
@@ -375,12 +362,9 @@ _copyHashJoin(HashJoin *from)
 
        newnode->hashjoinop = from->hashjoinop;
 
-       Node_Copy(from, newnode, hashjoinstate);
-
-       newnode->hashjointable = from->hashjointable;
+       /* both are unused !.. */
        newnode->hashjointablekey = from->hashjointablekey;
        newnode->hashjointablesize = from->hashjointablesize;
-       newnode->hashdone = from->hashdone;
 
        return newnode;
 }
@@ -437,12 +421,6 @@ _copyMaterial(Material *from)
        CopyPlanFields((Plan *) from, (Plan *) newnode);
        CopyTempFields((Temp *) from, (Temp *) newnode);
 
-       /* ----------------
-        *      copy remainder of node
-        * ----------------
-        */
-       Node_Copy(from, newnode, matstate);
-
        return newnode;
 }
 
@@ -463,14 +441,6 @@ _copySort(Sort *from)
        CopyPlanFields((Plan *) from, (Plan *) newnode);
        CopyTempFields((Temp *) from, (Temp *) newnode);
 
-       /* ----------------
-        *      copy remainder of node
-        * ----------------
-        */
-       Node_Copy(from, newnode, sortstate);
-       Node_Copy(from, newnode, psortstate);
-       newnode->cleaned = from->cleaned;
-
        return newnode;
 }
 
@@ -490,7 +460,6 @@ _copyGroup(Group *from)
        newnode->numCols = from->numCols;
        newnode->grpColIdx = palloc(from->numCols * sizeof(AttrNumber));
        memcpy(newnode->grpColIdx, from->grpColIdx, from->numCols * sizeof(AttrNumber));
-       Node_Copy(from, newnode, grpstate);
 
        return newnode;
 }
@@ -507,7 +476,6 @@ _copyAgg(Agg *from)
        CopyPlanFields((Plan *) from, (Plan *) newnode);
 
        newnode->aggs = get_agg_tlist_references(newnode);
-       Node_Copy(from, newnode, aggstate);
 
        return newnode;
 }
@@ -553,7 +521,6 @@ _copyUnique(Unique *from)
        else
                newnode->uniqueAttr = NULL;
        newnode->uniqueAttrNum = from->uniqueAttrNum;
-       Node_Copy(from, newnode, uniquestate);
 
        return newnode;
 }
@@ -579,9 +546,8 @@ _copyHash(Hash *from)
         * ----------------
         */
        Node_Copy(from, newnode, hashkey);
-       Node_Copy(from, newnode, hashstate);
 
-       newnode->hashtable = from->hashtable;
+       /* both are unused !.. */
        newnode->hashtablekey = from->hashtablekey;
        newnode->hashtablesize = from->hashtablesize;
 
@@ -599,7 +565,6 @@ _copySubPlan(SubPlan *from)
        newnode->setParam = listCopy(from->setParam);
        newnode->parParam = listCopy(from->parParam);
        Node_Copy(from, newnode, sublink);
-       newnode->shutdown = from->shutdown;
 
        return newnode;
 }
@@ -1901,7 +1866,7 @@ copyObject(void *from)
                        }
                        break;
                default:
-                       elog(NOTICE, "copyObject: don't know how to copy %d", nodeTag(from));
+                       elog(ERROR, "copyObject: don't know how to copy %d", nodeTag(from));
                        retval = from;
                        break;
        }
index 186b0213e5cd562bce8f1d8f7156ba81c8de12e2..30d6011cc4420cd847ca39da93999646173dc011 100644 (file)
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/Attic/gram.c,v 2.64 1999/01/26 23:32:04 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/Attic/gram.c,v 2.65 1999/01/29 09:23:02 vadim Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -4791,7 +4791,7 @@ static const short yycheck[] = {     3,
     -1,    -1,    -1,    -1,    -1,    -1,    -1,   214
 };
 /* -*-C-*-  Note some compilers choke on comments on `#line' lines.  */
-#line 3 "/usr/local/bison/bison.simple"
+#line 3 "/usr/share/misc/bison.simple"
 
 /* Skeleton output parser for bison,
    Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc.
@@ -4984,7 +4984,7 @@ __yy_memcpy (char *to, char *from, int count)
 #endif
 #endif
 \f
-#line 196 "/usr/local/bison/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 *.
@@ -11088,7 +11088,7 @@ case 960:
     break;}
 }
    /* the action file gets copied in in place of this dollarsign */
-#line 498 "/usr/local/bison/bison.simple"
+#line 498 "/usr/share/misc/bison.simple"
 \f
   yyvsp -= yylen;
   yyssp -= yylen;
index ecef85787c309db7118a9f5974992ef79be243c5..360027b1eb400777df5f91e8d2b2c6edd3acb81f 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/time/tqual.c,v 1.23 1998/12/18 09:10:39 vadim Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/time/tqual.c,v 1.24 1999/01/29 09:23:12 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -368,6 +368,7 @@ bool
 HeapTupleSatisfiesDirty(HeapTupleHeader tuple)
 {
        SnapshotDirty->xmin = SnapshotDirty->xmax = InvalidTransactionId;
+       ItemPointerSetInvalid(&(SnapshotDirty->tid));
 
        if (AMI_OVERRIDE)
                return true;
@@ -413,6 +414,7 @@ HeapTupleSatisfiesDirty(HeapTupleHeader tuple)
        {
                if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
                        return true;
+               SnapshotDirty->tid = tuple->t_ctid;
                return false;                                                   /* updated by other */
        }
 
@@ -437,6 +439,7 @@ HeapTupleSatisfiesDirty(HeapTupleHeader tuple)
        if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
                return true;
 
+       SnapshotDirty->tid = tuple->t_ctid;
        return false;                                                           /* updated by other */
 }
 
index 37de50b014788b2a5fb8062fd1d5c2fb153cceda..d9cdd2509defa4f8623aee8be11344f39e0363aa 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: execnodes.h,v 1.21 1999/01/25 12:01:19 vadim Exp $
+ * $Id: execnodes.h,v 1.22 1999/01/29 09:23:13 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -194,21 +194,27 @@ typedef struct JunkFilter
  */
 typedef struct EState
 {
-       NodeTag         type;
-       ScanDirection es_direction;
-       Snapshot        es_snapshot;
-       List       *es_range_table;
-       RelationInfo *es_result_relation_info;
-       Relation        es_into_relation_descriptor;
-       ParamListInfo es_param_list_info;
-       ParamExecData *es_param_exec_vals;      /* this is for subselects */
-       int                     es_BaseId;
-       TupleTable      es_tupleTable;
-       JunkFilter *es_junkFilter;
-       int                *es_refcount;
-       uint32          es_processed;   /* # of tuples processed */
-       Oid                     es_lastoid;             /* last oid processed (by INSERT) */
-       List       *es_rowMark;         /* not good place, but there is no other */
+       NodeTag                 type;
+       ScanDirection   es_direction;
+       Snapshot                es_snapshot;
+       List               *es_range_table;
+       RelationInfo   *es_result_relation_info;
+       Relation                es_into_relation_descriptor;
+       ParamListInfo   es_param_list_info;
+       ParamExecData  *es_param_exec_vals;     /* this is for subselects */
+       int                             es_BaseId;
+       TupleTable              es_tupleTable;
+       JunkFilter         *es_junkFilter;
+       int                        *es_refcount;
+       uint32                  es_processed;   /* # of tuples processed */
+       Oid                             es_lastoid;             /* last oid processed (by INSERT) */
+       List               *es_rowMark;         /* not good place, but there is no other */
+       /* Below is to re-evaluate plan qual in READ COMMITTED mode */
+       struct Plan        *es_origPlan;
+       Pointer                 es_evalPlanQual;
+       bool               *es_evTupleNull;
+       HeapTuple          *es_evTuple;
+       bool                    es_useEvalPlan;
 } EState;
 
 /* ----------------
index 17ff6f3d90f2e4c119fae30a56f5815b17f65a6f..7f811388e2244061fa9794a26203d4bbd066463e 100644 (file)
@@ -7,7 +7,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: tqual.h,v 1.18 1998/12/18 09:09:55 vadim Exp $
+ * $Id: tqual.h,v 1.19 1999/01/29 09:23:17 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -22,6 +22,7 @@ typedef struct SnapshotData
        TransactionId   xmax;                   /* XID >= xmax are invisible to me */
        uint32                  xcnt;                   /* # of xact below */
        TransactionId  *xip;                    /* array of xacts in progress */
+       ItemPointerData tid;                    /* required for Dirty snapshot -:( */
 }                      SnapshotData;
 
 typedef SnapshotData *Snapshot;