diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index a26216c0269f996710a9b1fb380082444aaf7eaa..3636993387528df91849d117ed59d66f11cc9c7e 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -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);
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 99e4e45dd5c7f0cdc3458c0efd2df0810b6c1793..95856194fff6a34f7341d34be228f3d64c7c7597 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -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;
 	}
diff --git a/src/backend/executor/Makefile b/src/backend/executor/Makefile
index 4f8c1341c8312baa2c5b48dd4d6e4048549cb9d0..ea0b20e9b489a8c3ebf09656c175581bb187c2e4 100644
--- a/src/backend/executor/Makefile
+++ b/src/backend/executor/Makefile
@@ -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
 
diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c
index dc69953e21095a3ebf055be8dc74af67a6e00039..0d7801bcd8a4a4e25d3273b80b7e85d174266943 100644
--- a/src/backend/executor/execAmi.c
+++ b/src/backend/executor/execAmi.c
@@ -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;
diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c
index 1b6d2bd84217b4cd2a8b8afaf9a514fc49fd3cb3..d4527be23badd1f291bd7daf3bbc1753f13c7eef 100644
--- a/src/backend/executor/execProcnode.c
+++ b/src/backend/executor/execProcnode.c
@@ -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;
diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c
index 53edd555ad8f546b798a77de925a8a54eb21d332..f1f6d15f1b00b5a5cf1b204818eae60bd5aedfa5 100644
--- a/src/backend/executor/execTuples.c
+++ b/src/backend/executor/execTuples.c
@@ -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
index 0000000000000000000000000000000000000000..8d6481bf8ad4b823cc89b3bc3e6ef593edefc844
--- /dev/null
+++ b/src/backend/executor/nodeTidscan.c
@@ -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;
+}
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 5f23a954b13a46325b88f3900c77021b25017571..1b2726f822647b655497c40c1ac7018b47e48738 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -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;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index fccb9d316087711bf93b76893949d3d6cc53cc5d..b35b271275404fab7d284eb823593009f7280211 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -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;
diff --git a/src/backend/nodes/freefuncs.c b/src/backend/nodes/freefuncs.c
index db09b6700bc3170723a648688b18a6236393fcf4..66368afd6871a1fd5ccc4d5aaeb695110b5b2f80 100644
--- a/src/backend/nodes/freefuncs.c
+++ b/src/backend/nodes/freefuncs.c
@@ -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;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 06c2520d271d38f2f6985ab9793701582d0b6e0a..789faad772c739468bd9feec0d0c147867da54f5 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -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;
diff --git a/src/backend/nodes/print.c b/src/backend/nodes/print.c
index 9cb04181cde47080bee0a2c2ac14eb03e5df7ec2..3241816cd38fde133dc5f4e289060370c60c3afc 100644
--- a/src/backend/nodes/print.c
+++ b/src/backend/nodes/print.c
@@ -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;
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index ef62e5a285fc71964b43837aa6c0ed017c575af0..99be5199fa9b9fc386912cebda8d7a6eed1fb39a 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -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))
diff --git a/src/backend/optimizer/path/Makefile b/src/backend/optimizer/path/Makefile
index cdc401b83104525fb7ec9eb214f0fc1709d09354..5e903ce666df0444939ffec5f696d39646f61ee8 100644
--- a/src/backend/optimizer/path/Makefile
+++ b/src/backend/optimizer/path/Makefile
@@ -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
 
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 23c759bd6e6ceceba5a4465ef3406a08cccfd859..3cc8466f77b819482c512fa02ee1fb4c76b4ffc3 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -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,
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index fcf462b83eb08a268e2080f1533f58f514ad5d2f..99ee42cf8c7b7cc14a40ba8cd18bafd54eaf186c 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -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
index 0000000000000000000000000000000000000000..9e618f7a872adfc3d85095015d8d096e68667aee
--- /dev/null
+++ b/src/backend/optimizer/path/tidpath.c
@@ -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;
+}
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index b9742d6fef5e8d46ee3ddaa896e72c0b2003a4d9..6fda28aa747f32edc9c8224f70934645143171e1 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -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))
 	{
 		/*
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 051c2ea3e3d97e4b6b34542cc57bd665c3caa2b0..ec8c67b7a7a08417a3038baea68242095ea80359 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -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));
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index 5290c96d5db6a4e5f8ef3bce935f3f53fa13fd86..d04839afc2969f68a1388143d756f48e48321fcc 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -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:
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index f3b99f88929a6766b4f274e5b3bf6ec9f58ad454..0f9bf1b8bbb987e0de84b73064424f444122f904 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -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
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 44aa8b8ace57ff9845e91e86a013f2ed32cc06df..47e6e40b7c212fb0535117786ea6e9b23d3699fe 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -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
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 09f60466f4399d5877df0a98bebe66b25b859194..4e830d7527c235e37a2578c8e9f531834187b977 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -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)
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 00e7025917da6842aabd6bcfee445b3059b07f63..9cd06e2d93211e20c5356e03272ad2ed7f8fe576 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -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
  * ==========
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index 91fa85dd25e3340900ecd3cb8bf924953ac8e25f..0f143017b2ab1a0828ee26f18eb8a556e5da9688 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -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.
  */
diff --git a/src/include/optimizer/cost.h b/src/include/optimizer/cost.h
index 6791435a4d14af2348bd5abc46549509217390a2..abde39b237c3eb1f0299f926c72eb3b2bbdaf3b8 100644
--- a/src/include/optimizer/cost.h
+++ b/src/include/optimizer/cost.h
@@ -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);
diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h
index 65ece63c57502305f4ddb2ffe28bdf3369d67f86..2aca95e605df1ca17dec3e0b21b03d3d1c1cd05d 100644
--- a/src/include/optimizer/pathnode.h
+++ b/src/include/optimizer/pathnode.h
@@ -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,
diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h
index 58da94368c95d59677580f03a5678faa0dfa5d64..92ce9f9719f6a5d0f9010cf809fa73be6637f864 100644
--- a/src/include/optimizer/paths.h
+++ b/src/include/optimizer/paths.h
@@ -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