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