]> granicus.if.org Git - postgresql/commitdiff
Tid access method feature from Hiroshi Inoue, Inoue@tpf.co.jp
authorBruce Momjian <bruce@momjian.us>
Tue, 23 Nov 1999 20:07:06 +0000 (20:07 +0000)
committerBruce Momjian <bruce@momjian.us>
Tue, 23 Nov 1999 20:07:06 +0000 (20:07 +0000)
28 files changed:
src/backend/access/heap/heapam.c
src/backend/commands/explain.c
src/backend/executor/Makefile
src/backend/executor/execAmi.c
src/backend/executor/execProcnode.c
src/backend/executor/execTuples.c
src/backend/executor/nodeTidscan.c [new file with mode: 0644]
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/freefuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/print.c
src/backend/nodes/readfuncs.c
src/backend/optimizer/path/Makefile
src/backend/optimizer/path/allpaths.c
src/backend/optimizer/path/costsize.c
src/backend/optimizer/path/tidpath.c [new file with mode: 0644]
src/backend/optimizer/plan/createplan.c
src/backend/optimizer/plan/setrefs.c
src/backend/optimizer/plan/subselect.c
src/backend/optimizer/util/pathnode.c
src/include/nodes/execnodes.h
src/include/nodes/nodes.h
src/include/nodes/plannodes.h
src/include/nodes/relation.h
src/include/optimizer/cost.h
src/include/optimizer/pathnode.h
src/include/optimizer/paths.h

index a26216c0269f996710a9b1fb380082444aaf7eaa..3636993387528df91849d117ed59d66f11cc9c7e 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.58 1999/11/07 23:07:52 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.59 1999/11/23 20:06:47 momjian Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -1062,7 +1062,13 @@ heap_fetch(Relation relation,
         * ----------------
         */
 
-       Assert(ItemIdIsUsed(lp));
+       if (!ItemIdIsUsed(lp))
+       {
+               ReleaseBuffer(buffer);
+               *userbuf = InvalidBuffer;
+               tuple->t_data = NULL;
+               return;
+       }
 
        tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp);
        tuple->t_len = ItemIdGetLength(lp);
index 99e4e45dd5c7f0cdc3458c0efd2df0810b6c1793..95856194fff6a34f7341d34be228f3d64c7c7597 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Copyright (c) 1994-5, Regents of the University of California
  *
- *       $Id: explain.c,v 1.49 1999/11/07 23:08:02 momjian Exp $
+ *       $Id: explain.c,v 1.50 1999/11/23 20:06:48 momjian Exp $
  *
  */
 
@@ -196,6 +196,9 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
                case T_Hash:
                        pname = "Hash";
                        break;
+               case T_TidScan:
+                       pname = "Tid Scan";
+                       break;
                default:
                        pname = "???";
                        break;
@@ -234,6 +237,20 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
                                appendStringInfo(str, stringStringInfo(rte->refname));
                        }
                        break;
+               case T_TidScan:
+                       if (((TidScan *) plan)->scan.scanrelid > 0)
+                       {
+                               RangeTblEntry *rte = nth(((TidScan *) plan)->scan.scanrelid - 1, es->rtable);
+
+                               appendStringInfo(str, " on ");
+                               if (strcmp(rte->refname, rte->relname) != 0)
+                               {
+                                       appendStringInfo(str, "%s ",
+                                                                        stringStringInfo(rte->relname));
+                               }
+                               appendStringInfo(str, stringStringInfo(rte->refname));
+                       }
+                       break;
                default:
                        break;
        }
index 4f8c1341c8312baa2c5b48dd4d6e4048549cb9d0..ea0b20e9b489a8c3ebf09656c175581bb187c2e4 100644 (file)
@@ -4,7 +4,7 @@
 #    Makefile for executor
 #
 # IDENTIFICATION
-#    $Header: /cvsroot/pgsql/src/backend/executor/Makefile,v 1.8 1999/03/23 16:50:46 momjian Exp $
+#    $Header: /cvsroot/pgsql/src/backend/executor/Makefile,v 1.9 1999/11/23 20:06:49 momjian Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -18,7 +18,8 @@ OBJS = execAmi.o execFlatten.o execJunk.o execMain.o \
        execUtils.o functions.o nodeAppend.o nodeAgg.o nodeHash.o \
        nodeHashjoin.o nodeIndexscan.o nodeMaterial.o nodeMergejoin.o \
        nodeNestloop.o nodeResult.o nodeSeqscan.o nodeSort.o \
-       nodeUnique.o nodeGroup.o spi.o nodeSubplan.o
+       nodeUnique.o nodeGroup.o spi.o nodeSubplan.o \
+       nodeTidscan.o
 
 all: SUBSYS.o
 
index dc69953e21095a3ebf055be8dc74af67a6e00039..0d7801bcd8a4a4e25d3273b80b7e85d174266943 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- *     $Id: execAmi.c,v 1.43 1999/11/04 08:00:57 inoue Exp $
+ *     $Id: execAmi.c,v 1.44 1999/11/23 20:06:50 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -40,6 +40,7 @@
 #include "executor/nodeHash.h"
 #include "executor/nodeHashjoin.h"
 #include "executor/nodeIndexscan.h"
+#include "executor/nodeTidscan.h"
 #include "executor/nodeMaterial.h"
 #include "executor/nodeMergejoin.h"
 #include "executor/nodeNestloop.h"
@@ -217,6 +218,10 @@ ExecCloseR(Plan *node)
                        state = &(((Agg *) node)->aggstate->csstate);
                        break;
 
+               case T_TidScan:
+                       state = ((TidScan *) node)->scan.scanstate;
+                       break;
+
                default:
                        elog(DEBUG, "ExecCloseR: not a scan, material, or sort node!");
                        return;
@@ -367,6 +372,10 @@ ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent)
                        ExecReScanAppend((Append *) node, exprCtxt, parent);
                        break;
 
+               case T_TidScan:
+                       ExecTidReScan((TidScan *) node, exprCtxt, parent);
+                       break;
+
                default:
                        elog(ERROR, "ExecReScan: node type %u not supported", nodeTag(node));
                        return;
@@ -413,7 +422,7 @@ ExecMarkPos(Plan *node)
 {
        switch (nodeTag(node))
        {
-                       case T_SeqScan:
+               case T_SeqScan:
                        ExecSeqMarkPos((SeqScan *) node);
                        break;
 
@@ -425,6 +434,10 @@ ExecMarkPos(Plan *node)
                        ExecSortMarkPos((Sort *) node);
                        break;
 
+               case T_TidScan:
+                       ExecTidMarkPos((TidScan *) node);
+                       break;
+
                default:
                        elog(DEBUG, "ExecMarkPos: node type %u not supported", nodeTag(node));
                        break;
index 1b6d2bd84217b4cd2a8b8afaf9a514fc49fd3cb3..d4527be23badd1f291bd7daf3bbc1753f13c7eef 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.15 1999/07/16 04:58:46 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.16 1999/11/23 20:06:51 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -81,6 +81,7 @@
 #include "executor/nodeHash.h"
 #include "executor/nodeHashjoin.h"
 #include "executor/nodeIndexscan.h"
+#include "executor/nodeTidscan.h"
 #include "executor/nodeMaterial.h"
 #include "executor/nodeMergejoin.h"
 #include "executor/nodeNestloop.h"
@@ -195,6 +196,10 @@ ExecInitNode(Plan *node, EState *estate, Plan *parent)
                        result = ExecInitHashJoin((HashJoin *) node, estate, parent);
                        break;
 
+               case T_TidScan:
+                       result = ExecInitTidScan((TidScan *) node, estate, parent);
+                       break;
+
                default:
                        elog(ERROR, "ExecInitNode: node %d unsupported", nodeTag(node));
                        result = FALSE;
@@ -310,6 +315,10 @@ ExecProcNode(Plan *node, Plan *parent)
                        result = ExecHashJoin((HashJoin *) node);
                        break;
 
+               case T_TidScan:
+                       result = ExecTidScan((TidScan *) node);
+                       break;
+
                default:
                        elog(ERROR, "ExecProcNode: node %d unsupported", nodeTag(node));
                        result = NULL;
@@ -381,6 +390,9 @@ ExecCountSlotsNode(Plan *node)
                case T_HashJoin:
                        return ExecCountSlotsHashJoin((HashJoin *) node);
 
+               case T_TidScan:
+                       return ExecCountSlotsTidScan((TidScan *) node);
+
                default:
                        elog(ERROR, "ExecCountSlotsNode: node not yet supported: %d",
                                 nodeTag(node));
@@ -497,6 +509,10 @@ ExecEndNode(Plan *node, Plan *parent)
                        ExecEndHashJoin((HashJoin *) node);
                        break;
 
+               case T_TidScan:
+                       ExecEndTidScan((TidScan *) node);
+                       break;
+
                default:
                        elog(ERROR, "ExecEndNode: node %d unsupported", nodeTag(node));
                        break;
index 53edd555ad8f546b798a77de925a8a54eb21d332..f1f6d15f1b00b5a5cf1b204818eae60bd5aedfa5 100644 (file)
@@ -14,7 +14,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.31 1999/11/07 23:08:06 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.32 1999/11/23 20:06:51 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -771,6 +771,13 @@ NodeGetResultTupleSlot(Plan *node)
                        }
                        break;
 
+               case T_TidScan:
+                       {
+                               CommonScanState *scanstate = ((IndexScan *) node)->scan.scanstate;
+                               slot = scanstate->cstate.cs_ResultTupleSlot;
+                       }
+                       break;
+
                default:
                        /* ----------------
                         *        should never get here
diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c
new file mode 100644 (file)
index 0000000..8d6481b
--- /dev/null
@@ -0,0 +1,550 @@
+/*-------------------------------------------------------------------------
+ *
+ * nodeTidscan.c
+ *       Routines to support direct tid scans of relations
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.1 1999/11/23 20:06:51 momjian Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+/*
+ * INTERFACE ROUTINES
+ *
+ *             ExecTidScan             scans a relation using tids
+ *             ExecInitTidScan         creates and initializes state info.
+ *             ExecTidReScan           rescans the tid relation.
+ *             ExecEndTidScan          releases all storage.
+ *             ExecTidMarkPos          marks scan position.
+ *             ExecTidRestrPos         restores scan position.
+ *
+ */
+#include "postgres.h"
+
+#include "executor/executor.h"
+#include "executor/execdebug.h"
+#include "executor/nodeTidscan.h"
+#include "optimizer/clauses.h" /* for get_op, get_leftop, get_rightop */
+#include "access/heapam.h"
+#include "parser/parsetree.h"
+
+static int TidListCreate(List *, ExprContext *, ItemPointer *);
+static TupleTableSlot *TidNext(TidScan *node);
+
+static int
+TidListCreate(List *evalList, ExprContext *econtext, ItemPointer *tidList)
+{
+       List            *lst;
+       ItemPointer     itemptr;
+       bool            isNull;
+       int             numTids = 0;
+
+       foreach (lst, evalList)
+       {
+               itemptr = (ItemPointer)ExecEvalExpr(lfirst(lst), econtext,
+                               &isNull, (bool *)0);
+               if (itemptr && ItemPointerIsValid(itemptr))
+               {
+                       tidList[numTids] = itemptr;
+                       numTids++;
+               }
+       }
+       return numTids;
+}
+
+/* ----------------------------------------------------------------
+ *             TidNext
+ *
+ *             Retrieve a tuple from the TidScan node's currentRelation
+ *             using the tids in the TidScanState information.
+ *
+ * ----------------------------------------------------------------
+ */
+static TupleTableSlot *
+TidNext(TidScan *node)
+{
+       EState          *estate;
+       CommonScanState *scanstate;
+       TidScanState    *tidstate;
+       ScanDirection   direction;
+       Snapshot        snapshot;
+       Relation        heapRelation;
+       HeapTuple       tuple;
+       TupleTableSlot  *slot;
+       Buffer          buffer = InvalidBuffer;
+       int             numTids;
+
+       bool            bBackward;
+       int             tidNumber;
+       ItemPointer     *tidList, itemptr;
+
+       /* ----------------
+        *      extract necessary information from tid scan node
+        * ----------------
+        */
+       estate = node->scan.plan.state;
+       direction = estate->es_direction;
+       snapshot = estate->es_snapshot;
+       scanstate = node->scan.scanstate;
+       tidstate = node->tidstate;
+       heapRelation = scanstate->css_currentRelation;
+       numTids = tidstate->tss_NumTids;
+       tidList = tidstate->tss_TidList;
+       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 TidScan --> NewNode
+        * switching in Init/ReScan plan...
+        */
+       if (estate->es_evTuple != NULL &&
+               estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
+       {
+               int     iptr, numQuals;
+
+               ExecClearTuple(slot);
+               if (estate->es_evTupleNull[node->scan.scanrelid - 1])
+                       return slot;            /* return empty slot */
+               
+               slot->val = estate->es_evTuple[node->scan.scanrelid - 1];
+               slot->ttc_shouldFree = false;
+               /* Flag for the next call that no more tuples */
+               estate->es_evTupleNull[node->scan.scanrelid - 1] = true;
+               return (slot);
+       }
+
+       tuple = &(tidstate->tss_htup);
+
+       /* ----------------
+        *      ok, now that we have what we need, fetch an tid tuple.
+        *      if scanning this tid succeeded then return the
+        *      appropriate heap tuple.. else return NULL.
+        * ----------------
+        */
+       bBackward = ScanDirectionIsBackward(direction);
+       if (bBackward)
+       {
+               tidNumber = numTids - tidstate->tss_TidPtr - 1;
+               if (tidNumber < 0)
+               {
+                       tidNumber = 0;
+                       tidstate->tss_TidPtr = numTids - 1;
+               }
+       }
+       else
+       {
+               if ((tidNumber = tidstate->tss_TidPtr) < 0)
+               {
+                       tidNumber = 0;
+                       tidstate->tss_TidPtr = 0;
+               }
+       }
+       while (tidNumber < numTids)
+       {
+               bool            slot_is_valid = false;
+
+               itemptr = tidList[tidstate->tss_TidPtr];
+               tuple->t_data = NULL;
+               if (itemptr)
+               {
+                       tuple->t_self = *(itemptr);
+                       heap_fetch(heapRelation, snapshot, tuple, &buffer);
+               }
+               if (tuple->t_data != NULL)
+               {
+                       bool            prev_matches = false;
+                       int             prev_tid;
+
+                       /* ----------------
+                        *      store the scanned tuple in the scan tuple slot of
+                        *      the scan state.  Eventually we will only do this and not
+                        *      return a tuple.  Note: we pass 'false' because tuples
+                        *      returned by amgetnext are pointers onto disk pages and
+                        *      were not created with palloc() and so should not be pfree()'d.
+                        * ----------------
+                        */
+                       ExecStoreTuple(tuple,   /* tuple to store */
+                                                  slot,        /* slot to store in */
+                                                  buffer,      /* buffer associated with tuple  */
+                                                  false);      /* don't pfree */
+
+                       /*
+                        * At this point we have an extra pin on the buffer,
+                        * because ExecStoreTuple incremented the pin count.
+                        * Drop our local pin.
+                       */
+                       ReleaseBuffer(buffer);  
+                       /*
+                        * We must check to see if the current tuple would have
+                        * been matched by an earlier tid, so we don't double
+                        * report it. We do this by passing the tuple through
+                        * ExecQual and look for failure with all previous
+                        * qualifications.
+                        */
+                       for (prev_tid = 0; prev_tid < tidstate->tss_TidPtr;
+                                prev_tid++)
+                       {
+                               if (ItemPointerEquals(tidList[prev_tid], &tuple->t_self))
+                               {
+                                       prev_matches = true;
+                                       break;
+                               }
+                       }
+                       if (!prev_matches)
+                               slot_is_valid = true;
+                       else
+                               ExecClearTuple(slot);
+               }
+               else if (BufferIsValid(buffer))
+                       ReleaseBuffer(buffer);
+               tidNumber++;
+               if (bBackward)
+                       tidstate->tss_TidPtr--;
+               else
+                       tidstate->tss_TidPtr++;
+               if (slot_is_valid)
+                       return slot; 
+       }
+       /* ----------------
+        *      if we get here it means the tid scan failed so we
+        *      are at the end of the scan..
+        * ----------------
+        */
+       return ExecClearTuple(slot);
+}
+
+/* ----------------------------------------------------------------
+ *             ExecTidScan(node)
+ *
+ *             Scans the relation using tids and returns
+ *                the next qualifying tuple in the direction specified.
+ *             It calls ExecScan() and passes it the access methods which returns
+ *             the next tuple using the tids.
+ *
+ *             Conditions:
+ *               -- the "cursor" maintained by the AMI is positioned at the tuple
+ *                      returned previously.
+ *
+ *             Initial States:
+ *               -- the relation indicated is opened for scanning so that the
+ *                      "cursor" is positioned before the first qualifying tuple.
+ *               -- tidPtr points to the first tid.
+ *               -- state variable ruleFlag = nil.
+ * ----------------------------------------------------------------
+ */
+TupleTableSlot *
+ExecTidScan(TidScan *node)
+{
+       /* ----------------
+        *      use TidNext as access method
+        * ----------------
+        */
+       return ExecScan(&node->scan, TidNext);
+}
+
+/* ----------------------------------------------------------------
+ *             ExecTidReScan(node)
+ * ----------------------------------------------------------------
+ */
+void
+ExecTidReScan(TidScan *node, ExprContext *exprCtxt, Plan *parent)
+{
+       EState          *estate;
+       TidScanState    *tidstate;
+       Plan            *outerPlan;
+       ItemPointer     *tidList;
+
+       tidstate = node->tidstate;
+       estate = node->scan.plan.state;
+       tidstate->tss_TidPtr = -1;
+       tidList = tidstate->tss_TidList;
+
+       if ((outerPlan = outerPlan((Plan *) node)) != NULL)
+       {
+               /* we are scanning a subplan */
+               outerPlan = outerPlan((Plan *) node);
+               ExecReScan(outerPlan, exprCtxt, parent);
+       }
+       else
+       /* otherwise, we are scanning a relation */
+       {
+               /* 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;
+
+               node->scan.scanstate->cstate.cs_ExprContext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
+               tidstate->tss_NumTids = TidListCreate(node->tideval, exprCtxt, tidList);
+       }
+
+       /* ----------------
+        *      perhaps return something meaningful
+        * ----------------
+        */
+       return;
+}
+
+/* ----------------------------------------------------------------
+ *             ExecEndTidScan
+ *
+ *             Releases any storage allocated through C routines.
+ *             Returns nothing.
+ * ----------------------------------------------------------------
+ */
+void
+ExecEndTidScan(TidScan *node)
+{
+       CommonScanState *scanstate;
+       TidScanState    *tidstate;
+
+       scanstate = node->scan.scanstate;
+       tidstate = node->tidstate;
+       if (tidstate && tidstate->tss_TidList)
+               pfree(tidstate->tss_TidList);
+
+       /* ----------------
+        *      extract information from the node
+        * ----------------
+        */
+
+       /* ----------------
+        *      Free the projection info and the scan attribute info
+        *
+        *      Note: we don't ExecFreeResultType(scanstate)
+        *                because the rule manager depends on the tupType
+        *                returned by ExecMain().  So for now, this
+        *                is freed at end-transaction time.  -cim 6/2/91
+        * ----------------
+        */
+       ExecFreeProjectionInfo(&scanstate->cstate);
+
+       /* ----------------
+        *      close the heap and tid relations
+        * ----------------
+        */
+       ExecCloseR((Plan *) node);
+
+       /* ----------------
+        *      clear out tuple table slots
+        * ----------------
+        */
+       ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot);
+       ExecClearTuple(scanstate->css_ScanTupleSlot);
+/*       ExecClearTuple(scanstate->css_RawTupleSlot); */
+}
+
+/* ----------------------------------------------------------------
+ *             ExecTidMarkPos
+ *
+ *             Marks scan position by marking the current tid.
+ *             Returns nothing.
+ * ----------------------------------------------------------------
+ */
+void
+ExecTidMarkPos(TidScan *node)
+{
+       TidScanState *tidstate;
+
+       tidstate = node->tidstate;
+       tidstate->tss_MarkTidPtr = tidstate->tss_TidPtr;
+}
+
+/* ----------------------------------------------------------------
+ *             ExecTidRestrPos
+ *
+ *             Restores scan position by restoring the current tid.
+ *             Returns nothing.
+ *
+ *             XXX Assumes previously marked scan position belongs to current tid
+ * ----------------------------------------------------------------
+ */
+void
+ExecTidRestrPos(TidScan *node)
+{
+       TidScanState *tidstate;
+
+       tidstate = node->tidstate;
+       tidstate->tss_TidPtr = tidstate->tss_MarkTidPtr;
+}
+
+/* ----------------------------------------------------------------
+ *             ExecInitTidScan
+ *
+ *             Initializes the tid scan's state information, creates
+ *             scan keys, and opens the base and tid relations.
+ *
+ *             Parameters:
+ *               node: TidNode node produced by the planner.
+ *               estate: the execution state initialized in InitPlan.
+ * ----------------------------------------------------------------
+ */
+bool
+ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
+{
+       TidScanState    *tidstate;
+       CommonScanState *scanstate;
+       ItemPointer     *tidList;
+       int             numTids;
+       int             tidPtr;
+       List            *rangeTable;
+       RangeTblEntry   *rtentry;
+       Oid             relid;
+       Oid             reloid;
+
+       Relation        currentRelation;
+       int             baseid;
+
+       List       *execParam = NULL;
+
+       /* ----------------
+        *      assign execution state to node
+        * ----------------
+        */
+       node->scan.plan.state = estate;
+
+       /* --------------------------------
+        *      Part 1)  initialize scan state
+        *
+        *      create new CommonScanState for node
+        * --------------------------------
+        */
+       scanstate = makeNode(CommonScanState);
+/*
+       scanstate->ss_ProcOuterFlag = false;
+       scanstate->ss_OldRelId = 0;
+*/
+
+       node->scan.scanstate = scanstate;
+
+       /* ----------------
+        *      assign node's base_id .. we don't use AssignNodeBaseid() because
+        *      the increment is done later on after we assign the tid scan's
+        *      scanstate.      see below.
+        * ----------------
+        */
+       baseid = estate->es_BaseId;
+/*       scanstate->csstate.cstate.bnode.base_id = baseid; */
+       scanstate->cstate.cs_base_id = baseid;
+
+       /* ----------------
+        *      create expression context for node
+        * ----------------
+        */
+       ExecAssignExprContext(estate, &scanstate->cstate);
+
+#define TIDSCAN_NSLOTS 3
+       /* ----------------
+        *      tuple table initialization
+        * ----------------
+        */
+       ExecInitResultTupleSlot(estate, &scanstate->cstate);
+       ExecInitScanTupleSlot(estate, scanstate);
+/*       ExecInitRawTupleSlot(estate, scanstate); */
+
+       /* ----------------
+        *      initialize projection info.  result type comes from scan desc
+        *      below..
+        * ----------------
+        */
+       ExecAssignProjectionInfo((Plan *) node, &scanstate->cstate);
+
+       /* --------------------------------
+         *  Part 2)  initialize tid scan state
+         *
+         *  create new TidScanState for node
+         * --------------------------------
+         */
+       tidstate = makeNode(TidScanState);
+       node->tidstate = tidstate;
+
+       /* ----------------
+        *      assign base id to tid scan state also
+        * ----------------
+        */
+       tidstate->cstate.cs_base_id = baseid;
+       baseid++;
+       estate->es_BaseId = baseid;
+
+       /* ----------------
+        *      get the tid node information
+        * ----------------
+        */
+       tidList = (ItemPointer *)palloc(length(node->tideval) * sizeof(ItemPointer));
+       numTids = 0;
+       if (!node->needRescan)
+               numTids = TidListCreate(node->tideval, scanstate->cstate.cs_ExprContext, tidList);
+       tidPtr = -1;
+
+       CXT1_printf("ExecInitTidScan: context is %d\n", CurrentMemoryContext);
+
+       tidstate->tss_NumTids = numTids;
+       tidstate->tss_TidPtr = tidPtr;
+       tidstate->tss_TidList = tidList;
+
+       /* ----------------
+        *      get the range table and direction information
+        *      from the execution state (these are needed to
+        *      open the relations).
+        * ----------------
+        */
+       rangeTable = estate->es_range_table;
+
+       /* ----------------
+        *      open the base relation
+        * ----------------
+        */
+       relid = node->scan.scanrelid;
+       rtentry = rt_fetch(relid, rangeTable);
+       reloid = rtentry->relid;
+
+       currentRelation = heap_open(reloid, AccessShareLock);
+        if (currentRelation == NULL)
+                elog(ERROR, "ExecInitTidScan heap_open failed."); 
+       scanstate->css_currentRelation = currentRelation;
+       scanstate->css_currentScanDesc = 0;
+
+       /* ----------------
+        *      get the scan type from the relation descriptor.
+        * ----------------
+        */
+       ExecAssignScanType(scanstate, RelationGetDescr(currentRelation));
+       ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate);
+
+       /* ----------------
+        *      tid scans don't have subtrees..
+        * ----------------
+        */
+/*       scanstate->ss_ProcOuterFlag = false; */
+
+       tidstate->cstate.cs_TupFromTlist = false;
+
+       /*
+        * if there are some PARAM_EXEC in skankeys then force tid rescan on
+        * first scan.
+        */
+       ((Plan *) node)->chgParam = execParam;
+
+       /* ----------------
+        *      all done.
+        * ----------------
+        */
+       return TRUE;
+}
+
+int
+ExecCountSlotsTidScan(TidScan *node)
+{
+       return ExecCountSlotsNode(outerPlan((Plan *) node)) +
+       ExecCountSlotsNode(innerPlan((Plan *) node)) + TIDSCAN_NSLOTS;
+}
index 5f23a954b13a46325b88f3900c77021b25017571..1b2726f822647b655497c40c1ac7018b47e48738 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.96 1999/11/15 03:28:06 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.97 1999/11/23 20:06:52 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -253,6 +253,32 @@ _copyIndexScan(IndexScan *from)
        return newnode;
 }
 
+/* ----------------
+ *              _copyTidScan
+ * ----------------
+ */
+static TidScan *
+_copyTidScan(TidScan *from)
+{
+       TidScan *newnode = makeNode(TidScan);
+
+       /* ----------------
+        *      copy node superclass fields
+        * ----------------
+        */
+       CopyPlanFields((Plan *) from, (Plan *) newnode);
+       CopyScanFields((Scan *) from, (Scan *) newnode);
+       /* ----------------
+        *      copy remainder of node
+        * ----------------
+        */
+       newnode->needRescan = from->needRescan;
+       Node_Copy(from, newnode, tideval);
+
+       return newnode;
+}
+
+    
 /* ----------------
  *             CopyJoinFields
  *
@@ -1058,6 +1084,30 @@ _copyIndexPath(IndexPath *from)
        return newnode;
 }
 
+/* ----------------
+ *              _copyTidPath
+ * ----------------
+ */
+static TidPath *
+_copyTidPath(TidPath *from)
+{
+       TidPath *newnode = makeNode(TidPath);
+
+       /* ----------------
+        *      copy the node superclass fields
+        * ----------------
+        */
+       CopyPathFields((Path *) from, (Path *) newnode);
+
+       /* ----------------
+        *      copy remainder of node
+        * ----------------
+        */
+       Node_Copy(from, newnode, tideval);
+       newnode->unjoined_relids = listCopy(from->unjoined_relids);
+
+       return newnode;
+}
 /* ----------------
  *             CopyJoinPathFields
  *
@@ -1437,6 +1487,9 @@ copyObject(void *from)
                case T_IndexScan:
                        retval = _copyIndexScan(from);
                        break;
+               case T_TidScan:
+                       retval = _copyTidScan(from);
+                       break;
                case T_Join:
                        retval = _copyJoin(from);
                        break;
@@ -1535,6 +1588,9 @@ copyObject(void *from)
                case T_IndexPath:
                        retval = _copyIndexPath(from);
                        break;
+               case T_TidPath:
+                       retval = _copyTidPath(from);
+                       break;
                case T_NestPath:
                        retval = _copyNestPath(from);
                        break;
index fccb9d316087711bf93b76893949d3d6cc53cc5d..b35b271275404fab7d284eb823593009f7280211 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.51 1999/11/15 03:28:06 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.52 1999/11/23 20:06:52 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -330,6 +330,18 @@ _equalIndexPath(IndexPath *a, IndexPath *b)
        return true;
 }
 
+static bool
+_equalTidPath(TidPath *a, TidPath *b)
+{
+       if (!_equalPath((Path *) a, (Path *) b))
+               return false;
+       if (!equal(a->tideval, b->tideval))
+               return false;
+       if (!equali(a->unjoined_relids, b->unjoined_relids))
+               return false;
+       return true;
+}
+
 static bool
 _equalJoinPath(JoinPath *a, JoinPath *b)
 {
@@ -403,6 +415,28 @@ _equalIndexScan(IndexScan *a, IndexScan *b)
        return true;
 }
 
+static bool
+_equalTidScan(TidScan *a, TidScan *b)
+{
+       Assert(IsA(a, TidScan));
+       Assert(IsA(b, TidScan));
+
+       /*
+        * if(a->scan.plan.cost != b->scan.plan.cost) return(false);
+        */
+
+       if (a->needRescan != b->needRescan)
+               return false;
+
+       if (!equal(a->tideval, b->tideval))
+               return false;
+
+       if (a->scan.scanrelid != b->scan.scanrelid)
+               return false;
+
+       return true;
+}
+
 static bool
 _equalSubPlan(SubPlan *a, SubPlan *b)
 {
@@ -756,6 +790,9 @@ equal(void *a, void *b)
                case T_IndexPath:
                        retval = _equalIndexPath(a, b);
                        break;
+               case T_TidPath:
+                       retval = _equalTidPath(a, b);
+                       break;
                case T_NestPath:
                        retval = _equalNestPath(a, b);
                        break;
@@ -768,6 +805,9 @@ equal(void *a, void *b)
                case T_IndexScan:
                        retval = _equalIndexScan(a, b);
                        break;
+               case T_TidScan:
+                       retval = _equalTidScan(a, b);
+                       break;
                case T_SubPlan:
                        retval = _equalSubPlan(a, b);
                        break;
index db09b6700bc3170723a648688b18a6236393fcf4..66368afd6871a1fd5ccc4d5aaeb695110b5b2f80 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/Attic/freefuncs.c,v 1.27 1999/11/15 03:28:07 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/Attic/freefuncs.c,v 1.28 1999/11/23 20:06:53 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -183,6 +183,29 @@ _freeIndexScan(IndexScan *node)
        pfree(node);
 }
 
+/* ----------------
+ *             _freeTidScan
+ * ----------------
+ */
+static void
+_freeTidScan(TidScan *node)
+{
+       /* ----------------
+        *      free node superclass fields
+        * ----------------
+        */
+       FreePlanFields((Plan *) node);
+       FreeScanFields((Scan *) node);
+
+       /* ----------------
+        *      free remainder of node
+        * ----------------
+        */
+       freeObject(node->tideval);
+
+       pfree(node);
+}
+
 /* ----------------
  *             FreeJoinFields
  *
@@ -781,6 +804,29 @@ _freeIndexPath(IndexPath *node)
        pfree(node);
 }
 
+/* ----------------
+ *             _freeTidPath
+ * ----------------
+ */
+static void
+_freeTidPath(TidPath *node)
+{
+       /* ----------------
+        *      free the node superclass fields
+        * ----------------
+        */
+       FreePathFields((Path *) node);
+
+       /* ----------------
+        *      free remainder of node
+        * ----------------
+        */
+       freeObject(node->tideval);
+       freeList(node->unjoined_relids);
+
+       pfree(node);
+}
+
 /* ----------------
  *             FreeJoinPathFields
  *
@@ -1079,6 +1125,9 @@ freeObject(void *node)
                case T_IndexScan:
                        _freeIndexScan(node);
                        break;
+               case T_TidScan:
+                       _freeTidScan(node);
+                       break;
                case T_Join:
                        _freeJoin(node);
                        break;
@@ -1177,6 +1226,9 @@ freeObject(void *node)
                case T_IndexPath:
                        _freeIndexPath(node);
                        break;
+               case T_TidPath:
+                       _freeTidPath(node);
+                       break;
                case T_NestPath:
                        _freeNestPath(node);
                        break;
index 06c2520d271d38f2f6985ab9793701582d0b6e0a..789faad772c739468bd9feec0d0c147867da54f5 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- *     $Id: outfuncs.c,v 1.97 1999/10/07 04:23:04 tgl Exp $
+ *     $Id: outfuncs.c,v 1.98 1999/11/23 20:06:53 momjian Exp $
  *
  * NOTES
  *       Every (plan) node in POSTGRES has an associated "out" routine which
@@ -451,6 +451,23 @@ _outIndexScan(StringInfo str, IndexScan *node)
        appendStringInfo(str, " :indxorderdir %d ", node->indxorderdir);
 }
 
+/*
+ *     TidScan is a subclass of Scan
+ */
+static void
+_outTidScan(StringInfo str, TidScan *node)
+{
+       appendStringInfo(str, " TIDSCAN ");
+       _outPlanInfo(str, (Plan *) node);
+
+       appendStringInfo(str, " :scanrelid %u ", node->scan.scanrelid);
+       appendStringInfo(str, " :needrescan %d ", node->needRescan);
+
+       appendStringInfo(str, " :tideval ");
+       _outNode(str, node->tideval);
+
+}
+
 /*
  *     Noname is a subclass of Plan
  */
@@ -914,6 +931,25 @@ _outIndexPath(StringInfo str, IndexPath *node)
        _outIntList(str, node->joinrelids);
 }
 
+/*
+ *     TidPath is a subclass of Path.
+ */
+static void
+_outTidPath(StringInfo str, TidPath *node)
+{
+       appendStringInfo(str,
+                                        " TIDPATH :pathtype %d :cost %f :pathkeys ",
+                                        node->path.pathtype,
+                                        node->path.path_cost);
+       _outNode(str, node->path.pathkeys);
+
+       appendStringInfo(str, " :tideval ");
+       _outNode(str, node->tideval);
+
+       appendStringInfo(str, " :un joined_relids ");
+       _outIntList(str, node->unjoined_relids);
+}
+
 /*
  *     NestPath is a subclass of Path
  */
@@ -1357,6 +1393,9 @@ _outNode(StringInfo str, void *obj)
                        case T_IndexScan:
                                _outIndexScan(str, obj);
                                break;
+                       case T_TidScan:
+                               _outTidScan(str, obj);
+                               break;
                        case T_Noname:
                                _outNoname(str, obj);
                                break;
@@ -1435,6 +1474,9 @@ _outNode(StringInfo str, void *obj)
                        case T_IndexPath:
                                _outIndexPath(str, obj);
                                break;
+                       case T_TidPath:
+                               _outTidPath(str, obj);
+                               break;
                        case T_NestPath:
                                _outNestPath(str, obj);
                                break;
index 9cb04181cde47080bee0a2c2ac14eb03e5df7ec2..3241816cd38fde133dc5f4e289060370c60c3afc 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.32 1999/08/16 02:17:43 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.33 1999/11/23 20:06:53 momjian Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -338,6 +338,9 @@ plannode_type(Plan *p)
                case T_Group:
                        return "GROUP";
                        break;
+               case T_TidScan:
+                       return "TIDSCAN";
+                       break;
                default:
                        return "UNKNOWN";
                        break;
index ef62e5a285fc71964b43837aa6c0ed017c575af0..99be5199fa9b9fc386912cebda8d7a6eed1fb39a 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.74 1999/10/07 04:23:04 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.75 1999/11/23 20:06:53 momjian Exp $
  *
  * NOTES
  *       Most of the read functions for plan nodes are tested. (In fact, they
@@ -541,6 +541,33 @@ _readIndexScan()
        return local_node;
 }
 
+/* ----------------
+ *             _readTidScan
+ *
+ *     TidScan is a subclass of Scan
+ * ----------------
+ */
+static TidScan *
+_readTidScan()
+{
+       TidScan  *local_node;
+       char       *token;
+       int                     length;
+
+       local_node = makeNode(TidScan);
+
+       _getScan((Scan *) local_node);
+
+       token = lsptok(NULL, &length);          /* eat :needrescan */
+       token = lsptok(NULL, &length);          /* get needrescan */
+       local_node->needRescan = atoi(token);
+
+       token = lsptok(NULL, &length);          /* eat :tideval */
+       local_node->tideval = nodeRead(true);   /* now read it */
+
+       return local_node;
+}
+
 /* ----------------
  *             _readNoname
  *
@@ -1476,6 +1503,41 @@ _readIndexPath()
        return local_node;
 }
 
+/* ----------------
+ *             _readTidPath
+ *
+ *     TidPath is a subclass of Path.
+ * ----------------
+ */
+static TidPath *
+_readTidPath()
+{
+       TidPath  *local_node;
+       char       *token;
+       int                     length;
+
+       local_node = makeNode(TidPath);
+
+       token = lsptok(NULL, &length);          /* get :pathtype */
+       token = lsptok(NULL, &length);          /* now read it */
+       local_node->path.pathtype = atol(token);
+
+       token = lsptok(NULL, &length);          /* get :cost */
+       token = lsptok(NULL, &length);          /* now read it */
+       local_node->path.path_cost = (Cost) atof(token);
+
+       token = lsptok(NULL, &length);          /* get :pathkeys */
+       local_node->path.pathkeys = nodeRead(true); /* now read it */
+
+       token = lsptok(NULL, &length);          /* get :tideval */
+       local_node->tideval = nodeRead(true);   /* now read it */
+
+       token = lsptok(NULL, &length);          /* get :unjoined_relids */
+       local_node->unjoined_relids = toIntList(nodeRead(true));
+
+       return local_node;
+}
+
 /* ----------------
  *             _readNestPath
  *
@@ -1801,6 +1863,8 @@ parsePlanString(void)
                return_value = _readSeqScan();
        else if (!strncmp(token, "INDEXSCAN", length))
                return_value = _readIndexScan();
+       else if (!strncmp(token, "TIDSCAN", length))
+               return_value = _readTidScan();
        else if (!strncmp(token, "NONAME", length))
                return_value = _readNoname();
        else if (!strncmp(token, "SORT", length))
@@ -1845,6 +1909,8 @@ parsePlanString(void)
                return_value = _readPath();
        else if (!strncmp(token, "INDEXPATH", length))
                return_value = _readIndexPath();
+       else if (!strncmp(token, "TIDPATH", length))
+               return_value = _readTidPath();
        else if (!strncmp(token, "NESTPATH", length))
                return_value = _readNestPath();
        else if (!strncmp(token, "MERGEPATH", length))
index cdc401b83104525fb7ec9eb214f0fc1709d09354..5e903ce666df0444939ffec5f696d39646f61ee8 100644 (file)
@@ -4,7 +4,7 @@
 #    Makefile for optimizer/path
 #
 # IDENTIFICATION
-#    $Header: /cvsroot/pgsql/src/backend/optimizer/path/Makefile,v 1.9 1999/08/16 02:17:50 tgl Exp $
+#    $Header: /cvsroot/pgsql/src/backend/optimizer/path/Makefile,v 1.10 1999/11/23 20:06:54 momjian Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -14,7 +14,8 @@ include ../../../Makefile.global
 CFLAGS += -I../..
 
 OBJS = allpaths.o clausesel.o costsize.o indxpath.o \
-       joinpath.o joinrels.o orindxpath.o pathkeys.o prune.o
+       joinpath.o joinrels.o orindxpath.o pathkeys.o prune.o \
+       tidpath.o
 
 all: SUBSYS.o
 
index 23c759bd6e6ceceba5a4465ef3406a08cccfd859..3cc8466f77b819482c512fa02ee1fb4c76b4ffc3 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.53 1999/08/16 02:17:50 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.54 1999/11/23 20:06:54 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -108,9 +108,14 @@ set_base_rel_pathlist(Query *root, List *rels)
                List       *sequential_scan_list;
                List       *rel_index_scan_list;
                List       *or_index_scan_list;
+               List       *tidscan_pathlist;
 
                sequential_scan_list = lcons(create_seqscan_path(rel), NIL);
-
+               /* Tid Scan Pathlist add */
+               tidscan_pathlist = create_tidscan_paths(root, rel);
+               if (tidscan_pathlist)
+                       sequential_scan_list = nconc(sequential_scan_list,
+                               tidscan_pathlist);
                rel_index_scan_list = create_index_paths(root,
                                                                                                 rel,
                                                                                                 indices,
index fcf462b83eb08a268e2080f1533f58f514ad5d2f..99ee42cf8c7b7cc14a40ba8cd18bafd54eaf186c 100644 (file)
@@ -18,7 +18,7 @@
  * Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.45 1999/08/22 20:14:41 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.46 1999/11/23 20:06:54 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -59,6 +59,7 @@ bool          _enable_sort_ = true;
 bool           _enable_nestloop_ = true;
 bool           _enable_mergejoin_ = true;
 bool           _enable_hashjoin_ = true;
+bool           _enable_tidscan_ = true;
 
 Cost            _cpu_page_weight_ = _CPU_PAGE_WEIGHT_;
 Cost           _cpu_index_page_weight_ = _CPU_INDEX_PAGE_WEIGHT_;
@@ -174,6 +175,29 @@ cost_index(Oid indexid,
        return temp;
 }
 
+/*
+ * cost_tidscan
+ *       Determines and returns the cost of scanning a relation using tid-s.
+ *
+ *             disk = number of tids
+ *             cpu = *CPU-PAGE-WEIGHT* * number_of_tids
+ *
+ * Returns a flonum.
+ *
+ */
+Cost
+cost_tidscan(List *tideval)
+{
+       Cost    temp = 0;
+
+       if (!_enable_tidscan_)
+               temp += _disable_cost_;
+
+       temp += (1.0 + _cpu_page_weight_) * length(tideval);
+
+       return temp;
+}
 /*
  * cost_sort
  *       Determines and returns the cost of sorting a relation by considering
diff --git a/src/backend/optimizer/path/tidpath.c b/src/backend/optimizer/path/tidpath.c
new file mode 100644 (file)
index 0000000..9e618f7
--- /dev/null
@@ -0,0 +1,296 @@
+/*-------------------------------------------------------------------------
+ *
+ * tidpath.c
+ *       Routines to determine which tids are usable for scanning a
+ *       given relation, and create TidPaths accordingly.
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/path/tidpath.c,v 1.1 1999/11/23 20:06:55 momjian Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include <math.h>
+
+#include "postgres.h"
+
+#include "access/heapam.h"
+#include "catalog/catname.h"
+#include "catalog/pg_amop.h"
+#include "catalog/pg_operator.h"
+#include "executor/executor.h"
+#include "nodes/makefuncs.h"
+#include "nodes/nodeFuncs.h"
+#include "optimizer/clauses.h"
+#include "optimizer/cost.h"
+#include "optimizer/pathnode.h"
+#include "optimizer/paths.h"
+#include "optimizer/plancat.h"
+#include "optimizer/restrictinfo.h"
+#include "parser/parse_coerce.h"
+#include "parser/parse_expr.h"
+#include "parser/parse_oper.h"
+#include "parser/parsetree.h"
+#include "utils/lsyscache.h"
+
+static List    *create_tidscan_joinpaths(RelOptInfo *);
+static List    *TidqualFromRestrictinfo(List *relids, List * restrictinfo);
+static bool    isEvaluable(int varno, Node *node);
+static Node    *TidequalClause(int varno, Expr *node);
+static List    *TidqualFromExpr(int varno, Expr *expr);
+
+static
+bool isEvaluable(int varno, Node *node)
+{
+       List    *lst;
+       Expr    *expr;
+
+       if (IsA(node, Const))           return true;
+       if (IsA(node, Param))           return true;
+       if (IsA(node, Var))
+       {
+               Var     *var = (Var *)node;
+
+               if (var->varno == varno)
+                       return false;
+               return true;
+       }
+       if (!is_funcclause(node))       return false;
+       expr = (Expr *)node;
+       foreach (lst, expr->args)
+       {
+               if (!isEvaluable(varno, lfirst(lst)))
+                       return false;
+       }
+
+       return true;
+}
+
+/*
+ *     The 2nd parameter should be an opclause
+ *     Extract the right node if the opclause is CTID= ....
+ *       or    the left  node if the opclause is ....=CTID
+ */
+static
+Node *TidequalClause(int varno, Expr *node)
+{
+       Node    *rnode = 0, *arg1, *arg2, *arg;
+       Oper    *oper;
+       Var     *var;
+       Const   *aconst;
+       Param   *param;
+       Expr    *expr;
+
+       if (!node->oper)                return rnode;
+       if (!node->args)                return rnode;
+       if (length(node->args) != 2)    return rnode;
+        oper = (Oper *) node->oper;
+       if (oper->opno != TIDEqualOperator)
+               return rnode;
+       arg1 = lfirst(node->args);
+       arg2 = lsecond(node->args);
+
+       arg = (Node *)0;
+       if (IsA(arg1, Var))
+       {
+               var = (Var *) arg1;
+               if (var->varno == varno &&
+                   var->varattno == SelfItemPointerAttributeNumber &&
+                   var->vartype == TIDOID)
+                       arg = arg2;
+               else if (var->varnoold == varno &&
+                       var->varoattno == SelfItemPointerAttributeNumber &&
+                       var->vartype == TIDOID)
+                       arg = arg2;
+       }
+       if ((!arg) && IsA(arg2, Var))
+       {
+               var = (Var *) arg2;
+               if (var->varno == varno &&
+                   var->varattno == SelfItemPointerAttributeNumber &&
+                   var->vartype == TIDOID)
+                       arg = arg1;
+       }
+       if (!arg)
+               return rnode;
+       switch (nodeTag(arg))
+       {
+               case T_Const:
+                       aconst = (Const *) arg;
+                       if (aconst->consttype != TIDOID)
+                               return rnode;
+                       if (aconst->constbyval)
+                               return rnode;
+                       rnode = arg;
+                       break;
+               case T_Param:
+                       param = (Param *) arg;
+                       if (param->paramtype != TIDOID)
+                               return rnode;
+                       rnode = arg;
+                       break;
+               case T_Var:
+                       var = (Var *) arg;
+                       if (var->varno == varno ||
+                           var->vartype != TIDOID)
+                               return rnode;
+                       rnode = arg;
+                       break;
+               case T_Expr:
+                       expr = (Expr *) arg;
+                       if (expr->typeOid != TIDOID)    return rnode;
+                       if (expr->opType != FUNC_EXPR)  return rnode;
+                       if (isEvaluable(varno, (Node *)expr))
+                               rnode = arg;
+                       break;
+               default:
+                       break;
+       }
+       return rnode;
+}
+
+/*
+ *     Extract the list of CTID values from a specified expr node.
+ *     When the expr node is an or_clause,we try to extract CTID
+ *     values from all member nodes. However we would discard them
+ *     all if we couldn't extract CTID values from a member node.
+ *     When the expr node is an and_clause,we return the list of
+ *     CTID values if we could extract the CTID values from a member
+ *     node.
+ */ 
+static
+List *TidqualFromExpr(int varno, Expr *expr)
+{
+       List    *rlst = NIL, *lst, *frtn;
+       Node    *node = (Node *) expr, *rnode;
+
+       if (is_opclause(node))
+       {
+               rnode = TidequalClause(varno, expr);
+               if (rnode)
+               {
+                       rlst = lcons(rnode, rlst);
+               } 
+       }
+       else if (and_clause(node))
+       {
+               foreach (lst, expr->args)
+               {
+                       node = lfirst(lst);
+                       if (!IsA(node, Expr))   
+                               continue;
+                       rlst = TidqualFromExpr(varno, (Expr *)node);
+                       if (rlst)
+                               break;
+               }
+       }
+       else if (or_clause(node))
+       {
+               foreach (lst, expr->args)
+               {
+                       node = lfirst(lst);
+                       if (IsA(node, Expr) &&
+                           (frtn = TidqualFromExpr(varno, (Expr *)node)) )
+                       {
+                               rlst = nconc(rlst, frtn);
+                       }
+                       else
+                       {
+                               if (rlst)
+                                       freeList(rlst);
+                               rlst = NIL;
+                               break;
+                       }
+               }
+       }
+       return rlst;
+} 
+
+static
+List *TidqualFromRestrictinfo(List *relids, List * restrictinfo)
+{
+       List    *lst, *rlst = NIL;
+       int     varno;
+       Node    *node;
+       Expr    *expr;
+
+       if (length(relids)>1)   return NIL;
+       varno = (int)lfirst(relids);
+       foreach (lst, restrictinfo)
+       {
+               node = lfirst(lst);
+               if (!IsA(node, RestrictInfo))   continue;
+               expr = ((RestrictInfo *)node)->clause;
+               rlst = TidqualFromExpr(varno, expr);
+               if (rlst)
+               {
+                       break;
+               }
+       }
+       return rlst;
+}
+
+/*
+ * create_tidscan_joinpaths
+ *       Creates a path corresponding to a tid_direct scan, returning the
+ *       pathnode.
+ *
+ */
+List *
+create_tidscan_joinpaths(RelOptInfo *rel)
+{
+       List            *rlst = NIL, *lst;
+       TidPath         *pathnode = (TidPath *)0;
+       List            *restinfo, *tideval;
+
+       foreach (lst, rel->joininfo)
+       {
+               JoinInfo *joininfo = (JoinInfo *)lfirst(lst);
+               restinfo = joininfo->jinfo_restrictinfo;
+               tideval = TidqualFromRestrictinfo(rel->relids, restinfo);
+               if (tideval && length(tideval) == 1)
+               {
+                       pathnode = makeNode(TidPath);
+
+                       pathnode->path.pathtype = T_TidScan;
+                       pathnode->path.parent = rel;
+                       pathnode->path.path_cost = 0.0;
+                       pathnode->path.pathkeys = NIL;
+
+                       pathnode->path.path_cost = cost_tidscan(tideval);
+                       pathnode->tideval = tideval;
+                       /*
+                       pathnode->tideval = copyObject(tideval);
+                       freeList(tideval);
+                       */
+                       pathnode->unjoined_relids = joininfo->unjoined_relids;
+                       rlst = lappend(rlst, pathnode);
+               }
+       }
+       rel->innerjoin = nconc(rel->innerjoin, rlst);
+       return rlst;
+}
+
+/*
+ * create_tidscan_paths
+ *       Creates a path corresponding to a tid direct scan, returning the
+ *       pathnode List.
+ *
+ */
+List *
+create_tidscan_paths(Query *root, RelOptInfo *rel)
+{
+       List    *rlst = NIL;
+       TidPath *pathnode = (TidPath *)0;
+       List    *tideval = TidqualFromRestrictinfo(rel->relids, rel->restrictinfo);
+       
+       if (tideval)
+               pathnode = create_tidscan_path(rel, tideval);
+       if (pathnode)
+               rlst = lcons(pathnode, rlst);
+       create_tidscan_joinpaths(rel);
+
+       return rlst;
+}
index b9742d6fef5e8d46ee3ddaa896e72c0b2003a4d9..6fda28aa747f32edc9c8224f70934645143171e1 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.76 1999/08/22 23:56:44 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.77 1999/11/23 20:06:57 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -37,6 +37,8 @@ static SeqScan *create_seqscan_node(Path *best_path, List *tlist,
                                        List *scan_clauses);
 static IndexScan *create_indexscan_node(IndexPath *best_path, List *tlist,
                                          List *scan_clauses);
+static TidScan *create_tidscan_node(TidPath *best_path, List *tlist,
+                                         List *scan_clauses); 
 static NestLoop *create_nestloop_node(NestPath *best_path, List *tlist,
                                         List *clauses, Plan *outer_node, List *outer_tlist,
                                         Plan *inner_node, List *inner_tlist);
@@ -53,6 +55,8 @@ static Node *fix_indxqual_operand(Node *node, IndexPath *index_path,
                                                                  Form_pg_index index);
 static IndexScan *make_indexscan(List *qptlist, List *qpqual, Index scanrelid,
                           List *indxid, List *indxqual, List *indxqualorig);
+static TidScan *make_tidscan(List *qptlist, List *qpqual, Index scanrelid,
+                        List *tideval);
 static NestLoop *make_nestloop(List *qptlist, List *qpqual, Plan *lefttree,
                          Plan *righttree);
 static HashJoin *make_hashjoin(List *tlist, List *qpqual,
@@ -101,6 +105,7 @@ create_plan(Path *best_path)
        {
                case T_IndexScan:
                case T_SeqScan:
+               case T_TidScan:
                        plan_node = (Plan *) create_scan_node(best_path, tlist);
                        break;
                case T_HashJoin:
@@ -168,6 +173,12 @@ create_scan_node(Path *best_path, List *tlist)
                                                                                                  scan_clauses);
                        break;
 
+               case T_TidScan:
+                       node = (Scan *) create_tidscan_node((TidPath *) best_path,
+                                                                                                 tlist,
+                                                                                                 scan_clauses);
+                       break;
+
                default:
                        elog(ERROR, "create_scan_node: unknown node type",
                                 best_path->pathtype);
@@ -399,6 +410,62 @@ create_indexscan_node(IndexPath *best_path,
        return scan_node;
 }
 
+static TidScan *
+make_tidscan(List *qptlist,
+                       List *qpqual,
+                       Index scanrelid,        
+                       List *tideval)
+{
+        TidScan        *node = makeNode(TidScan);
+       Plan    *plan = &node->scan.plan;
+
+       plan->cost = 0;
+       plan->plan_size = 0;
+       plan->plan_width = 0;
+       plan->state = (EState *) NULL;
+       plan->targetlist = qptlist;
+       plan->qual = qpqual;
+       plan->lefttree = NULL;
+       plan->righttree = NULL;
+       node->scan.scanrelid = scanrelid;
+       node->tideval = copyObject(tideval);
+       node->needRescan = false;
+       node->scan.scanstate = (CommonScanState *) NULL;
+
+       return node;
+}
+
+/*
+ * create_tidscan_node
+ *      Returns a tidscan node for the base relation scanned by 'best_path'
+ *      with restriction clauses 'scan_clauses' and targetlist 'tlist'.
+ */
+static TidScan *
+create_tidscan_node(TidPath *best_path, List *tlist, List *scan_clauses)
+{
+       TidScan *scan_node = (TidScan *) NULL;
+       Index   scan_relid = -1;
+       List    *temp;
+
+       temp = best_path->path.parent->relids;
+       if (temp == NULL)
+               elog(ERROR, "scanrelid is empty");
+       else if (length(temp) != 1)
+               return scan_node;
+       else 
+               scan_relid = (Index) lfirsti(temp);
+       scan_node = make_tidscan(tlist,
+                                scan_clauses,
+                                scan_relid,
+                                best_path->tideval);
+
+       if (best_path->unjoined_relids)
+               scan_node->needRescan = true; 
+       scan_node->scan.plan.cost = best_path->path.path_cost;
+
+       return scan_node;
+}
+
 /*****************************************************************************
  *
  *     JOIN METHODS
@@ -487,6 +554,12 @@ create_nestloop_node(NestPath *best_path,
                                                                                                   innerrel);
                }
        }
+       else if (IsA(inner_node, TidScan))
+       {
+               List    *inner_tideval = ((TidScan *) inner_node)->tideval;
+               TidScan *innerscan = (TidScan *) inner_node; 
+               ((TidScan *) inner_node)->tideval = join_references(inner_tideval, outer_tlist, inner_tlist, innerscan->scan.scanrelid);
+       } 
        else if (IsA_Join(inner_node))
        {
                /*
index 051c2ea3e3d97e4b6b34542cc57bd665c3caa2b0..ec8c67b7a7a08417a3038baea68242095ea80359 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.58 1999/10/30 23:07:55 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.59 1999/11/23 20:06:57 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -125,6 +125,9 @@ set_plan_references(Plan *plan)
                                set_plan_references((Plan *) lfirst(pl));
                        }
                        break;
+               case T_TidScan:
+                       /* nothing special */
+                       break;
                default:
                        elog(ERROR, "set_plan_references: unknown plan type %d",
                                 nodeTag(plan));
index 5290c96d5db6a4e5f8ef3bce935f3f53fa13fd86..d04839afc2969f68a1388143d756f48e48321fcc 100644 (file)
@@ -6,7 +6,7 @@
  * Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.25 1999/11/15 02:00:08 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.26 1999/11/23 20:06:57 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -534,6 +534,11 @@ SS_finalize_plan(Plan *plan)
                                                          &results);
                        break;
 
+               case T_TidScan:
+                       finalize_primnode((Node *) ((TidScan *) plan)->tideval,
+                                                       &results);
+                       break;
+
                case T_Agg:
                case T_SeqScan:
                case T_NestLoop:
index f3b99f88929a6766b4f274e5b3bf6ec9f58ad454..0f9bf1b8bbb987e0de84b73064424f444122f904 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.54 1999/08/16 02:17:58 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.55 1999/11/23 20:07:00 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -318,6 +318,32 @@ create_index_path(Query *root,
        return pathnode;
 }
 
+/*
+ * create_tidscan_path
+ *       Creates a path corresponding to a tid_direct scan, returning the
+ *       pathnode.
+ *
+ */
+TidPath *
+create_tidscan_path(RelOptInfo *rel, List *tideval)
+{
+       TidPath *pathnode = makeNode(TidPath);
+
+       pathnode->path.pathtype = T_TidScan;
+       pathnode->path.parent = rel;
+       pathnode->path.path_cost = 0.0;
+       pathnode->path.pathkeys = NIL;
+
+       pathnode->path.path_cost = cost_tidscan(tideval);
+       /* divide selectivity for each clause to get an equal selectivity
+        * as IndexScan does OK ? 
+       */
+       pathnode->tideval = copyObject(tideval);
+       pathnode->unjoined_relids = NIL;
+
+       return pathnode;
+}
+
 /*
  * create_nestloop_path
  *       Creates a pathnode corresponding to a nestloop join between two
index 44aa8b8ace57ff9845e91e86a013f2ed32cc06df..47e6e40b7c212fb0535117786ea6e9b23d3699fe 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: execnodes.h,v 1.37 1999/10/17 22:15:07 tgl Exp $
+ * $Id: execnodes.h,v 1.38 1999/11/23 20:07:02 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -414,6 +414,37 @@ typedef struct IndexScanState
        HeapTupleData iss_htup;
 } IndexScanState;
 
+/* ----------------
+ *      TidScanState information
+ *
+ *|            tid scans don't use CommonScanState because
+ *|            the underlying AM abstractions for heap scans and
+ *|            tid scans are too different..  It would be nice
+ *|            if the current abstraction was more useful but ... -cim 10/15/89
+ *
+ *             TidPtr             current tid in use
+ *             NumTids            number of tids in this scan
+ *             tidList            evaluated item pointers
+ *
+ *      CommonState information
+ *
+ *             OuterTupleSlot     pointer to slot containing current "outer" tuple
+ *             ResultTupleSlot    pointer to slot in tuple table for projected tuple
+ *             ExprContext                node's current expression context
+ *             ProjInfo                   info this node uses to form tuple projections
+ *             NumScanAttributes  size of ScanAttributes array
+ *             ScanAttributes     attribute numbers of interest in this tuple
+ * ----------------
+ */
+typedef struct TidScanState
+{
+       CommonState cstate;                     /* its first field is NodeTag */
+       int                     tss_NumTids;
+       int                     tss_TidPtr;
+       int                     tss_MarkTidPtr;
+       ItemPointer             *tss_TidList;
+       HeapTupleData           tss_htup;
+} TidScanState;
 
 /* ----------------------------------------------------------------
  *                              Join State Information
index 09f60466f4399d5877df0a98bebe66b25b859194..4e830d7527c235e37a2578c8e9f531834187b977 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: nodes.h,v 1.55 1999/10/15 01:49:47 momjian Exp $
+ * $Id: nodes.h,v 1.56 1999/11/23 20:07:02 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -47,6 +47,7 @@ typedef enum NodeTag
        T_Choose,
        T_Group,
        T_SubPlan,
+       T_TidScan,
 
        /*---------------------
         * TAGS FOR PRIMITIVE NODES (primnodes.h)
@@ -80,6 +81,7 @@ typedef enum NodeTag
        T_RestrictInfo,
        T_JoinInfo,
        T_Stream,
+       T_TidPath,
 
        /*---------------------
         * TAGS FOR EXECUTOR NODES (execnodes.h)
@@ -110,6 +112,7 @@ typedef enum NodeTag
        T_SortState,
        T_UniqueState,
        T_HashState,
+       T_TidScanState,
 
        /*---------------------
         * TAGS FOR MEMORY NODES (memnodes.h)
index 00e7025917da6842aabd6bcfee445b3059b07f63..9cd06e2d93211e20c5356e03272ad2ed7f8fe576 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: plannodes.h,v 1.33 1999/11/15 03:28:06 tgl Exp $
+ * $Id: plannodes.h,v 1.34 1999/11/23 20:07:02 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -179,7 +179,19 @@ typedef struct IndexScan
        IndexScanState *indxstate;
 } IndexScan;
 
-/*
+/* ----------------
+ *              tid scan node
+ * ----------------
+ */
+typedef struct TidScan
+{
+        Scan            scan;
+       bool            needRescan;
+        List            *tideval;
+        TidScanState    *tidstate;
+} TidScan;
+
+/* 
  * ==========
  * Join nodes
  * ==========
index 91fa85dd25e3340900ecd3cb8bf924953ac8e25f..0f143017b2ab1a0828ee26f18eb8a556e5da9688 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: relation.h,v 1.38 1999/08/16 02:17:40 tgl Exp $
+ * $Id: relation.h,v 1.39 1999/11/23 20:07:02 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -193,6 +193,13 @@ typedef struct IndexPath
        Relids          joinrelids;                     /* other rels mentioned in indexqual */
 } IndexPath;
 
+typedef struct TidPath
+{
+       Path    path;
+       List    *tideval;
+       Relids  unjoined_relids; /* some rels not yet part of my Path */
+} TidPath;  
+
 /*
  * All join-type paths share these fields.
  */
index 6791435a4d14af2348bd5abc46549509217390a2..abde39b237c3eb1f0299f926c72eb3b2bbdaf3b8 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: cost.h,v 1.23 1999/08/06 04:00:13 tgl Exp $
+ * $Id: cost.h,v 1.24 1999/11/23 20:07:05 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -31,11 +31,13 @@ extern bool _enable_sort_;
 extern bool _enable_nestloop_;
 extern bool _enable_mergejoin_;
 extern bool _enable_hashjoin_;
+extern bool _enable_tidscan_;
 
 extern Cost cost_seqscan(int relid, int relpages, int reltuples);
 extern Cost cost_index(Oid indexid, int expected_indexpages, Cost selec,
                   int relpages, int reltuples, int indexpages,
                   int indextuples, bool is_injoin);
+extern Cost cost_tidscan(List *evallist);
 extern Cost cost_sort(List *pathkeys, int tuples, int width);
 extern Cost cost_nestloop(Cost outercost, Cost innercost, int outertuples,
                          int innertuples, int outerpages, bool is_indexjoin);
index 65ece63c57502305f4ddb2ffe28bdf3369d67f86..2aca95e605df1ca17dec3e0b21b03d3d1c1cd05d 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pathnode.h,v 1.21 1999/08/16 02:17:45 tgl Exp $
+ * $Id: pathnode.h,v 1.22 1999/11/23 20:07:06 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -27,6 +27,7 @@ extern Path *create_seqscan_path(RelOptInfo *rel);
 
 extern IndexPath *create_index_path(Query *root, RelOptInfo *rel,
                RelOptInfo *index, List *restriction_clauses);
+extern TidPath *create_tidscan_path(RelOptInfo *rel, List *tideval);
 
 extern NestPath *create_nestloop_path(RelOptInfo *joinrel,
                RelOptInfo *outer_rel, Path *outer_path, Path *inner_path,
index 58da94368c95d59677580f03a5678faa0dfa5d64..92ce9f9719f6a5d0f9010cf809fa73be6637f864 100644 (file)
@@ -7,7 +7,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: paths.h,v 1.35 1999/08/21 03:49:15 tgl Exp $
+ * $Id: paths.h,v 1.36 1999/11/23 20:07:06 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -30,6 +30,12 @@ extern List *create_index_paths(Query *root, RelOptInfo *rel, List *indices,
                                   List *joininfo_list);
 extern List *expand_indexqual_conditions(List *indexquals);
 
+/*
+ * tidpath.h
+ *       routines to generate tid paths
+ */
+extern List *create_tidscan_paths(Query *root, RelOptInfo *rel);
+
 /*
  * joinpath.c
  *        routines to create join paths