summaryrefslogtreecommitdiff
path: root/src/backend/nodes
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/nodes')
-rw-r--r--src/backend/nodes/Makefile.inc33
-rw-r--r--src/backend/nodes/README65
-rw-r--r--src/backend/nodes/copyfuncs.c1675
-rw-r--r--src/backend/nodes/equalfuncs.c703
-rw-r--r--src/backend/nodes/execnodes.h689
-rw-r--r--src/backend/nodes/list.c438
-rw-r--r--src/backend/nodes/makefuncs.c117
-rw-r--r--src/backend/nodes/makefuncs.h48
-rw-r--r--src/backend/nodes/memnodes.h101
-rw-r--r--src/backend/nodes/nodeFuncs.c116
-rw-r--r--src/backend/nodes/nodeFuncs.h23
-rw-r--r--src/backend/nodes/nodes.c45
-rw-r--r--src/backend/nodes/nodes.h299
-rw-r--r--src/backend/nodes/outfuncs.c1670
-rw-r--r--src/backend/nodes/params.h90
-rw-r--r--src/backend/nodes/parsenodes.h731
-rw-r--r--src/backend/nodes/pg_list.h112
-rw-r--r--src/backend/nodes/plannodes.h330
-rw-r--r--src/backend/nodes/primnodes.h318
-rw-r--r--src/backend/nodes/print.c377
-rw-r--r--src/backend/nodes/read.c270
-rw-r--r--src/backend/nodes/readfuncs.c1948
-rw-r--r--src/backend/nodes/readfuncs.h27
-rw-r--r--src/backend/nodes/relation.h279
24 files changed, 10504 insertions, 0 deletions
diff --git a/src/backend/nodes/Makefile.inc b/src/backend/nodes/Makefile.inc
new file mode 100644
index 0000000000..4066231f1f
--- /dev/null
+++ b/src/backend/nodes/Makefile.inc
@@ -0,0 +1,33 @@
+#-------------------------------------------------------------------------
+#
+# Makefile.inc--
+# Makefile for the nodes module
+#
+# Copyright (c) 1994, Regents of the University of California
+#
+#
+# IDENTIFICATION
+# $Header$
+#
+# NOTES
+# Originally, the nodes module is a home-brew, C++ like inheritance
+# system. However, the automatically generated tags, accessor functions
+# and the header files themselves are difficult to maintain. We need
+# real language support. Emulation doesn't quite do it...
+#
+# See nodes/README for an explanation of the new no-frills nodes
+# structures.
+# - ay 11/5/94
+#
+#-------------------------------------------------------------------------
+
+VPATH:= $(VPATH):$(CURDIR)/nodes
+
+
+SRCS_NODES= nodeFuncs.c nodes.c list.c \
+ copyfuncs.c equalfuncs.c makefuncs.c outfuncs.c readfuncs.c \
+ print.c read.c
+
+HEADERS+= execnodes.h makefuncs.h memnodes.h nodeFuncs.h nodes.h \
+ params.h parsenodes.h pg_list.h plannodes.h primnodes.h relation.h
+
diff --git a/src/backend/nodes/README b/src/backend/nodes/README
new file mode 100644
index 0000000000..6a5bfd4dc9
--- /dev/null
+++ b/src/backend/nodes/README
@@ -0,0 +1,65 @@
+*******************************************************************************
+* *
+* EXPLANATION OF THE NODE STRUCTURES *
+* - Andrew Yu (11/94) *
+* *
+* Copyright (c) 1994, Regents of the University of California *
+* *
+* $Id$
+* *
+*******************************************************************************
+
+INTRODUCTION
+
+The current node structures are plain old C structures. "Inheritance" is
+achieved by convention. No additional functions will be generated. Functions
+that manipulate node structures reside in this directory.
+
+
+FILES IN THIS DIRECTORY
+
+ Node manipulation functions:
+ copyfuncs.c - copying a node
+ equalfuncs.c - comparing a node
+ outfuncs.c - convert a node to ascii representation
+ readfuncs.c - convert ascii representation back to a node
+ makefuncs.c - creator functions for primitive nodes
+
+ Node definitions:
+ nodes.h - define node tags (NodeTag)
+ pg_list.h - generic list
+ primnodes.h - primitive nodes
+ parsenodes.h - parse tree nodes
+ plannodes.h - plan tree nodes
+ relation.h - inner plan tree nodes
+ execnodes.h - executor nodes
+ memnodes.h - memory nodes
+
+
+STEPS TO ADD A NODE
+
+Suppose you wana define a node Foo:
+
+1. add a tag (T_Foo) to the enum NodeTag in nodes.h (You may have to
+ recompile the whole tree after doing this.)
+2. add the structure definition to the appropriate ???nodes.h file. If you
+ intend to inherit from, say a Plan node, put Plan as the first field of
+ you definition.
+3. if you intend to use copyObject, equal, nodeToString or stringToNode,
+ add an appropriate function to copyfuncs.c, equalfuncs.c, outfuncs.c
+ and readfuncs.c accordingly. (Except for frequently used nodes, don't
+ bother writing a creator function in makefuncs.c)
+
+
+HISTORICAL NOTE
+
+Prior to the current simple C structure definitions, the Node structures
+uses a pseudo-inheritance system which automatically generates creator and
+accessor functions. Since every node inherits from LispValue, the whole thing
+is a mess. Here's a little anecdote:
+
+ LispValue definition -- class used to support lisp structures
+ in C. This is here because we did not want to totally rewrite
+ planner and executor code which depended on lisp structures when
+ we ported postgres V1 from lisp to C. -cim 4/23/90
+
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
new file mode 100644
index 0000000000..0da8aba429
--- /dev/null
+++ b/src/backend/nodes/copyfuncs.c
@@ -0,0 +1,1675 @@
+/*-------------------------------------------------------------------------
+ *
+ * copyfuncs.c--
+ * Copy functions for Postgres tree nodes.
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header$
+ *
+ *-------------------------------------------------------------------------
+ */
+#include <stdio.h>
+#include <string.h>
+
+#include "postgres.h"
+
+#include "nodes/pg_list.h"
+#include "nodes/execnodes.h"
+#include "nodes/plannodes.h"
+#include "nodes/parsenodes.h"
+#include "nodes/primnodes.h"
+#include "nodes/relation.h"
+
+#include "utils/syscache.h"
+#include "utils/builtins.h" /* for namecpy */
+#include "utils/elog.h"
+#include "utils/palloc.h"
+#include "catalog/pg_type.h"
+#include "storage/lmgr.h"
+
+/*
+ * listCopy--
+ * this copy function only copies the "lcons-cells" of the list but not
+ * its contents. (good for list of pointers as well as list of integers).
+ */
+List *
+listCopy(List *list)
+{
+ List *newlist=NIL;
+ List *l, *nl;
+
+ foreach(l, list) {
+ if (newlist==NIL) {
+ newlist = nl = lcons(lfirst(l),NIL);
+ }else {
+ lnext(nl) = lcons(lfirst(l),NIL);
+ nl = lnext(nl);
+ }
+ }
+ return newlist;
+}
+
+/*
+ * Node_Copy--
+ * a macro to simplify calling of copyObject on the specified field
+ */
+#define Node_Copy(from, newnode, field) \
+ newnode->field = copyObject(from->field)
+
+/* ****************************************************************
+ * plannodes.h copy functions
+ * ****************************************************************
+ */
+
+/* ----------------
+ * CopyPlanFields
+ *
+ * This function copies the fields of the Plan node. It is used by
+ * all the copy functions for classes which inherit from Plan.
+ * ----------------
+ */
+static void
+CopyPlanFields(Plan *from, Plan *newnode)
+{
+ newnode->cost = from->cost;
+ newnode->plan_size = from->plan_size;
+ newnode->plan_width = from->plan_width;
+ newnode->state = from->state;
+ newnode->targetlist = copyObject(from->targetlist);
+ newnode->qual = copyObject(from->qual);
+ newnode->lefttree = copyObject(from->lefttree);
+ newnode->righttree = copyObject(from->righttree);
+}
+
+/* ----------------
+ * _copyPlan
+ * ----------------
+ */
+static Plan *
+_copyPlan(Plan *from)
+{
+ Plan *newnode = makeNode(Plan);
+
+ /* ----------------
+ * copy the node superclass fields
+ * ----------------
+ */
+ CopyPlanFields(from, newnode);
+
+ return newnode;
+}
+
+
+/* ----------------
+ * _copyExistential
+ * ----------------
+ */
+static Existential *
+_copyExistential(Existential *from)
+{
+ Existential *newnode = makeNode(Existential);
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+ CopyPlanFields(from, newnode);
+
+ return newnode;
+}
+
+/* ----------------
+ * _copyResult
+ * ----------------
+ */
+static Result *
+_copyResult(Result *from)
+{
+ Result *newnode = makeNode(Result);
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+ CopyPlanFields((Plan*)from, (Plan*)newnode);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ Node_Copy(from, newnode, resconstantqual);
+ Node_Copy(from, newnode, resstate);
+
+ return newnode;
+}
+
+/* ----------------
+ * _copyAppend
+ * ----------------
+ */
+static Append *
+_copyAppend(Append *from)
+{
+ Append *newnode = makeNode(Append);
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+ CopyPlanFields((Plan*)from, (Plan*)newnode);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ Node_Copy(from, newnode, unionplans);
+ newnode->unionrelid = from->unionrelid;
+ Node_Copy(from, newnode, unionrtentries);
+ Node_Copy(from, newnode, unionstate);
+
+ return newnode;
+}
+
+
+/* ----------------
+ * CopyScanFields
+ *
+ * This function copies the fields of the Scan node. It is used by
+ * all the copy functions for classes which inherit from Scan.
+ * ----------------
+ */
+static void
+CopyScanFields(Scan *from, Scan *newnode)
+{
+ newnode->scanrelid = from->scanrelid;
+ Node_Copy(from, newnode, scanstate);
+ return;
+}
+
+/* ----------------
+ * _copyScan
+ * ----------------
+ */
+static Scan *
+_copyScan(Scan *from)
+{
+ Scan *newnode = makeNode(Scan);
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+ CopyPlanFields((Plan*)from, (Plan*)newnode);
+ CopyScanFields(from, newnode);
+
+ return newnode;
+}
+
+/* ----------------
+ * _copySeqScan
+ * ----------------
+ */
+static SeqScan *
+_copySeqScan(SeqScan *from)
+{
+ SeqScan *newnode = makeNode(SeqScan);
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+ CopyPlanFields((Plan*)from, (Plan*)newnode);
+ CopyScanFields((Scan*)from, (Scan*)newnode);
+
+ return newnode;
+}
+
+/* ----------------
+ * _copyIndexScan
+ * ----------------
+ */
+static IndexScan *
+_copyIndexScan(IndexScan *from)
+{
+ IndexScan *newnode = makeNode(IndexScan);
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+ CopyPlanFields((Plan*)from, (Plan*)newnode);
+ CopyScanFields((Scan*)from, (Scan*)newnode);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ newnode->indxid = listCopy(from->indxid);
+ Node_Copy(from, newnode, indxqual);
+ Node_Copy(from, newnode, indxstate);
+
+ return newnode;
+}
+
+/* ----------------
+ * CopyJoinFields
+ *
+ * This function copies the fields of the Join node. It is used by
+ * all the copy functions for classes which inherit from Join.
+ * ----------------
+ */
+static void
+CopyJoinFields(Join *from, Join *newnode)
+{
+ /* nothing extra */
+ return;
+}
+
+
+/* ----------------
+ * _copyJoin
+ * ----------------
+ */
+static Join *
+_copyJoin(Join *from)
+{
+ Join *newnode = makeNode(Join);
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+ CopyPlanFields((Plan*)from, (Plan*)newnode);
+ CopyJoinFields(from, newnode);
+
+ return newnode;
+}
+
+
+/* ----------------
+ * _copyNestLoop
+ * ----------------
+ */
+static NestLoop *
+_copyNestLoop(NestLoop *from)
+{
+ NestLoop *newnode = makeNode(NestLoop);
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+ CopyPlanFields((Plan*)from, (Plan*)newnode);
+ CopyJoinFields((Join*)from, (Join*)newnode);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ Node_Copy(from, newnode, nlstate);
+
+ return newnode;
+}
+
+
+/* ----------------
+ * _copyMergeJoin
+ * ----------------
+ */
+static MergeJoin *
+_copyMergeJoin(MergeJoin *from)
+{
+ MergeJoin *newnode = makeNode(MergeJoin);
+ List *newlist;
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+ CopyPlanFields((Plan*)from, (Plan*)newnode);
+ CopyJoinFields((Join*)from, (Join*)newnode);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ Node_Copy(from, newnode, mergeclauses);
+
+ newnode->mergesortop = from->mergesortop;
+ newlist = NIL;
+
+ newnode->mergerightorder = (Oid *)palloc(sizeof(Oid)*2);
+ newnode->mergerightorder[0] = from->mergerightorder[0];
+ newnode->mergerightorder[1] = 0;
+
+ newnode->mergeleftorder = (Oid *)palloc(sizeof(Oid)*2);
+ newnode->mergeleftorder[0] = from->mergeleftorder[0];
+ newnode->mergeleftorder[1] = 0;
+
+ Node_Copy(from, newnode, mergestate);
+
+ return newnode;
+}
+
+/* ----------------
+ * _copyHashJoin
+ * ----------------
+ */
+static HashJoin *
+_copyHashJoin(HashJoin *from)
+{
+ HashJoin *newnode = makeNode(HashJoin);
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+ CopyPlanFields((Plan*)from, (Plan*)newnode);
+ CopyJoinFields((Join*)from, (Join*)newnode);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ Node_Copy(from, newnode, hashclauses);
+
+ newnode->hashjoinop = from->hashjoinop;
+
+ Node_Copy(from, newnode, hashjoinstate);
+
+ newnode->hashjointable = from->hashjointable;
+ newnode->hashjointablekey = from->hashjointablekey;
+ newnode->hashjointablesize = from->hashjointablesize;
+ newnode->hashdone = from->hashdone;
+
+ return newnode;
+}
+
+
+/* ----------------
+ * CopyTempFields
+ *
+ * This function copies the fields of the Temp node. It is used by
+ * all the copy functions for classes which inherit from Temp.
+ * ----------------
+ */
+static void
+CopyTempFields(Temp *from, Temp *newnode)
+{
+ newnode->tempid = from->tempid;
+ newnode->keycount = from->keycount;
+ return;
+}
+
+
+/* ----------------
+ * _copyTemp
+ * ----------------
+ */
+static Temp *
+_copyTemp(Temp *from)
+{
+ Temp *newnode = makeNode(Temp);
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+ CopyPlanFields((Plan*)from, (Plan*)newnode);
+ CopyTempFields(from, newnode);
+
+ return newnode;
+}
+
+/* ----------------
+ * _copyMaterial
+ * ----------------
+ */
+static Material *
+_copyMaterial(Material *from)
+{
+ Material *newnode = makeNode(Material);
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+ CopyPlanFields((Plan*)from, (Plan*)newnode);
+ CopyTempFields((Temp*)from, (Temp*)newnode);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ Node_Copy(from, newnode, matstate);
+
+ return newnode;
+}
+
+
+/* ----------------
+ * _copySort
+ * ----------------
+ */
+static Sort *
+_copySort(Sort *from)
+{
+ Sort *newnode = makeNode(Sort);
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+ CopyPlanFields((Plan*)from, (Plan*)newnode);
+ CopyTempFields((Temp*)from, (Temp*)newnode);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ Node_Copy(from, newnode, sortstate);
+
+ return newnode;
+}
+
+/* ---------------
+ * _copyAgg
+ * --------------
+ */
+static Agg *
+_copyAgg(Agg *from)
+{
+ Agg *newnode = makeNode(Agg);
+ int i;
+
+ CopyPlanFields((Plan*)from, (Plan*)newnode);
+ CopyTempFields((Temp*)from, (Temp*)newnode);
+
+ newnode->numAgg = from->numAgg;
+ newnode->aggs = malloc(sizeof(Aggreg *));
+ for(i=0; i < from->numAgg; i++) {
+ newnode->aggs[i] = copyObject(from->aggs[i]);
+ }
+
+ Node_Copy(from, newnode, aggstate);
+
+ return newnode;
+}
+
+
+/* ----------------
+ * _copyUnique
+ * ----------------
+ */
+static Unique *
+_copyUnique(Unique *from)
+{
+ Unique *newnode = makeNode(Unique);
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+ CopyPlanFields((Plan*)from, (Plan*)newnode);
+ CopyTempFields((Temp*)from, (Temp*)newnode);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ Node_Copy(from, newnode, uniquestate);
+
+ return newnode;
+}
+
+
+/* ----------------
+ * _copyHash
+ * ----------------
+ */
+static Hash *
+_copyHash(Hash *from)
+{
+ Hash *newnode = makeNode(Hash);
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+ CopyPlanFields((Plan*)from, (Plan*)newnode);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ Node_Copy(from, newnode, hashkey);
+ Node_Copy(from, newnode, hashstate);
+
+ newnode->hashtable = from->hashtable;
+ newnode->hashtablekey = from->hashtablekey;
+ newnode->hashtablesize = from->hashtablesize;
+
+ return newnode;
+}
+
+/* ****************************************************************
+ * primnodes.h copy functions
+ * ****************************************************************
+ */
+
+/* ----------------
+ * _copyResdom
+ * ----------------
+ */
+static Resdom *
+_copyResdom(Resdom *from)
+{
+ Resdom *newnode = makeNode(Resdom);
+
+ newnode->resno = from->resno;
+ newnode->restype = from->restype;
+ newnode->reslen = from->reslen;
+
+ if (from->resname != NULL) {
+ newnode->resname = palloc(strlen(from->resname)+1);
+ strcpy(newnode->resname, from->resname);
+ } else
+ newnode->resname = (char*) NULL;
+
+ newnode->reskey = from->reskey;
+ newnode->reskeyop = from->reskeyop;
+ newnode->resjunk = from->resjunk;
+
+ return newnode;
+}
+
+static Fjoin *
+_copyFjoin(Fjoin *from)
+{
+ Fjoin *newnode;
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+
+ newnode->fj_initialized = from->fj_initialized;
+ newnode->fj_nNodes = from->fj_nNodes;
+
+ Node_Copy(from, newnode, fj_innerNode);
+
+ newnode->fj_results = (DatumPtr)
+ palloc((from->fj_nNodes)*sizeof(Datum));
+
+ newnode->fj_alwaysDone = (BoolPtr)
+ palloc((from->fj_nNodes)*sizeof(bool));
+
+ memmove(from->fj_results,
+ newnode->fj_results,
+ (from->fj_nNodes)*sizeof(Datum));
+
+ memmove(from->fj_alwaysDone,
+ newnode->fj_alwaysDone,
+ (from->fj_nNodes)*sizeof(bool));
+
+
+ return newnode;
+}
+
+/* ----------------
+ * _copyExpr
+ * ----------------
+ */
+static Expr *
+_copyExpr(Expr *from)
+{
+ Expr *newnode = makeNode(Expr);
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+ newnode->typeOid = from->typeOid;
+ newnode->opType = from->opType;
+
+ Node_Copy(from, newnode, oper);
+ Node_Copy(from, newnode, args);
+
+ return newnode;
+}
+
+/* ----------------
+ * _copyVar
+ * ----------------
+ */
+static Var *
+_copyVar(Var *from)
+{
+ Var *newnode = makeNode(Var);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ newnode->varno = from->varno;
+ newnode->varattno = from->varattno;
+ newnode->vartype = from->vartype;
+
+ newnode->varnoold = from->varnoold;
+ newnode->varoattno = from->varoattno;
+
+ return newnode;
+}
+
+/* ----------------
+ * _copyOper
+ * ----------------
+ */
+static Oper *
+_copyOper(Oper *from)
+{
+ Oper *newnode = makeNode(Oper);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ newnode->opno = from->opno;
+ newnode->opid = from->opid;
+ newnode->opresulttype = from->opresulttype;
+ newnode->opsize = from->opsize;
+
+ /*
+ * NOTE: shall we copy the cache structure or just the pointer ?
+ * Alternatively we can set 'op_fcache' to NULL, in which
+ * case the executor will initialize it when it needs it...
+ */
+ newnode->op_fcache = from->op_fcache;
+
+ return newnode;
+}
+
+/* ----------------
+ * _copyConst
+ * ----------------
+ */
+static Const *
+_copyConst(Const *from)
+{
+ static Oid cached_type;
+ static bool cached_typbyval;
+
+ Const *newnode = makeNode(Const);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ newnode->consttype = from->consttype;
+ newnode->constlen = from->constlen;
+
+ /* ----------------
+ * XXX super cheesy hack until parser/planner
+ * puts in the right values here.
+ * ----------------
+ */
+ if (cached_type != from->consttype) {
+ HeapTuple typeTuple;
+ TypeTupleForm typeStruct;
+
+ /* ----------------
+ * get the type tuple corresponding to the paramList->type,
+ * If this fails, returnValue has been pre-initialized
+ * to "null" so we just return it.
+ * ----------------
+ */
+ typeTuple = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(from->consttype),
+ 0,0,0);
+
+ /* ----------------
+ * get the type length and by-value from the type tuple and
+ * save the information in our one element cache.
+ * ----------------
+ */
+ Assert(PointerIsValid(typeTuple));
+
+ typeStruct = (TypeTupleForm) GETSTRUCT(typeTuple);
+ cached_typbyval = (typeStruct)->typbyval ? true : false ;
+ cached_type = from->consttype;
+ }
+
+ from->constbyval = cached_typbyval;
+
+ if (!from->constisnull) {
+ /* ----------------
+ * copying the Datum in a const node is a bit trickier
+ * because it might be a pointer and it might also be of
+ * variable length...
+ * ----------------
+ */
+ if (from->constbyval == true) {
+ /* ----------------
+ * passed by value so just copy the datum.
+ * ----------------
+ */
+ newnode->constvalue = from->constvalue;
+ } else {
+ /* ----------------
+ * not passed by value. datum contains a pointer.
+ * ----------------
+ */
+ if (from->constlen != -1) {
+ /* ----------------
+ * fixed length structure
+ * ----------------
+ */
+ newnode->constvalue = PointerGetDatum(palloc(from->constlen));
+ memmove((char*)newnode->constvalue,
+ (char*)from->constvalue, from->constlen);
+ } else {
+ /* ----------------
+ * variable length structure. here the length is stored
+ * in the first int pointed to by the constval.
+ * ----------------
+ */
+ int length;
+ length = *((int *) from->constvalue);
+ newnode->constvalue = PointerGetDatum(palloc(length));
+ memmove((char*)newnode->constvalue,
+ (char*)from->constvalue, length);
+ }
+ }
+ }
+ else {
+ newnode->constvalue = from->constvalue;
+ }
+ newnode->constisnull = from->constisnull;
+ newnode->constbyval = from->constbyval;
+
+ return newnode;
+}
+
+/* ----------------
+ * _copyParam
+ * ----------------
+ */
+static Param *
+_copyParam(Param *from)
+{
+ Param *newnode = makeNode(Param);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ newnode->paramkind = from->paramkind;
+ newnode->paramid = from->paramid;
+
+ if (from->paramname != NULL) {
+ newnode->paramname = pstrdup(from->paramname);
+ } else
+ newnode->paramname = (char*)NULL;
+
+ newnode->paramtype = from->paramtype;
+ Node_Copy(from, newnode, param_tlist);
+
+ return newnode;
+}
+
+/* ----------------
+ * _copyFunc
+ * ----------------
+ */
+static Func *
+_copyFunc(Func *from)
+{
+ Func *newnode = makeNode(Func);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ newnode->funcid = from->funcid;
+ newnode->functype = from->functype;
+ newnode->funcisindex = from->funcisindex;
+ newnode->funcsize = from->funcsize;
+ newnode->func_fcache = from->func_fcache;
+ Node_Copy(from, newnode, func_tlist);
+ Node_Copy(from, newnode, func_planlist);
+
+ return newnode;
+}
+
+/* ----------------
+ * _copyAggreg
+ * ----------------
+ */
+static Aggreg *
+_copyAggreg(Aggreg *from)
+{
+ Aggreg *newnode = makeNode(Aggreg);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ newnode->aggname = pstrdup(from->aggname);
+ newnode->basetype = from->basetype;
+ newnode->aggtype = from->aggtype;
+
+ Node_Copy(from, newnode, target);
+
+ newnode->aggno = from->aggno;
+
+ return newnode;
+}
+
+static Array *
+_copyArray(Array *from)
+{
+ Array *newnode = makeNode(Array);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ newnode->arrayelemtype = from->arrayelemtype;
+ newnode->arrayelemlength = from->arrayelemlength;
+ newnode->arrayelembyval = from->arrayelembyval;
+ newnode->arrayndim = from->arrayndim;
+ newnode->arraylow = from->arraylow;
+ newnode->arrayhigh = from->arrayhigh;
+ newnode->arraylen = from->arraylen;
+
+ return newnode;
+}
+
+static ArrayRef *
+_copyArrayRef(ArrayRef *from)
+{
+ ArrayRef *newnode = makeNode(ArrayRef);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ newnode->refelemtype = from->refelemtype;
+ newnode->refattrlength = from->refattrlength;
+ newnode->refelemlength = from->refelemlength;
+ newnode->refelembyval = from->refelembyval;
+
+ Node_Copy(from,newnode,refupperindexpr);
+ Node_Copy(from,newnode,reflowerindexpr);
+ Node_Copy(from,newnode,refexpr);
+ Node_Copy(from,newnode,refassgnexpr);
+
+ return newnode;
+}
+
+/* ****************************************************************
+ * relation.h copy functions
+ * ****************************************************************
+ */
+
+/* ----------------
+ * _copyRel
+ * ----------------
+ */
+/*
+ ** when you change this, also make sure to fix up xfunc_copyRel in
+ ** planner/path/xfunc.c accordingly!!!
+ ** -- JMH, 8/2/93
+ */
+static Rel *
+_copyRel(Rel *from)
+{
+ Rel *newnode = makeNode(Rel);
+ int i, len;
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ newnode->relids = listCopy(from->relids);
+
+ newnode->indexed = from->indexed;
+ newnode->pages = from->pages;
+ newnode->tuples = from->tuples;
+ newnode->size = from->size;
+ newnode->width = from->width;
+ newnode->indproc = from->indproc;
+
+ Node_Copy(from, newnode, targetlist);
+ Node_Copy(from, newnode, pathlist);
+ Node_Copy(from, newnode, unorderedpath);
+ Node_Copy(from, newnode, cheapestpath);
+ newnode->pruneable = from->pruneable;
+ newnode->relam = from->relam;
+
+ if (from->classlist) {
+ for(len=0; from->classlist[len]!=0; len++)
+ ;
+ newnode->classlist = (Oid *)palloc(sizeof(Oid) * (len+1));
+ for(i=0; i < len; i++) {
+ newnode->classlist[i] = from->classlist[i];
+ }
+ newnode->classlist[len] = 0;
+ }
+
+ if (from->indexkeys) {
+ for(len=0; from->indexkeys[len]!=0; len++)
+ ;
+ newnode->indexkeys = (int *)palloc(sizeof(int) * (len+1));
+ for(i=0; i < len; i++) {
+ newnode->indexkeys[i] = from->indexkeys[i];
+ }
+ newnode->indexkeys[len] = 0;
+ }
+
+ if (from->ordering) {
+ for(len=0; from->ordering[len]!=0; len++)
+ ;
+ newnode->ordering = (Oid *)palloc(sizeof(Oid) * (len+1));
+ for(i=0; i < len; i++) {
+ newnode->ordering[i] = from->ordering[i];
+ }
+ newnode->ordering[len] = 0;
+ }
+
+ Node_Copy(from, newnode, clauseinfo);
+ Node_Copy(from, newnode, joininfo);
+ Node_Copy(from, newnode, innerjoin);
+ Node_Copy(from, newnode, superrels);
+
+ return newnode;
+}
+
+/* ----------------
+ * CopyPathFields
+ *
+ * This function copies the fields of the Path node. It is used by
+ * all the copy functions for classes which inherit from Path.
+ * ----------------
+ */
+static void
+CopyPathFields(Path *from, Path *newnode)
+{
+ newnode->pathtype = from->pathtype;
+ /* Modify the next line, since it causes the copying to cycle
+ (i.e. the parent points right back here!
+ -- JMH, 7/7/92.
+ Old version:
+ Node_Copy(from, newnode, parent);
+ */
+ newnode->parent = from->parent;
+
+ newnode->path_cost = from->path_cost;
+
+ newnode->p_ordering.ordtype = from->p_ordering.ordtype;
+ if (from->p_ordering.ordtype == SORTOP_ORDER) {
+ int len, i;
+ Oid *ordering = from->p_ordering.ord.sortop;
+
+ if (ordering) {
+ for(len=0; ordering[len]!=0; len++)
+ ;
+ newnode->p_ordering.ord.sortop =
+ (Oid *)palloc(sizeof(Oid) * (len+1));
+ for(i=0; i < len; i++) {
+ newnode->p_ordering.ord.sortop[i] = ordering[i];
+ }
+ newnode->p_ordering.ord.sortop[len] = 0;
+ } else {
+ newnode->p_ordering.ord.sortop = NULL;
+ }
+ } else {
+ Node_Copy(from, newnode, p_ordering.ord.merge);
+ }
+
+ Node_Copy(from, newnode, keys);
+
+ newnode->outerjoincost = from->outerjoincost;
+
+ newnode->joinid = listCopy(from->joinid);
+ Node_Copy(from, newnode, locclauseinfo);
+}
+
+/* ----------------
+ * _copyPath
+ * ----------------
+ */
+static Path *
+_copyPath(Path *from)
+{
+ Path *newnode = makeNode(Path);
+
+ CopyPathFields(from, newnode);
+
+ return newnode;
+}
+
+/* ----------------
+ * _copyIndexPath
+ * ----------------
+ */
+static IndexPath *
+_copyIndexPath(IndexPath *from)
+{
+ IndexPath *newnode = makeNode(IndexPath);
+
+ /* ----------------
+ * copy the node superclass fields
+ * ----------------
+ */
+ CopyPathFields((Path*)from, (Path*)newnode);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ newnode->indexid = listCopy(from->indexid);
+ Node_Copy(from, newnode, indexqual);
+
+ return newnode;
+}
+
+/* ----------------
+ * CopyJoinPathFields
+ *
+ * This function copies the fields of the JoinPath node. It is used by
+ * all the copy functions for classes which inherit from JoinPath.
+ * ----------------
+ */
+static void
+CopyJoinPathFields(JoinPath *from, JoinPath *newnode)
+{
+ Node_Copy(from, newnode, pathclauseinfo);
+ Node_Copy(from, newnode, outerjoinpath);
+ Node_Copy(from, newnode, innerjoinpath);
+}
+
+/* ----------------
+ * _copyJoinPath
+ * ----------------
+ */
+static JoinPath *
+_copyJoinPath(JoinPath *from)
+{
+ JoinPath *newnode = makeNode(JoinPath);
+
+ /* ----------------
+ * copy the node superclass fields
+ * ----------------
+ */
+ CopyPathFields((Path*)from, (Path*)newnode);
+ CopyJoinPathFields(from, newnode);
+
+ return newnode;
+}
+
+/* ----------------
+ * _copyMergePath
+ * ----------------
+ */
+static MergePath *
+_copyMergePath(MergePath *from)
+{
+ MergePath *newnode = makeNode(MergePath);
+
+ /* ----------------
+ * copy the node superclass fields
+ * ----------------
+ */
+ CopyPathFields((Path*)from, (Path*)newnode);
+ CopyJoinPathFields((JoinPath*)from, (JoinPath*)newnode);
+
+ /* ----------------
+ * copy the remainder of the node
+ * ----------------
+ */
+ Node_Copy(from, newnode, path_mergeclauses);
+ Node_Copy(from, newnode, outersortkeys);
+ Node_Copy(from, newnode, innersortkeys);
+
+ return newnode;
+}
+
+/* ----------------
+ * _copyHashPath
+ * ----------------
+ */
+static HashPath *
+_copyHashPath(HashPath *from)
+{
+ HashPath *newnode = makeNode(HashPath);
+
+ /* ----------------
+ * copy the node superclass fields
+ * ----------------
+ */
+ CopyPathFields((Path*)from, (Path*)newnode);
+ CopyJoinPathFields((JoinPath*)from, (JoinPath*)newnode);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ Node_Copy(from, newnode, path_hashclauses);
+ Node_Copy(from, newnode, outerhashkeys);
+ Node_Copy(from, newnode, innerhashkeys);
+
+ return newnode;
+}
+
+/* ----------------
+ * _copyOrderKey
+ * ----------------
+ */
+static OrderKey *
+_copyOrderKey(OrderKey *from)
+{
+ OrderKey *newnode = makeNode(OrderKey);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ newnode->attribute_number = from->attribute_number;
+ newnode->array_index = from->array_index;
+
+ return newnode;
+}
+
+
+/* ----------------
+ * _copyJoinKey
+ * ----------------
+ */
+static JoinKey *
+_copyJoinKey(JoinKey *from)
+{
+ JoinKey *newnode = makeNode(JoinKey);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ Node_Copy(from, newnode, outer);
+ Node_Copy(from, newnode, inner);
+
+ return newnode;
+}
+
+/* ----------------
+ * _copyMergeOrder
+ * ----------------
+ */
+static MergeOrder *
+_copyMergeOrder(MergeOrder *from)
+{
+ MergeOrder *newnode = makeNode(MergeOrder);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ newnode->join_operator = from->join_operator;
+ newnode->left_operator = from->left_operator;
+ newnode->right_operator = from->right_operator;
+ newnode->left_type = from->left_type;
+ newnode->right_type = from->right_type;
+
+ return newnode;
+}
+
+/* ----------------
+ * _copyCInfo
+ * ----------------
+ */
+static CInfo *
+_copyCInfo(CInfo *from)
+{
+ CInfo *newnode = makeNode(CInfo);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ Node_Copy(from, newnode, clause);
+
+ newnode->selectivity = from->selectivity;
+ newnode->notclause = from->notclause;
+
+ Node_Copy(from, newnode, indexids);
+ Node_Copy(from, newnode, mergesortorder);
+ newnode->hashjoinoperator = from->hashjoinoperator;
+ newnode->cinfojoinid = listCopy(from->cinfojoinid);
+
+ return newnode;
+}
+
+/* ----------------
+ * CopyJoinMethodFields
+ *
+ * This function copies the fields of the JoinMethod node. It is used by
+ * all the copy functions for classes which inherit from JoinMethod.
+ * ----------------
+ */
+static void
+CopyJoinMethodFields(JoinMethod *from, JoinMethod *newnode)
+{
+ Node_Copy(from, newnode, jmkeys);
+ Node_Copy(from, newnode, clauses);
+ return;
+}
+
+/* ----------------
+ * _copyJoinMethod
+ * ----------------
+ */
+static JoinMethod *
+_copyJoinMethod(JoinMethod *from)
+{
+ JoinMethod *newnode = makeNode(JoinMethod);
+
+ CopyJoinMethodFields(from, newnode);
+
+ return newnode;
+}
+
+/* ----------------
+ * _copyHInfo
+ * ----------------
+ */
+static HInfo *
+_copyHInfo(HInfo *from)
+{
+ HInfo *newnode = makeNode(HInfo);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ newnode->hashop = from->hashop;
+
+ return newnode;
+}
+
+/* ----------------
+ * _copyMInfo
+ * ----------------
+ */
+static MInfo *
+_copyMInfo(MInfo *from)
+{
+ MInfo *newnode = makeNode(MInfo);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ Node_Copy(from, newnode, m_ordering);
+
+ return newnode;
+}
+
+/* ----------------
+ * _copyJInfo
+ * ----------------
+ */
+static JInfo *
+_copyJInfo(JInfo *from)
+{
+ JInfo *newnode = makeNode(JInfo);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ newnode->otherrels = listCopy(from->otherrels);
+ Node_Copy(from, newnode, jinfoclauseinfo);
+
+ newnode->mergesortable = from->mergesortable;
+ newnode->hashjoinable = from->hashjoinable;
+ newnode->inactive = from->inactive;
+
+ return newnode;
+}
+
+static Iter *
+_copyIter(Iter *from)
+{
+ Iter *newnode = makeNode(Iter);
+
+ Node_Copy(from, newnode, iterexpr);
+ newnode->itertype = from->itertype;
+
+ return newnode;
+}
+
+static Stream *
+_copyStream(Stream *from)
+{
+ Stream *newnode = makeNode(Stream);
+
+ newnode->pathptr = from->pathptr;
+ newnode->cinfo = from->cinfo;
+ newnode->clausetype = from->clausetype;
+ newnode->groupup = from->groupup;
+ newnode->groupcost = from->groupcost;
+ newnode->groupsel = from->groupsel;
+ newnode->upstream = (StreamPtr)NULL; /* only copy nodes downwards! */
+ Node_Copy(from, newnode, downstream);
+ if (newnode->downstream)
+ ((Stream*)newnode->downstream)->upstream = (Stream*)newnode;
+
+ return newnode;
+}
+
+/* ****************
+ * parsenodes.h routines have no copy functions
+ * ****************
+ */
+
+static TargetEntry *
+_copyTargetEntry(TargetEntry *from)
+{
+ TargetEntry *newnode = makeNode(TargetEntry);
+
+ Node_Copy(from, newnode, resdom);
+ Node_Copy(from, newnode, fjoin);
+ Node_Copy(from, newnode, expr);
+ return newnode;
+}
+
+static RangeTblEntry *
+_copyRangeTblEntry(RangeTblEntry *from)
+{
+ RangeTblEntry *newnode = makeNode(RangeTblEntry);
+
+ *newnode = *from; /* ??? quick hack, be careful */
+
+ return newnode;
+}
+
+static SortClause *
+_copySortClause(SortClause *from)
+{
+ SortClause *newnode = makeNode(SortClause);
+
+ Node_Copy(from, newnode, resdom);
+ newnode->opoid = from->opoid;
+
+ return newnode;
+}
+
+static Query *
+_copyQuery(Query *from)
+{
+ Query *newnode = makeNode(Query);
+
+ newnode->commandType = from->commandType;
+ newnode->resultRelation = from->resultRelation;
+ newnode->into = from->into;
+ newnode->isPortal = from->isPortal;
+ Node_Copy(from, newnode, rtable);
+ if (from->utilityStmt && nodeTag(from->utilityStmt) == T_NotifyStmt) {
+ NotifyStmt *from_notify = (NotifyStmt*)from->utilityStmt;
+ NotifyStmt *n = makeNode(NotifyStmt);
+ int length = strlen(from_notify->relname);
+
+ n->relname = palloc(length + 1);
+ strcpy(n->relname,from_notify->relname);
+ newnode->utilityStmt = (Node*)n;
+ }
+ if (from->uniqueFlag) {
+ newnode->uniqueFlag = (char*)palloc(strlen(from->uniqueFlag)+1);
+ strcpy(newnode->uniqueFlag, from->uniqueFlag);
+ }
+ else
+ newnode->uniqueFlag = NULL;
+ Node_Copy(from, newnode, sortClause);
+ Node_Copy(from, newnode, targetList);
+ Node_Copy(from, newnode, qual);
+
+ return newnode;
+}
+
+
+/* ****************
+ * mnodes.h routines have no copy functions
+ * ****************
+ */
+
+/* ****************************************************************
+ * pg_list.h copy functions
+ * ****************************************************************
+ */
+
+static Value *
+_copyValue(Value *from)
+{
+ Value *newnode = makeNode(Value);
+
+ newnode->type = from->type;
+ switch(from->type) {
+ case T_String:
+ newnode->val.str = pstrdup(from->val.str);
+ break;
+ case T_Integer:
+ newnode->val.ival = from->val.ival;
+ break;
+ case T_Float:
+ newnode->val.dval = from->val.dval;
+ break;
+ default:
+ break;
+ }
+ return newnode;
+}
+
+/* ----------------
+ * copyObject returns a copy of the node or list. If it is a list, it
+ * recursively copies its items.
+ * ----------------
+ */
+void *
+copyObject(void *from)
+{
+ void *retval;
+
+ if (from==NULL)
+ return NULL;
+ switch(nodeTag(from)) {
+ /*
+ * PLAN NODES
+ */
+ case T_Plan:
+ retval = _copyPlan(from);
+ break;
+ case T_Existential:
+ retval = _copyExistential(from);
+ break;
+ case T_Result:
+ retval = _copyResult(from);
+ break;
+ case T_Append:
+ retval = _copyAppend(from);
+ break;
+ case T_Scan:
+ retval = _copyScan(from);
+ break;
+ case T_SeqScan:
+ retval = _copySeqScan(from);
+ break;
+ case T_IndexScan:
+ retval = _copyIndexScan(from);
+ break;
+ case T_Join:
+ retval = _copyJoin(from);
+ break;
+ case T_NestLoop:
+ retval = _copyNestLoop(from);
+ break;
+ case T_MergeJoin:
+ retval = _copyMergeJoin(from);
+ break;
+ case T_HashJoin:
+ retval = _copyHashJoin(from);
+ break;
+ case T_Temp:
+ retval = _copyTemp(from);
+ break;
+ case T_Material:
+ retval = _copyMaterial(from);
+ break;
+ case T_Sort:
+ retval = _copySort(from);
+ break;
+ case T_Agg:
+ retval = _copyAgg(from);
+ break;
+ case T_Unique:
+ retval = _copyUnique(from);
+ break;
+ case T_Hash:
+ retval = _copyHash(from);
+ break;
+
+ /*
+ * PRIMITIVE NODES
+ */
+ case T_Resdom:
+ retval = _copyResdom(from);
+ break;
+ case T_Fjoin:
+ retval = _copyFjoin(from);
+ break;
+ case T_Expr:
+ retval = _copyExpr(from);
+ break;
+ case T_Var:
+ retval = _copyVar(from);
+ break;
+ case T_Oper:
+ retval = _copyOper(from);
+ break;
+ case T_Const:
+ retval = _copyConst(from);
+ break;
+ case T_Param:
+ retval = _copyParam(from);
+ break;
+ case T_Func:
+ retval = _copyFunc(from);
+ break;
+ case T_Array:
+ retval = _copyArray(from);
+ break;
+ case T_ArrayRef:
+ retval = _copyArrayRef(from);
+ break;
+ case T_Aggreg:
+ retval = _copyAggreg(from);
+ break;
+ /*
+ * RELATION NODES
+ */
+ case T_Rel:
+ retval = _copyRel(from);
+ break;
+ case T_Path:
+ retval = _copyPath(from);
+ break;
+ case T_IndexPath:
+ retval = _copyIndexPath(from);
+ break;
+ case T_JoinPath:
+ retval = _copyJoinPath(from);
+ break;
+ case T_MergePath:
+ retval = _copyMergePath(from);
+ break;
+ case T_HashPath:
+ retval = _copyHashPath(from);
+ break;
+ case T_OrderKey:
+ retval = _copyOrderKey(from);
+ break;
+ case T_JoinKey:
+ retval = _copyJoinKey(from);
+ break;
+ case T_MergeOrder:
+ retval = _copyMergeOrder(from);
+ break;
+ case T_CInfo:
+ retval = _copyCInfo(from);
+ break;
+ case T_JoinMethod:
+ retval = _copyJoinMethod(from);
+ break;
+ case T_HInfo:
+ retval = _copyHInfo(from);
+ break;
+ case T_MInfo:
+ retval = _copyMInfo(from);
+ break;
+ case T_JInfo:
+ retval = _copyJInfo(from);
+ break;
+ case T_Iter:
+ retval = _copyIter(from);
+ break;
+ case T_Stream:
+ retval = _copyStream(from);
+ break;
+
+ /*
+ * PARSE NODES
+ */
+ case T_Query:
+ retval = _copyQuery(from);
+ break;
+ case T_TargetEntry:
+ retval = _copyTargetEntry(from);
+ break;
+ case T_RangeTblEntry:
+ retval = _copyRangeTblEntry(from);
+ break;
+ case T_SortClause:
+ retval = _copySortClause(from);
+ break;
+
+ /*
+ * VALUE NODES
+ */
+ case T_Integer: case T_String: case T_Float:
+ retval = _copyValue(from);
+ break;
+ case T_List:
+ {
+ List *list=from, *l;
+ List *newlist = NIL, *nl;
+ foreach(l, list) {
+ if (newlist==NIL) {
+ newlist = nl = lcons(copyObject(lfirst(l)),NIL);
+ }else {
+ lnext(nl) = lcons(copyObject(lfirst(l)),NIL);
+ nl = lnext(nl);
+ }
+ }
+ retval = newlist;
+ }
+ break;
+ default:
+ elog(NOTICE, "copyObject: don't know how to copy %d", nodeTag(from));
+ retval = from;
+ break;
+ }
+ return retval;
+}
+
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
new file mode 100644
index 0000000000..25783d2720
--- /dev/null
+++ b/src/backend/nodes/equalfuncs.c
@@ -0,0 +1,703 @@
+/*-------------------------------------------------------------------------
+ *
+ * equalfuncs.c--
+ * equal functions to compare the nodes
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header$
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "nodes/nodes.h"
+#include "nodes/primnodes.h"
+#include "nodes/relation.h"
+#include "nodes/execnodes.h"
+#include "nodes/plannodes.h"
+
+#include "utils/builtins.h" /* for namestrcmp() */
+#include "utils/datum.h"
+#include "utils/elog.h"
+#include "storage/itemptr.h"
+
+/*
+ * Stuff from primnodes.h
+ */
+
+/*
+ * Resdom is a subclass of Node.
+ */
+static bool
+_equalResdom(Resdom *a, Resdom *b)
+{
+ if (a->resno != b->resno)
+ return (false);
+ if (a->restype != b->restype)
+ return (false);
+ if (a->reslen != b->reslen)
+ return (false);
+ if (strcmp(a->resname, b->resname) != 0)
+ return (false);
+ if (a->reskey != b->reskey)
+ return (false);
+ if (a->reskeyop != b->reskeyop)
+ return (false);
+
+ return (true);
+}
+
+static bool
+_equalFjoin(Fjoin *a, Fjoin *b)
+{
+ int nNodes;
+
+ if (a->fj_initialized != b->fj_initialized)
+ return (false);
+ if (a->fj_nNodes != b->fj_nNodes)
+ return (false);
+ if (!equal(a->fj_innerNode, b->fj_innerNode))
+ return (false);
+
+ nNodes = a->fj_nNodes;
+ if (memcmp(a->fj_results, b->fj_results, nNodes*sizeof(Datum)) != 0)
+ return (false);
+ if (memcmp(a->fj_alwaysDone, b->fj_alwaysDone, nNodes*sizeof(bool)) != 0)
+ return (false);
+
+ return(true);
+}
+
+/*
+ * Expr is a subclass of Node.
+ */
+static bool
+_equalExpr(Expr *a, Expr *b)
+{
+ if (a->opType != b->opType)
+ return (false);
+ if (!equal(a->oper, b->oper))
+ return (false);
+ if (!equal(a->args, b->args))
+ return (false);
+
+ return (true);
+}
+
+bool _equalIter(Iter *a, Iter *b)
+{
+ return (equal(a->iterexpr, b->iterexpr));
+}
+
+static bool
+_equalStream(Stream *a, Stream *b)
+{
+ if (a->clausetype != b->clausetype)
+ return(false);
+ if (a->groupup != b->groupup)
+ return(false);
+ if (a->groupcost != b->groupcost)
+ return(false);
+ if (a->groupsel != b->groupsel)
+ return(false);
+ if (!equal(a->pathptr, b->pathptr))
+ return(false);
+ if (!equal(a->cinfo, b->cinfo))
+ return(false);
+ if (!equal(a->upstream, b->upstream))
+ return(false);
+ return(equal(a->downstream, b->downstream));
+}
+
+/*
+ * Var is a subclass of Expr.
+ */
+static bool
+_equalVar(Var *a, Var *b)
+{
+ if (a->varno != b->varno)
+ return (false);
+ if (a->varattno != b->varattno)
+ return (false);
+ if (a->vartype != b->vartype)
+ return (false);
+ if (a->varnoold != b->varnoold)
+ return (false);
+ if (a->varoattno != b->varoattno)
+ return (false);
+
+ return (true);
+}
+
+static bool
+_equalArray(Array *a, Array *b)
+{
+ if (a->arrayelemtype != b->arrayelemtype)
+ return (false);
+ if (a->arrayndim != b->arrayndim)
+ return (false);
+ if (a->arraylow.indx[0] != b->arraylow.indx[0])
+ return (false);
+ if (a->arrayhigh.indx[0] != b->arrayhigh.indx[0])
+ return (false);
+ if (a->arraylen != b->arraylen)
+ return (false);
+ return(TRUE);
+}
+
+static bool
+_equalArrayRef(ArrayRef *a, ArrayRef *b)
+{
+ if (a->refelemtype != b->refelemtype)
+ return (false);
+ if (a->refattrlength != b->refattrlength)
+ return (false);
+ if (a->refelemlength != b->refelemlength)
+ return (false);
+ if (a->refelembyval != b->refelembyval)
+ return (false);
+ if (!equal(a->refupperindexpr, b->refupperindexpr))
+ return (false);
+ if (!equal(a->reflowerindexpr, b->reflowerindexpr))
+ return (false);
+ if (!equal(a->refexpr, b->refexpr))
+ return (false);
+ return (equal(a->refassgnexpr, b->refassgnexpr));
+}
+
+/*
+ * Oper is a subclass of Expr.
+ */
+static bool
+_equalOper(Oper *a, Oper *b)
+{
+ if (a->opno != b->opno)
+ return (false);
+ if (a->opresulttype != b->opresulttype)
+ return (false);
+
+ return (true);
+}
+
+/*
+ * Const is a subclass of Expr.
+ */
+static bool
+_equalConst(Const *a, Const *b)
+{
+ /*
+ ** this function used to do a pointer compare on a and b. That's
+ ** ridiculous. -- JMH, 7/11/92
+ */
+ if (a->consttype != b->consttype)
+ return(false);
+ if (a->constlen != b->constlen)
+ return(false);
+ if (a->constisnull != b->constisnull)
+ return(false);
+ if (a->constbyval != b->constbyval)
+ return(false);
+ return(datumIsEqual(a->constvalue, b->constvalue,
+ a->consttype, a->constbyval, a->constlen));
+}
+
+/*
+ * Param is a subclass of Expr.
+ */
+static bool
+_equalParam(Param *a, Param *b)
+{
+ if (a->paramkind != b->paramkind)
+ return (false);
+ if (a->paramtype != b->paramtype)
+ return (false);
+ if (!equal(a->param_tlist, b->param_tlist))
+ return (false);
+
+ switch (a->paramkind) {
+ case PARAM_NAMED:
+ case PARAM_NEW:
+ case PARAM_OLD:
+ if (strcmp(a->paramname, b->paramname) != 0)
+ return (false);
+ break;
+ case PARAM_NUM:
+ if (a->paramid != b->paramid)
+ return (false);
+ break;
+ case PARAM_INVALID:
+ /*
+ * XXX: Hmmm... What are we supposed to return
+ * in this case ??
+ */
+ return(true);
+ break;
+ default:
+ elog(WARN, "_equalParam: Invalid paramkind value: %d",
+ a->paramkind);
+ }
+
+ return (true);
+}
+
+/*
+ * Func is a subclass of Expr.
+ */
+static bool
+_equalFunc(Func *a, Func *b)
+{
+ if (a->funcid != b->funcid)
+ return (false);
+ if (a->functype != b->functype)
+ return (false);
+ if (a->funcisindex != b->funcisindex)
+ return (false);
+ if (a->funcsize != b->funcsize)
+ return (false);
+ if (!equal(a->func_tlist, b->func_tlist))
+ return (false);
+ if (!equal(a->func_planlist, b->func_planlist))
+ return (false);
+
+ return (true);
+}
+
+/*
+ * CInfo is a subclass of Node.
+ */
+static bool
+_equalCInfo(CInfo *a, CInfo *b)
+{
+ Assert(IsA(a,CInfo));
+ Assert(IsA(b,CInfo));
+
+ if (!equal(a->clause, b->clause))
+ return(false);
+ if (a->selectivity != b->selectivity)
+ return(false);
+ if (a->notclause != b->notclause)
+ return(false);
+#ifdef EqualMergeOrderExists
+ if (!EqualMergeOrder(a->mergesortorder,b->mergesortorder))
+ return(false);
+#endif
+ if(a->hashjoinoperator != b->hashjoinoperator)
+ return(false);
+ return(equal((a->indexids),
+ (b->indexids)));
+}
+
+static bool
+_equalJoinMethod(JoinMethod *a, JoinMethod *b)
+{
+ Assert(IsA(a,JoinMethod));
+ Assert(IsA(b,JoinMethod));
+
+ if (!equal((a->jmkeys),
+ (b->jmkeys)))
+ return(false);
+ if (!equal((a->clauses),
+ (b->clauses)))
+ return(false);
+ return(true);
+}
+
+static bool
+_equalPath(Path *a, Path *b)
+{
+ if (a->pathtype != b->pathtype)
+ return(false);
+ if (a->parent != b->parent)
+ return(false);
+ /*
+ if (a->path_cost != b->path_cost)
+ return(false);
+ */
+ if (a->p_ordering.ordtype == SORTOP_ORDER) {
+ int i = 0;
+ if (a->p_ordering.ord.sortop==NULL ||
+ b->p_ordering.ord.sortop==NULL) {
+
+ if (a->p_ordering.ord.sortop != b->p_ordering.ord.sortop)
+ return false;
+ } else {
+ while(a->p_ordering.ord.sortop[i]!=0 &&
+ b->p_ordering.ord.sortop[i]!=0) {
+ if (a->p_ordering.ord.sortop[i] != b->p_ordering.ord.sortop[i])
+ return false;
+ i++;
+ }
+ if (a->p_ordering.ord.sortop[i]!=0 ||
+ b->p_ordering.ord.sortop[i]!=0)
+ return false;
+ }
+ } else {
+ if (!equal((a->p_ordering.ord.merge),
+ (b->p_ordering.ord.merge)))
+ return(false);
+ }
+ if (!equal((a->keys),
+ (b->keys)))
+ return(false);
+ /*
+ if (a->outerjoincost != b->outerjoincost)
+ return(false);
+ */
+ if (!equali((a->joinid),
+ (b->joinid)))
+ return(false);
+ return(true);
+}
+
+static bool
+_equalIndexPath(IndexPath *a, IndexPath *b)
+{
+ if (!_equalPath((Path*)a,(Path*)b))
+ return(false);
+ if (!equali((a->indexid), (b->indexid)))
+ return(false);
+ if (!equal((a->indexqual), (b->indexqual)))
+ return(false);
+ return(true);
+}
+
+static bool
+_equalJoinPath(JoinPath *a,JoinPath *b)
+{
+ Assert(IsA_JoinPath(a));
+ Assert(IsA_JoinPath(b));
+
+ if (!_equalPath((Path*)a,(Path*)b))
+ return(false);
+ if (!equal((a->pathclauseinfo), (b->pathclauseinfo)))
+ return(false);
+ if (!equal((a->outerjoinpath), (b->outerjoinpath)))
+ return(false);
+ if (!equal((a->innerjoinpath), (b->innerjoinpath)))
+ return(false);
+ return(true);
+}
+
+static bool
+_equalMergePath(MergePath *a, MergePath *b)
+{
+ Assert(IsA(a,MergePath));
+ Assert(IsA(b,MergePath));
+
+ if (!_equalJoinPath((JoinPath*)a,(JoinPath*)b))
+ return(false);
+ if (!equal((a->path_mergeclauses), (b->path_mergeclauses)))
+ return(false);
+ if (!equal((a->outersortkeys), (b->outersortkeys)))
+ return(false);
+ if (!equal((a->innersortkeys), (b->innersortkeys)))
+ return(false);
+ return(true);
+}
+
+static bool
+_equalHashPath(HashPath *a, HashPath *b)
+{
+ Assert(IsA(a,HashPath));
+ Assert(IsA(b,HashPath));
+
+ if (!_equalJoinPath((JoinPath*)a,(JoinPath*)b))
+ return(false);
+ if (!equal((a->path_hashclauses), (b->path_hashclauses)))
+ return(false);
+ if (!equal((a->outerhashkeys), (b->outerhashkeys)))
+ return(false);
+ if (!equal((a->innerhashkeys), (b->innerhashkeys)))
+ return(false);
+ return(true);
+}
+
+static bool
+_equalJoinKey(JoinKey *a, JoinKey *b)
+{
+ Assert(IsA(a,JoinKey));
+ Assert(IsA(b,JoinKey));
+
+ if (!equal((a->outer),(b->outer)))
+ return(false);
+ if (!equal((a->inner),(b->inner)))
+ return(false);
+ return(true);
+}
+
+static bool
+_equalMergeOrder(MergeOrder *a, MergeOrder *b)
+{
+ if (a == (MergeOrder*)NULL && b == (MergeOrder*)NULL)
+ return(true);
+ Assert(IsA(a,MergeOrder));
+ Assert(IsA(b,MergeOrder));
+
+ if (a->join_operator != b->join_operator)
+ return(false);
+ if (a->left_operator != b->left_operator)
+ return(false);
+ if (a->right_operator != b->right_operator)
+ return(false);
+ if (a->left_type != b->left_type)
+ return(false);
+ if (a->right_type != b->right_type)
+ return(false);
+ return(true);
+}
+
+static bool
+_equalHInfo(HInfo *a, HInfo *b)
+{
+ Assert(IsA(a,HInfo));
+ Assert(IsA(b,HInfo));
+
+ if (a->hashop != b->hashop)
+ return(false);
+ return(true);
+}
+
+/* XXX This equality function is a quick hack, should be
+ * fixed to compare all fields.
+ */
+static bool
+_equalIndexScan(IndexScan *a, IndexScan *b)
+{
+ Assert(IsA(a,IndexScan));
+ Assert(IsA(b,IndexScan));
+
+ /*
+ if(a->scan.plan.cost != b->scan.plan.cost)
+ return(false);
+ */
+
+ if (!equal((a->indxqual),(b->indxqual)))
+ return(false);
+
+ if (a->scan.scanrelid != b->scan.scanrelid)
+ return(false);
+
+ if (!equali((a->indxid),(b->indxid)))
+ return(false);
+ return(true);
+}
+
+static bool
+_equalJInfo(JInfo *a, JInfo *b)
+{
+ Assert(IsA(a,JInfo));
+ Assert(IsA(b,JInfo));
+ if (!equal((a->otherrels),(b->otherrels)))
+ return(false);
+ if (!equal((a->jinfoclauseinfo),(b->jinfoclauseinfo)))
+ return(false);
+ if (a->mergesortable != b->mergesortable)
+ return(false);
+ if (a->hashjoinable != b->hashjoinable)
+ return(false);
+ return(true);
+}
+
+/*
+ * Stuff from execnodes.h
+ */
+
+/*
+ * EState is a subclass of Node.
+ */
+static bool
+_equalEState(EState *a, EState *b)
+{
+ if (a->es_direction != b->es_direction)
+ return (false);
+
+ if (!equal(a->es_range_table, b->es_range_table))
+ return (false);
+
+ if (a->es_result_relation_info != b->es_result_relation_info)
+ return (false);
+
+ return (true);
+}
+
+
+/*
+ * equal -- are two lists equal?
+ *
+ * This is a comparison by value. It would be simpler to write it
+ * to be recursive, but it should run faster if we iterate.
+ */
+static bool
+_equalValue(Value *a, Value *b)
+{
+ if (a->type != b->type)
+ return (false);
+
+ switch(a->type) {
+ case T_String:
+ return strcmp(a->val.str, b->val.str);
+ case T_Integer:
+ return (a->val.ival==b->val.ival);
+ case T_Float:
+ return (a->val.dval==b->val.dval);
+ default:
+ break;
+ }
+
+ return (true);
+}
+
+/*
+ * equal--
+ * returns whether two nodes are equal
+ */
+bool
+equal(void *a, void *b)
+{
+ bool retval;
+
+ if (a == b)
+ return(true);
+ /*
+ * note that a!=b, so only one of them can be NULL
+ */
+ if (a==NULL || b==NULL)
+ return (false);
+ /*
+ * are they the same type of nodes?
+ */
+ if (nodeTag(a)!=nodeTag(b))
+ return (false);
+
+ switch(nodeTag(a)) {
+ case T_Resdom:
+ retval = _equalResdom(a, b);
+ break;
+ case T_Fjoin:
+ retval = _equalFjoin(a, b);
+ break;
+ case T_Expr:
+ retval = _equalExpr(a, b);
+ break;
+ case T_Iter:
+ retval = _equalIter(a, b);
+ break;
+ case T_Stream:
+ retval = _equalStream(a, b);
+ break;
+ case T_Var:
+ retval = _equalVar(a, b);
+ break;
+ case T_Array:
+ retval = _equalArray(a, b);
+ break;
+ case T_ArrayRef:
+ retval = _equalArrayRef(a, b);
+ break;
+ case T_Oper:
+ retval = _equalOper(a, b);
+ break;
+ case T_Const:
+ retval = _equalConst(a, b);
+ break;
+ case T_Param:
+ retval = _equalParam(a, b);
+ break;
+ case T_Func:
+ retval = _equalFunc(a, b);
+ break;
+ case T_CInfo:
+ retval = _equalCInfo(a, b);
+ break;
+ case T_JoinMethod:
+ retval = _equalJoinMethod(a, b);
+ break;
+ case T_Path:
+ retval = _equalPath(a, b);
+ break;
+ case T_IndexPath:
+ retval = _equalIndexPath(a, b);
+ break;
+ case T_JoinPath:
+ retval = _equalJoinPath(a, b);
+ break;
+ case T_MergePath:
+ retval = _equalMergePath(a, b);
+ break;
+ case T_HashPath:
+ retval = _equalHashPath(a, b);
+ break;
+ case T_JoinKey:
+ retval = _equalJoinKey(a, b);
+ break;
+ case T_MergeOrder:
+ retval = _equalMergeOrder(a, b);
+ break;
+ case T_HInfo:
+ retval = _equalHInfo(a, b);
+ break;
+ case T_IndexScan:
+ retval = _equalIndexScan(a, b);
+ break;
+ case T_JInfo:
+ retval = _equalJInfo(a, b);
+ break;
+ case T_EState:
+ retval = _equalEState(a, b);
+ break;
+ case T_Integer: case T_String: case T_Float:
+ retval = _equalValue(a, b);
+ break;
+ case T_List:
+ {
+ List *la = (List*)a;
+ List *lb = (List*)b;
+ List *l;
+
+ if (a==NULL && b==NULL)
+ return (true);
+ if (length(a)!=length(b))
+ return (false);
+ foreach(l, la) {
+ if (!equal(lfirst(l), lfirst(lb)))
+ return (false);
+ lb = lnext(lb);
+ }
+ retval = true;
+ }
+ break;
+ default:
+ elog(NOTICE, "equal: don't know whether nodes of type %d are equal",
+ nodeTag(a));
+ break;
+ }
+
+ return retval;
+}
+
+/*
+ * equali--
+ * compares two lists of integers
+ *
+ * XXX temp hack. needs something like T_IntList
+ */
+bool equali(List *a, List *b)
+{
+ List *la = (List*)a;
+ List *lb = (List*)b;
+ List *l;
+
+ if (a==NULL && b==NULL)
+ return (true);
+ if (length(a)!=length(b))
+ return (false);
+ foreach(l, la) {
+ if (lfirsti(l) != lfirsti(lb))
+ return (false);
+ lb = lnext(lb);
+ }
+ return true;
+}
diff --git a/src/backend/nodes/execnodes.h b/src/backend/nodes/execnodes.h
new file mode 100644
index 0000000000..2790f670de
--- /dev/null
+++ b/src/backend/nodes/execnodes.h
@@ -0,0 +1,689 @@
+/*-------------------------------------------------------------------------
+ *
+ * execnodes.h--
+ * definitions for executor state nodes
+ *
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id$
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef EXECNODES_H
+#define EXECNODES_H
+
+#include "postgres.h"
+
+#include "nodes/nodes.h"
+#include "nodes/primnodes.h"
+#include "nodes/pg_list.h"
+
+#include "nodes/memnodes.h"
+
+#include "storage/item.h"
+#include "access/sdir.h"
+#include "access/htup.h"
+#include "access/tupdesc.h"
+#include "access/funcindex.h"
+#include "utils/rel.h"
+#include "access/relscan.h"
+#include "executor/hashjoin.h"
+#include "executor/tuptable.h"
+
+/* ----------------
+ * IndexInfo information
+ *
+ * this class holds the information saying what attributes
+ * are the key attributes for this index. -cim 10/15/89
+ *
+ * NumKeyAttributes number of key attributes for this index
+ * KeyAttributeNumbers array of attribute numbers used as keys
+ * Predicate partial-index predicate for this index
+ * ----------------
+ */
+typedef struct IndexInfo {
+ NodeTag type;
+ int ii_NumKeyAttributes;
+ AttrNumber *ii_KeyAttributeNumbers;
+ FuncIndexInfoPtr ii_FuncIndexInfo;
+ Node *ii_Predicate;
+} IndexInfo;
+
+/* ----------------
+ * RelationInfo information
+ *
+ * whenever we update an existing relation, we have to
+ * update indices on the relation. The RelationInfo class
+ * is used to hold all the information on result relations,
+ * including indices.. -cim 10/15/89
+ *
+ * RangeTableIndex result relation's range table index
+ * RelationDesc relation descriptor for result relation
+ * NumIndices number indices existing on result relation
+ * IndexRelationDescs array of relation descriptors for indices
+ * IndexRelationInfo array of key/attr info for indices
+ * ----------------
+ */
+typedef struct RelationInfo {
+ NodeTag type;
+ Index ri_RangeTableIndex;
+ Relation ri_RelationDesc;
+ int ri_NumIndices;
+ RelationPtr ri_IndexRelationDescs;
+ IndexInfo **ri_IndexRelationInfo;
+} RelationInfo;
+
+/* ----------------
+ * ExprContext
+ *
+ * This class holds the "current context" information
+ * needed to evaluate expressions for doing tuple qualifications
+ * and tuple projections. For example, if an expression refers
+ * to an attribute in the current inner tuple then we need to know
+ * what the current inner tuple is and so we look at the expression
+ * context.
+ * ----------------
+ */
+typedef struct ExprContext {
+ NodeTag type;
+ TupleTableSlot *ecxt_scantuple;
+ TupleTableSlot *ecxt_innertuple;
+ TupleTableSlot *ecxt_outertuple;
+ Relation ecxt_relation;
+ Index ecxt_relid;
+ ParamListInfo ecxt_param_list_info;
+ List *ecxt_range_table;
+ Datum *ecxt_values; /* precomputed values for aggreg */
+ char *ecxt_nulls; /* null flags for aggreg values */
+} ExprContext;
+
+/* ----------------
+ * ProjectionInfo node information
+ *
+ * This is all the information needed to preform projections
+ * on a tuple. Nodes which need to do projections create one
+ * of these. In theory, when a node wants to preform a projection
+ * it should just update this information as necessary and then
+ * call ExecProject(). -cim 6/3/91
+ *
+ * targetlist target list for projection
+ * len length of target list
+ * tupValue array of pointers to projection results
+ * exprContext expression context for ExecTargetList
+ * slot slot to place projection result in
+ * ----------------
+ */
+typedef struct ProjectionInfo {
+ NodeTag type;
+ List *pi_targetlist;
+ int pi_len;
+ Datum *pi_tupValue;
+ ExprContext *pi_exprContext;
+ TupleTableSlot *pi_slot;
+} ProjectionInfo;
+
+/* ----------------
+ * JunkFilter
+ *
+ * this class is used to store information regarding junk attributes.
+ * A junk attribute is an attribute in a tuple that is needed only for
+ * storing intermediate information in the executor, and does not belong
+ * in the tuple proper. For example, when we do a delete or replace
+ * query, the planner adds an entry to the targetlist so that the tuples
+ * returned to ExecutePlan() contain an extra attribute: the t_ctid of
+ * the tuple to be deleted/replaced. This is needed for amdelete() and
+ * amreplace(). In doing a delete this does not make much of a
+ * difference, but in doing a replace we have to make sure we disgard
+ * all the junk in a tuple before calling amreplace(). Otherwise the
+ * inserted tuple will not have the correct schema. This solves a
+ * problem with hash-join and merge-sort replace plans. -cim 10/10/90
+ *
+ * targetList: the original target list (including junk attributes).
+ * length: the length of 'targetList'.
+ * tupType: the tuple descriptor for the "original" tuple
+ * (including the junk attributes).
+ * cleanTargetList: the "clean" target list (junk attributes removed).
+ * cleanLength: the length of 'cleanTargetList'
+ * cleanTupTyp: the tuple descriptor of the "clean" tuple (with
+ * junk attributes removed).
+ * cleanMap: A map with the correspondance between the non junk
+ * attributes of the "original" tuple and the
+ * attributes of the "clean" tuple.
+ * ----------------
+ */
+typedef struct JunkFilter {
+ NodeTag type;
+ List *jf_targetList;
+ int jf_length;
+ TupleDesc jf_tupType;
+ List *jf_cleanTargetList;
+ int jf_cleanLength;
+ TupleDesc jf_cleanTupType;
+ AttrNumber *jf_cleanMap;
+} JunkFilter;
+
+/* ----------------
+ * EState information
+ *
+ * direction direction of the scan
+ *
+ * range_table array of scan relation information
+ *
+ * result_relation_information for update queries
+ *
+ * into_relation_descriptor relation being retrieved "into"
+ *
+ * param_list_info information needed to transform
+ * Param nodes into Const nodes
+ *
+ * BaseId during InitPlan(), each node is
+ * given a number. this is the next
+ * number to be assigned.
+ *
+ * tupleTable this is a pointer to an array
+ * of pointers to tuples used by
+ * the executor at any given moment.
+ *
+ * junkFilter contains information used to
+ * extract junk attributes from a tuple.
+ * (see JunkFilter above)
+ *
+ * refcount local buffer refcounts used in
+ * an ExecMain cycle. this is introduced
+ * to avoid ExecStart's unpinning each
+ * other's buffers when called recursively
+ * ----------------
+ */
+typedef struct EState {
+ NodeTag type;
+ ScanDirection es_direction;
+ List *es_range_table;
+ RelationInfo *es_result_relation_info;
+ Relation es_into_relation_descriptor;
+ ParamListInfo es_param_list_info;
+ int es_BaseId;
+ TupleTable es_tupleTable;
+ JunkFilter *es_junkFilter;
+ int *es_refcount;
+} EState;
+
+/* ----------------
+ * Executor Type information needed by plannodes.h
+ *
+ *| Note: the bogus classes CommonState and CommonScanState exist only
+ *| because our inheritance system only allows single inheritance
+ *| and we have to have unique slot names. Hence two or more
+ *| classes which want to have a common slot must ALL inherit
+ *| the slot from some other class. (This is a big hack to
+ *| allow our classes to share slot names..)
+ *|
+ *| Example:
+ *| the class Result and the class NestLoop nodes both want
+ *| a slot called "OuterTuple" so they both have to inherit
+ *| it from some other class. In this case they inherit
+ *| it from CommonState. "CommonState" and "CommonScanState" are
+ *| the best names I could come up with for this sort of
+ *| stuff.
+ *|
+ *| As a result, many classes have extra slots which they
+ *| don't use. These slots are denoted (unused) in the
+ *| comment preceeding the class definition. If you
+ *| comes up with a better idea of a way of doing things
+ *| along these lines, then feel free to make your idea
+ *| known to me.. -cim 10/15/89
+ * ----------------
+ */
+
+/* ----------------------------------------------------------------
+ * Common Executor State Information
+ * ----------------------------------------------------------------
+ */
+
+/* BaseNode removed -- base_id moved into CommonState - jolly */
+
+/* ----------------
+ * CommonState information
+ *
+ *| this is a bogus class used to hold slots so other
+ *| nodes can inherit them...
+ *
+ * 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 CommonState {
+ NodeTag type; /* its first field is NodeTag */
+ int cs_base_id;
+ TupleTableSlot *cs_OuterTupleSlot;
+ TupleTableSlot *cs_ResultTupleSlot;
+ ExprContext *cs_ExprContext;
+ ProjectionInfo *cs_ProjInfo;
+ bool cs_TupFromTlist;
+} CommonState;
+
+
+/* ----------------------------------------------------------------
+ * Control Node State Information
+ * ----------------------------------------------------------------
+ */
+
+/* ----------------
+ * ResultState information
+ *
+ * done flag which tells us to quit when we
+ * have already returned a constant tuple.
+ *
+ * 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 ResultState {
+ CommonState cstate; /* its first field is NodeTag */
+ int rs_done;
+} ResultState;
+
+/* ----------------
+ * AppendState information
+ *
+ * append nodes have this field "unionplans" which is this
+ * list of plans to execute in sequence.. these variables
+ * keep track of things..
+ *
+ * whichplan which plan is being executed
+ * nplans how many plans are in the list
+ * initialized array of ExecInitNode() results
+ * rtentries range table for the current plan
+ * result_relation_info_list array of each subplan's result relation info
+ * junkFilter_list array of each subplan's junk filter
+ *
+ * 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 AppendState {
+ CommonState cstate; /* its first field is NodeTag */
+ int as_whichplan;
+ int as_nplans;
+ bool *as_initialized;
+ List *as_rtentries;
+ List *as_result_relation_info_list;
+ List *as_junkFilter_list;
+} AppendState;
+
+/* ----------------------------------------------------------------
+ * Scan State Information
+ * ----------------------------------------------------------------
+ */
+
+/* ----------------
+ * CommonScanState information
+ *
+ * CommonScanState is a class like CommonState, but is used more
+ * by the nodes like SeqScan and Sort which want to
+ * keep track of an underlying relation.
+ *
+ * currentRelation relation being scanned
+ * currentScanDesc current scan descriptor for scan
+ * ScanTupleSlot pointer to slot in tuple table holding scan tuple
+ *
+ * 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 CommonScanState {
+ CommonState cstate; /* its first field is NodeTag */
+ Relation css_currentRelation;
+ HeapScanDesc css_currentScanDesc;
+ TupleTableSlot *css_ScanTupleSlot;
+} CommonScanState;
+
+/* ----------------
+ * IndexScanState information
+ *
+ *| index scans don't use CommonScanState because
+ *| the underlying AM abstractions for heap scans and
+ *| index scans are too different.. It would be nice
+ *| if the current abstraction was more useful but ... -cim 10/15/89
+ *
+ * IndexPtr current index in use
+ * NumIndices number of indices in this scan
+ * ScanKeys Skey structures to scan index rels
+ * NumScanKeys array of no of keys in each Skey struct
+ * RuntimeKeyInfo array of array of flags for Skeys evaled at runtime
+ * RelationDescs ptr to array of relation descriptors
+ * ScanDescs ptr to array of scan descriptors
+ *
+ * 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 IndexScanState {
+ CommonState cstate; /* its first field is NodeTag */
+ int iss_NumIndices;
+ int iss_IndexPtr;
+ ScanKey *iss_ScanKeys;
+ int *iss_NumScanKeys;
+ Pointer iss_RuntimeKeyInfo;
+ RelationPtr iss_RelationDescs;
+ IndexScanDescPtr iss_ScanDescs;
+} IndexScanState;
+
+
+/* ----------------------------------------------------------------
+ * Join State Information
+ * ----------------------------------------------------------------
+ */
+
+/* ----------------
+ * JoinState information
+ *
+ * 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 CommonState JoinState;
+
+/* ----------------
+ * NestLoopState information
+ *
+ * PortalFlag Set to enable portals to work.
+ *
+ * JoinState information
+ *
+ * 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 NestLoopState {
+ JoinState jstate; /* its first field is NodeTag */
+ bool nl_PortalFlag;
+} NestLoopState;
+
+/* ----------------
+ * MergeJoinState information
+ *
+ * OSortopI outerKey1 sortOp innerKey1 ...
+ * ISortopO innerkey1 sortOp outerkey1 ...
+ * JoinState current "state" of join. see executor.h
+ * MarkedTupleSlot pointer to slot in tuple table for marked tuple
+ *
+ * JoinState information
+ *
+ * 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 MergeJoinState {
+ JoinState jstate; /* its first field is NodeTag */
+ List *mj_OSortopI;
+ List *mj_ISortopO;
+ int mj_JoinState;
+ TupleTableSlot *mj_MarkedTupleSlot;
+} MergeJoinState;
+
+/* ----------------
+ * HashJoinState information
+ *
+ * hj_HashTable address of the hash table for the hashjoin
+ * hj_HashTableShmId shared memory id of hash table
+ * hj_CurBucket the current hash bucket that we are searching
+ * for matches of the current outer tuple
+ * hj_CurTuple the current matching inner tuple in the
+ * current hash bucket
+ * hj_CurOTuple the current matching inner tuple in the
+ * current hash overflow chain
+ * hj_InnerHashKey the inner hash key in the hashjoin condition
+ * hj_OuterBatches file descriptors for outer batches
+ * hj_InnerBatches file descriptors for inner batches
+ * hj_OuterReadPos current read position of outer batch
+ * hj_OuterReadBlk current read block of outer batch
+ * hj_OuterTupleSlot tuple slot for outer tuples
+ * hj_HashTupleSlot tuple slot for hashed tuples
+ *
+ *
+ *
+ * JoinState information
+ *
+ * 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 HashJoinState {
+ JoinState jstate; /* its first field is NodeTag */
+ HashJoinTable hj_HashTable;
+ IpcMemoryId hj_HashTableShmId;
+ HashBucket hj_CurBucket;
+ HeapTuple hj_CurTuple;
+ OverflowTuple hj_CurOTuple;
+ Var *hj_InnerHashKey;
+ File *hj_OuterBatches;
+ File *hj_InnerBatches;
+ char *hj_OuterReadPos;
+ int hj_OuterReadBlk;
+ TupleTableSlot *hj_OuterTupleSlot;
+ TupleTableSlot *hj_HashTupleSlot;
+} HashJoinState;
+
+
+/* ----------------------------------------------------------------
+ * Materialization State Information
+ * ----------------------------------------------------------------
+ */
+
+/* ----------------
+ * MaterialState information
+ *
+ * materialize nodes are used to materialize the results
+ * of a subplan into a temporary relation.
+ *
+ * Flag indicated whether subplan has been materialized
+ * TempRelation temporary relation containing result of executing
+ * the subplan.
+ *
+ * CommonScanState information
+ *
+ * currentRelation relation descriptor of sorted relation
+ * currentScanDesc current scan descriptor for scan
+ * ScanTupleSlot pointer to slot in tuple table holding scan tuple
+ *
+ * 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 MaterialState {
+ CommonScanState csstate; /* its first field is NodeTag */
+ bool mat_Flag;
+ Relation mat_TempRelation;
+} MaterialState;
+
+/* ---------------------
+ * AggregateState information
+ *
+ * done indicated whether aggregate has been materialized
+ * -------------------------
+ */
+typedef struct AggState {
+ CommonScanState csstate; /* its first field is NodeTag */
+ bool agg_done;
+} AggState;
+
+/* ---------------------
+ * GroupState information
+ *
+ * -------------------------
+ */
+typedef struct GroupState {
+ CommonScanState csstate; /* its first field is NodeTag */
+ bool grp_useLastTuple; /* last tuple not processed yet */
+ bool grp_done;
+ TupleTableSlot *grp_lastSlot;
+} GroupState;
+
+/* ----------------
+ * SortState information
+ *
+ *| sort nodes are really just a kind of a scan since
+ *| we implement sorts by retrieveing the entire subplan
+ *| into a temp relation, sorting the temp relation into
+ *| another sorted relation, and then preforming a simple
+ *| unqualified sequential scan on the sorted relation..
+ *| -cim 10/15/89
+ *
+ * Flag indicated whether relation has been sorted
+ * Keys scan key structures used to keep info on sort keys
+ * TempRelation temporary relation containing result of executing
+ * the subplan.
+ *
+ * CommonScanState information
+ *
+ * currentRelation relation descriptor of sorted relation
+ * currentScanDesc current scan descriptor for scan
+ * ScanTupleSlot pointer to slot in tuple table holding scan tuple
+ *
+ * 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 SortState {
+ CommonScanState csstate; /* its first field is NodeTag */
+ bool sort_Flag;
+ ScanKey sort_Keys;
+ Relation sort_TempRelation;
+} SortState;
+
+/* ----------------
+ * UniqueState information
+ *
+ * Unique nodes are used "on top of" sort nodes to discard
+ * duplicate tuples returned from the sort phase. Basically
+ * all it does is compare the current tuple from the subplan
+ * with the previously fetched tuple stored in OuterTuple and
+ * if the two are identical, then we just fetch another tuple
+ * from the sort and try again.
+ *
+ * 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 CommonState UniqueState;
+
+
+/* ----------------
+ * HashState information
+ *
+ * hashBatches file descriptors for the batches
+ *
+ * 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 HashState {
+ CommonState cstate; /* its first field is NodeTag */
+ File *hashBatches;
+} HashState;
+
+/* -----------------------
+ * TeeState information
+ * leftPlace : next item in the queue unseen by the left parent
+ * rightPlace : next item in the queue unseen by the right parent
+ * lastPlace : last item in the queue
+ * bufferRelname : name of the relation used as the buffer queue
+ * bufferRel : the relation used as the buffer queue
+ * mcxt : for now, tee's have their own memory context
+ * may be cleaned up later if portals are cleaned up
+ *
+ * initially, a Tee starts with [left/right]Place variables set to -1.
+ * on cleanup, queue is free'd when both leftPlace and rightPlace = -1
+ * -------------------------
+*/
+typedef struct TeeState {
+ CommonState cstate; /* its first field is NodeTag */
+ int tee_leftPlace;
+ int tee_rightPlace;
+ int tee_lastPlace;
+ char *tee_bufferRelname;
+ Relation tee_bufferRel;
+ MemoryContext tee_mcxt;
+ HeapScanDesc tee_leftScanDesc;
+ HeapScanDesc tee_rightScanDesc;
+} TeeState;
+
+#endif /* EXECNODES_H */
diff --git a/src/backend/nodes/list.c b/src/backend/nodes/list.c
new file mode 100644
index 0000000000..e8d4d076c9
--- /dev/null
+++ b/src/backend/nodes/list.c
@@ -0,0 +1,438 @@
+/*-------------------------------------------------------------------------
+ *
+ * list.c--
+ * various list handling routines
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header$
+ *
+ * NOTES
+ * XXX a few of the following functions are duplicated to handle
+ * List of pointers and List of integers separately. Some day,
+ * someone should unify them. - ay 11/2/94
+ * This file needs cleanup.
+ *
+ * HISTORY
+ * AUTHOR DATE MAJOR EVENT
+ * Andrew Yu Oct, 1994 file creation
+ *
+ *-------------------------------------------------------------------------
+ */
+#include <stdarg.h>
+#include "postgres.h"
+#include "nodes/pg_list.h"
+#include "nodes/parsenodes.h"
+#include "utils/builtins.h" /* for namecpy */
+#include "utils/elog.h"
+#include "utils/palloc.h"
+
+List *
+makeList(void *elem, ...)
+{
+ va_list args;
+ List *retval = NIL;
+ List *temp = NIL;
+ List *tempcons = NIL;
+
+ va_start(args, elem);
+
+ temp = elem;
+ while (temp != (void *) -1) {
+ temp = lcons(temp, NIL);
+ if (tempcons == NIL)
+ retval = temp;
+ else
+ lnext(tempcons) = temp;
+ tempcons = temp;
+
+ temp = va_arg(args, void *);
+ }
+
+ va_end(args);
+
+ return (retval);
+}
+
+List *
+lcons(void *datum, List *list)
+{
+ List *l = makeNode(List);
+ lfirst(l) = datum;
+ lnext(l) = list;
+ return l;
+}
+
+List *
+lappend(List *list, void *obj)
+{
+ return nconc(list, lcons(obj, NIL));
+}
+
+Value *
+makeInteger(long i)
+{
+ Value *v = makeNode(Value);
+ v->type = T_Integer;
+ v->val.ival = i;
+ return v;
+}
+
+Value *
+makeFloat(double d)
+{
+ Value *v = makeNode(Value);
+ v->type = T_Float;
+ v->val.dval = d;
+ return v;
+}
+
+Value *
+makeString(char *str)
+{
+ Value *v = makeNode(Value);
+ v->type = T_String;
+ v->val.str = str;
+ return v;
+}
+
+/* n starts with 0 */
+void *
+nth(int n, List *l)
+{
+ /* XXX assume list is long enough */
+ while(n > 0) {
+ l = lnext(l);
+ n--;
+ }
+ return lfirst(l);
+}
+
+/* this is here solely for rt_store. Get rid of me some day! */
+void
+set_nth(List *l, int n, void *elem)
+{
+ /* XXX assume list is long enough */
+ while(n > 0) {
+ l = lnext(l);
+ n--;
+ }
+ lfirst(l) = elem;
+ return;
+}
+
+int
+length(List *l)
+{
+ int i=0;
+ while(l!=NIL) {
+ l = lnext(l);
+ i++;
+ }
+ return i;
+}
+
+void
+freeList(List *list)
+{
+ while(list!=NIL) {
+ List *l = list;
+ list = lnext(list);
+ pfree(l);
+ }
+}
+
+/*
+ * below are for backwards compatibility
+ */
+List *
+append(List *l1, List *l2)
+{
+ List *newlist, *newlist2, *p;
+
+ if (l1==NIL)
+ return copyObject(l2);
+
+ newlist = copyObject(l1);
+ newlist2 = copyObject(l2);
+
+ for (p=newlist; lnext(p)!=NIL; p=lnext(p))
+ ;
+ lnext(p) = newlist2;
+ return newlist;
+}
+
+/*
+ * below are for backwards compatibility
+ */
+List *
+intAppend(List *l1, List *l2)
+{
+ List *newlist, *newlist2, *p;
+
+ if (l1==NIL)
+ return listCopy(l2);
+
+ newlist = listCopy(l1);
+ newlist2 = listCopy(l2);
+
+ for (p=newlist; lnext(p)!=NIL; p=lnext(p))
+ ;
+ lnext(p) = newlist2;
+ return newlist;
+}
+
+List *
+nconc(List *l1, List *l2)
+{
+ List *temp;
+
+ if (l1 == NIL)
+ return l2;
+ if (l2 == NIL)
+ return l1;
+ if (l1 == l2)
+ elog(WARN, "tryout to nconc a list to itself");
+
+ for (temp = l1; lnext(temp)!=NULL; temp = lnext(temp))
+ ;
+
+ lnext(temp) = l2;
+ return(l1); /* list1 is now list1[]list2 */
+}
+
+
+List *
+nreverse(List *list)
+{
+ List *rlist = NIL;
+ List *p = NIL;
+
+ if(list==NULL)
+ return(NIL);
+
+ if (length(list) == 1)
+ return(list);
+
+ for (p = list; p!=NULL; p = lnext(p)) {
+ rlist = lcons(lfirst(p),rlist);
+ }
+
+ lfirst(list) = lfirst(rlist);
+ lnext(list) = lnext(rlist);
+ return(list);
+}
+
+/*
+ * same
+ *
+ * Returns t if two lists contain the same elements.
+ * now defined in lispdep.c
+ *
+ * XXX only good for IntList -ay
+ */
+bool
+same(List *foo, List *bar)
+{
+ List *temp = NIL;
+
+ if (foo == NULL)
+ return (bar==NULL);
+ if (bar == NULL)
+ return (foo==NULL);
+ if (length(foo) == length(bar)) {
+ foreach (temp,foo) {
+ if (!intMember((int)lfirst(temp),bar))
+ return(false);
+ }
+ return(true);
+ }
+ return(false);
+
+}
+
+List *
+LispUnion(List *foo, List *bar)
+{
+ List *retval = NIL;
+ List *i = NIL;
+ List *j = NIL;
+
+ if (foo==NIL)
+ return(bar); /* XXX - should be copy of bar */
+
+ if (bar==NIL)
+ return(foo); /* XXX - should be copy of foo */
+
+ foreach (i,foo) {
+ foreach (j,bar) {
+ if (! equal(lfirst(i), lfirst(j))) {
+ retval = lappend(retval,lfirst(i));
+ break;
+ }
+ }
+ }
+ foreach(i,bar) {
+ retval = lappend(retval,lfirst(i));
+ }
+
+ return(retval);
+}
+
+List *
+LispUnioni(List *foo, List *bar)
+{
+ List *retval = NIL;
+ List *i = NIL;
+ List *j = NIL;
+
+ if (foo==NIL)
+ return(bar); /* XXX - should be copy of bar */
+
+ if (bar==NIL)
+ return(foo); /* XXX - should be copy of foo */
+
+ foreach (i,foo) {
+ foreach (j,bar) {
+ if (lfirsti(i) != lfirsti(j)) {
+ retval = lappendi(retval,lfirst(i));
+ break;
+ }
+ }
+ }
+ foreach(i,bar) {
+ retval = lappendi(retval, lfirsti(i));
+ }
+
+ return(retval);
+}
+
+/*
+ * member()
+ * - nondestructive, returns t iff foo is a member of the list
+ * bar
+ */
+bool
+member(void *foo, List *bar)
+{
+ List *i;
+ foreach (i,bar)
+ if (equal((Node*)(lfirst(i)),(Node*)foo))
+ return(true);
+ return(false);
+}
+
+bool
+intMember(int foo, List *bar)
+{
+ List *i;
+ foreach (i,bar)
+ if (foo == (int)lfirst(i))
+ return(true);
+ return(false);
+}
+
+/*
+ * lremove -
+ * only does pointer comparisons. Removes 'elem' from the the linked list.
+ */
+List *
+lremove(void *elem, List *list)
+{
+ List *l;
+ List *prev = NIL;
+ List *result = list;
+
+ foreach(l, list) {
+ if (elem == lfirst(l))
+ break;
+ prev = l;
+ }
+ if (l!=NULL) {
+ if (prev == NIL) {
+ result = lnext(list);
+ } else {
+ lnext(prev) = lnext(l);
+ }
+ }
+ return result;
+}
+
+List *
+LispRemove(void *elem, List *list)
+{
+ List *temp = NIL;
+ List *prev = NIL;
+
+ if (equal(elem, lfirst(list)))
+ return lnext(list);
+
+ temp = lnext(list);
+ prev = list;
+ while(temp!=NIL) {
+ if (equal(elem, lfirst(temp))) {
+ lnext(prev) = lnext(temp);
+ break;
+ }
+ temp = lnext(temp);
+ prev = lnext(prev);
+ }
+ return(list);
+}
+
+List *
+intLispRemove(int elem, List *list)
+{
+ List *temp = NIL;
+ List *prev = NIL;
+
+ if (elem == (int)lfirst(list))
+ return lnext(list);
+
+ temp = lnext(list);
+ prev = list;
+ while(temp!=NIL) {
+ if (elem == (int)lfirst(temp)) {
+ lnext(prev) = lnext(temp);
+ break;
+ }
+ temp = lnext(temp);
+ prev = lnext(prev);
+ }
+ return(list);
+}
+
+List *
+set_difference(List *list1, List *list2)
+{
+ List *temp1 = NIL;
+ List *result = NIL;
+
+ if (list2==NIL)
+ return(list1);
+
+ foreach (temp1, list1) {
+ if (!member(lfirst(temp1), list2))
+ result = lappend(result, lfirst(temp1));
+ }
+ return(result);
+}
+
+List *
+set_differencei(List *list1, List *list2)
+{
+ List *temp1 = NIL;
+ List *result = NIL;
+
+ if (list2==NIL)
+ return(list1);
+
+ foreach (temp1, list1) {
+ if (!intMember(lfirsti(temp1), list2))
+ result = lappendi(result, lfirst(temp1));
+ }
+ return(result);
+}
+
diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c
new file mode 100644
index 0000000000..99e977279e
--- /dev/null
+++ b/src/backend/nodes/makefuncs.c
@@ -0,0 +1,117 @@
+/*
+ * makefuncs.c--
+ * creator functions for primitive nodes. The functions here are for
+ * the most frequently created nodes.
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header$
+ *
+ * NOTES
+ * Creator functions in POSTGRES 4.2 are generated automatically. Most of
+ * them are rarely used. Now we don't generate them any more. If you want
+ * one, you have to write it yourself.
+ *
+ * HISTORY
+ * AUTHOR DATE MAJOR EVENT
+ * Andrew Yu Oct 20, 1994 file creation
+ */
+#include "postgres.h"
+#include "nodes/pg_list.h"
+#include "nodes/primnodes.h"
+#include "nodes/makefuncs.h"
+
+/*
+ * makeOper -
+ * creates an Oper node
+ */
+Oper *
+makeOper(Oid opno,
+ Oid opid,
+ Oid opresulttype,
+ int opsize,
+ FunctionCachePtr op_fcache)
+{
+ Oper *oper = makeNode(Oper);
+
+ oper->opno = opno;
+ oper->opid = opid;
+ oper->opresulttype = opresulttype;
+ oper->opsize = opsize;
+ oper->op_fcache = op_fcache;
+ return oper;
+}
+
+/*
+ * makeVar -
+ * creates a Var node
+ *
+ */
+Var *
+makeVar(Index varno,
+ AttrNumber varattno,
+ Oid vartype,
+ Index varnoold,
+ AttrNumber varoattno)
+{
+ Var *var = makeNode(Var);
+
+ var->varno = varno;
+ var->varattno = varattno;
+ var->vartype = vartype;
+ var->varnoold = varnoold;
+ var->varoattno = varoattno;
+
+ return var;
+}
+
+/*
+ * makeResdom -
+ * creates a Resdom (Result Domain) node
+ */
+Resdom *
+makeResdom(AttrNumber resno,
+ Oid restype,
+ int reslen,
+ char *resname,
+ Index reskey,
+ Oid reskeyop,
+ int resjunk)
+{
+ Resdom *resdom = makeNode(Resdom);
+
+ resdom->resno = resno;
+ resdom->restype = restype;
+ resdom->reslen = reslen;
+ resdom->resname = resname;
+ resdom->reskey = reskey;
+ resdom->reskeyop = reskeyop;
+ resdom->resjunk = resjunk;
+ return resdom;
+}
+
+/*
+ * makeConst -
+ * creates a Const node
+ */
+Const *
+makeConst(Oid consttype,
+ Size constlen,
+ Datum constvalue,
+ bool constisnull,
+ bool constbyval,
+ bool constisset)
+{
+ Const *cnst = makeNode(Const);
+
+ cnst->consttype = consttype;
+ cnst->constlen = constlen;
+ cnst->constvalue = constvalue;
+ cnst->constisnull = constisnull;
+ cnst->constbyval = constbyval;
+ cnst->constisset = constisset;
+ return cnst;
+}
+
diff --git a/src/backend/nodes/makefuncs.h b/src/backend/nodes/makefuncs.h
new file mode 100644
index 0000000000..e1701ce5db
--- /dev/null
+++ b/src/backend/nodes/makefuncs.h
@@ -0,0 +1,48 @@
+/*-------------------------------------------------------------------------
+ *
+ * makefuncs.h--
+ * prototypes for the creator functions (for primitive nodes)
+ *
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id$
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef MAKEFUNC_H
+#define MAKEFUNC_H
+
+#include "access/attnum.h"
+#include "catalog/pg_operator.h"
+#include "utils/fcache.h"
+#include "nodes/primnodes.h"
+
+extern Oper *makeOper(Oid opno,
+ Oid opid,
+ Oid opresulttype,
+ int opsize,
+ FunctionCachePtr op_fcache);
+
+extern Var *makeVar(Index varno,
+ AttrNumber varattno,
+ Oid vartype,
+ Index varnoold,
+ AttrNumber varoattno);
+
+extern Resdom *makeResdom(AttrNumber resno,
+ Oid restype,
+ int reslen,
+ char *resname,
+ Index reskey,
+ Oid reskeyop,
+ int resjunk);
+
+extern Const *makeConst(Oid consttype,
+ Size constlen,
+ Datum constvalue,
+ bool constisnull,
+ bool constbyval,
+ bool constisset);
+
+#endif /* MAKEFUNC_H */
diff --git a/src/backend/nodes/memnodes.h b/src/backend/nodes/memnodes.h
new file mode 100644
index 0000000000..9cf4e0fbcf
--- /dev/null
+++ b/src/backend/nodes/memnodes.h
@@ -0,0 +1,101 @@
+/*-------------------------------------------------------------------------
+ *
+ * memnodes.h--
+ * POSTGRES memory context node definitions.
+ *
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id$
+ *
+ * XXX the typedefs in this file are different from the other ???nodes.h;
+ * they are pointers to structures instead of the structures themselves.
+ * If you're wondering, this is plain laziness. I don't want to touch
+ * the memory context code which should be revamped altogether some day.
+ * - ay 10/94
+ *-------------------------------------------------------------------------
+ */
+#ifndef MEMNODES_H
+#define MEMNODES_H
+
+#include "c.h"
+
+#include "utils/memutils.h"
+#include "lib/fstack.h"
+
+#include "nodes/nodes.h"
+
+/*
+ * MemoryContext --
+ * A logical context in which memory allocations occur.
+ *
+ * The types of memory contexts can be thought of as members of the
+ * following inheritance hierarchy with properties summarized below.
+ *
+ * Node
+ * |
+ * MemoryContext___
+ * / \
+ * GlobalMemory PortalMemoryContext
+ * / \
+ * PortalVariableMemory PortalHeapMemory
+ *
+ * Flushed at Flushed at Checkpoints
+ * Transaction Portal
+ * Commit Close
+ *
+ * GlobalMemory n n n
+ * PortalVariableMemory n y n
+ * PortalHeapMemory y y y
+ */
+
+typedef struct MemoryContextMethodsData {
+ Pointer (*alloc)();
+ void (*free_p)(); /* need to use free as a #define,
+ so can't use free */
+ Pointer (*realloc)();
+ char* (*getName)();
+ void (*dump)();
+} *MemoryContextMethods;
+
+typedef struct MemoryContext {
+ NodeTag type;
+ MemoryContextMethods method;
+} *MemoryContext;
+
+/* think about doing this right some time but we'll have explicit fields
+ for now -ay 10/94 */
+typedef struct GlobalMemory {
+ NodeTag type;
+ MemoryContextMethods method;
+ AllocSetData setData;
+ char *name;
+ OrderedElemData elemData;
+} *GlobalMemory;
+
+typedef MemoryContext *PortalMemoryContext;
+
+typedef struct PortalVariableMemory {
+ NodeTag type;
+ MemoryContextMethods method;
+ AllocSetData setData;
+} *PortalVariableMemory;
+
+typedef struct PortalHeapMemory {
+ NodeTag type;
+ MemoryContextMethods method;
+ Pointer block;
+ FixedStackData stackData;
+} *PortalHeapMemory;
+
+/*
+ * MemoryContextIsValid --
+ * True iff memory context is valid.
+ */
+#define MemoryContextIsValid(context) \
+ (IsA(context,MemoryContext) || IsA(context,GlobalMemory) || \
+ IsA(context,PortalVariableMemory) || IsA(context,PortalHeapMemory))
+
+#endif /* MEMNODES_H */
+
+
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
new file mode 100644
index 0000000000..8c08d5e159
--- /dev/null
+++ b/src/backend/nodes/nodeFuncs.c
@@ -0,0 +1,116 @@
+/*-------------------------------------------------------------------------
+ *
+ * nodeFuncs.c--
+ * All node routines more complicated than simple access/modification
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header$
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "c.h"
+
+#include "nodes/primnodes.h"
+#include "nodes/plannodes.h"
+#include "nodes/pg_list.h"
+#include "nodes/relation.h"
+#include "nodes/nodeFuncs.h"
+#include "utils/lsyscache.h"
+
+/*
+ * single_node -
+ * Returns t if node corresponds to a single-noded expression
+ */
+bool
+single_node(Node *node)
+{
+ if(IsA(node,Ident) || IsA(node,Const) || IsA(node,Var) || IsA(node,Param))
+ return(true);
+ else
+ return(false);
+}
+
+/*****************************************************************************
+ * VAR nodes
+ *****************************************************************************/
+
+/*
+ * var_is_outer
+ * var_is_inner
+ * var_is_mat
+ * var_is_rel
+ *
+ * Returns t iff the var node corresponds to (respectively):
+ * the outer relation in a join
+ * the inner relation of a join
+ * a materialized relation
+ * a base relation (i.e., not an attribute reference, a variable from
+ * some lower join level, or a sort result)
+ * var node is an array reference
+ *
+ */
+bool
+var_is_outer (Var *var)
+{
+ return((bool)(var->varno == OUTER));
+}
+
+bool
+var_is_inner (Var *var)
+{
+ return ( (bool) (var->varno == INNER));
+}
+
+bool
+var_is_rel (Var *var)
+{
+ return (bool)
+ ! (var_is_inner (var) || var_is_outer (var));
+}
+
+/*****************************************************************************
+ * OPER nodes
+ *****************************************************************************/
+
+/*
+ * replace_opid -
+ *
+ * Given a oper node, resets the opfid field with the
+ * procedure OID (regproc id).
+ *
+ * Returns the modified oper node.
+ *
+ */
+Oper *
+replace_opid (Oper *oper)
+{
+ oper->opid = get_opcode(oper->opno);
+ oper->op_fcache = NULL;
+ return(oper);
+}
+
+/*****************************************************************************
+ * constant (CONST, PARAM) nodes
+ *****************************************************************************/
+
+/*
+ * non_null -
+ * Returns t if the node is a non-null constant, e.g., if the node has a
+ * valid `constvalue' field.
+ *
+ */
+bool
+non_null (Expr *c)
+{
+
+ if ( IsA(c,Const) && ! ((Const*)c)->constisnull )
+ return(true);
+ else
+ return(false);
+}
+
+
+
diff --git a/src/backend/nodes/nodeFuncs.h b/src/backend/nodes/nodeFuncs.h
new file mode 100644
index 0000000000..58b7d0449a
--- /dev/null
+++ b/src/backend/nodes/nodeFuncs.h
@@ -0,0 +1,23 @@
+/*-------------------------------------------------------------------------
+ *
+ * nodeFuncs.h--
+ *
+ *
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id$
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef NODEFUNCS_H
+#define NODEFUNCS_H
+
+extern bool single_node(Node *node);
+extern bool var_is_outer(Var *var);
+extern bool var_is_inner(Var *var);
+extern bool var_is_rel(Var *var);
+extern Oper *replace_opid(Oper *oper);
+extern bool non_null(Expr *c);
+
+#endif /* NODEFUNCS_H */
diff --git a/src/backend/nodes/nodes.c b/src/backend/nodes/nodes.c
new file mode 100644
index 0000000000..8054612c88
--- /dev/null
+++ b/src/backend/nodes/nodes.c
@@ -0,0 +1,45 @@
+/*-------------------------------------------------------------------------
+ *
+ * nodes.c--
+ * support code for nodes (now that we get rid of the home-brew
+ * inheritance system, our support code for nodes get much simpler)
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header$
+ *
+ * HISTORY
+ * Andrew Yu Oct 20, 1994 file creation
+ *
+ *-------------------------------------------------------------------------
+ */
+#include <string.h>
+#include "postgres.h"
+#include "utils/palloc.h"
+#include "utils/elog.h"
+#include "nodes/nodes.h" /* where func declarations of this file goes */
+
+/*
+ * newNode -
+ * create a new node of the specified size and tag the node with the
+ * specified tag.
+ *
+ * !WARNING!: Avoid using newNode directly. You should be using the
+ * macro makeNode. eg. to create a Resdom node, use makeNode(Resdom)
+ *
+ */
+Node *
+newNode(Size size, NodeTag tag)
+{
+ Node *newNode;
+
+ Assert(size >= 4); /* need the tag, at least */
+
+ newNode = (Node *)palloc(size);
+ memset((char *)newNode, 0, size);
+ newNode->type = tag;
+ return(newNode);
+}
+
diff --git a/src/backend/nodes/nodes.h b/src/backend/nodes/nodes.h
new file mode 100644
index 0000000000..78cd1d85e6
--- /dev/null
+++ b/src/backend/nodes/nodes.h
@@ -0,0 +1,299 @@
+/*-------------------------------------------------------------------------
+ *
+ * nodes.h--
+ * Definitions for tagged nodes.
+ *
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id$
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef NODES_H
+#define NODES_H
+
+#include "c.h"
+
+/*
+ * The first field of every node is NodeTag. Each node created (with makeNode)
+ * will have one of the following tags as the value of its first field.
+ *
+ * Note that the number of the node tags are not contiguous. We left holes
+ * here so that we can add more tags without changing the existing enum's.
+ */
+typedef enum NodeTag {
+ T_Invalid = 0,
+
+ /*---------------------
+ * TAGS FOR PLAN NODES (plannodes.h)
+ *---------------------
+ */
+ T_Plan = 10,
+ T_Existential,
+ T_Result,
+ T_Append,
+ T_Scan,
+ T_SeqScan,
+ T_IndexScan,
+ T_Join,
+ T_NestLoop,
+ T_MergeJoin,
+ T_HashJoin,
+ T_Temp,
+ T_Material,
+ T_Sort,
+ T_Agg,
+ T_Unique,
+ T_Hash,
+ T_Choose,
+ T_Tee,
+ T_Group,
+
+ /*---------------------
+ * TAGS FOR PRIMITIVE NODES (primnodes.h)
+ *---------------------
+ */
+ T_Resdom = 100,
+ T_Fjoin,
+ T_Expr,
+ T_Var,
+ T_Oper,
+ T_Const,
+ T_Param,
+ T_Aggreg,
+ T_Func,
+ T_Array,
+ T_ArrayRef,
+
+ /*---------------------
+ * TAGS FOR INNER PLAN NODES (relation.h)
+ *---------------------
+ */
+ T_Rel = 200,
+ T_Path,
+ T_IndexPath,
+ T_JoinPath,
+ T_MergePath,
+ T_HashPath,
+ T_OrderKey,
+ T_JoinKey,
+ T_MergeOrder,
+ T_CInfo,
+ T_JoinMethod,
+ T_HInfo,
+ T_MInfo,
+ T_JInfo,
+ T_Iter,
+ T_Stream,
+
+ /*---------------------
+ * TAGS FOR EXECUTOR NODES (execnodes.h)
+ *---------------------
+ */
+ T_IndexInfo = 300,
+ T_RelationInfo,
+ T_TupleCount,
+ T_TupleTableSlot,
+ T_ExprContext,
+ T_ProjectionInfo,
+ T_JunkFilter,
+ T_EState,
+ T_BaseNode,
+ T_CommonState,
+ T_ResultState,
+ T_AppendState,
+ T_CommonScanState,
+ T_ScanState,
+ T_IndexScanState,
+ T_JoinState,
+ T_NestLoopState,
+ T_MergeJoinState,
+ T_HashJoinState,
+ T_MaterialState,
+ T_AggState,
+ T_GroupState,
+ T_SortState,
+ T_UniqueState,
+ T_HashState,
+ T_TeeState,
+
+ /*---------------------
+ * TAGS FOR MEMORY NODES (memnodes.h)
+ *---------------------
+ */
+ T_MemoryContext = 400,
+ T_GlobalMemory,
+ T_PortalMemoryContext,
+ T_PortalVariableMemory,
+ T_PortalHeapMemory,
+
+ /*---------------------
+ * TAGS FOR VALUE NODES (pg_list.h)
+ *---------------------
+ */
+ T_Value = 500,
+ T_List,
+ T_Integer,
+ T_Float,
+ T_String,
+ T_Null,
+
+ /*---------------------
+ * TAGS FOR PARSE TREE NODES (parsenode.h)
+ *---------------------
+ */
+ T_Query = 600,
+ T_AppendStmt,
+ T_DeleteStmt,
+ T_ReplaceStmt,
+ T_CursorStmt,
+ T_RetrieveStmt,
+ T_AddAttrStmt,
+ T_AggregateStmt,
+ T_ChangeACLStmt,
+ T_ClosePortalStmt,
+ T_ClusterStmt,
+ T_CopyStmt,
+ T_CreateStmt,
+ T_VersionStmt,
+ T_DefineStmt,
+ T_DestroyStmt,
+ T_ExtendStmt,
+ T_FetchStmt,
+ T_IndexStmt,
+ T_MoveStmt,
+ T_ProcedureStmt,
+ T_PurgeStmt,
+ T_RecipeStmt,
+ T_RemoveFuncStmt,
+ T_RemoveOperStmt,
+ T_RemoveStmt,
+ T_RenameStmt,
+ T_RuleStmt,
+ T_NotifyStmt,
+ T_ListenStmt,
+ T_TransactionStmt,
+ T_ViewStmt,
+ T_LoadStmt,
+ T_CreatedbStmt,
+ T_DestroydbStmt,
+ T_VacuumStmt,
+ T_ExplainStmt,
+
+ T_A_Expr = 700,
+ T_Attr,
+ T_A_Const,
+ T_ParamNo,
+ T_Ident,
+ T_FuncCall,
+ T_A_Indices,
+ T_ResTarget,
+ T_ParamString,
+ T_TimeRange,
+ T_RelExpr,
+ T_SortBy,
+ T_RangeVar,
+ T_TypeName,
+ T_IndexElem,
+ T_ColumnDef,
+ T_DefElem,
+ T_TargetEntry,
+ T_RangeTblEntry,
+ T_SortClause,
+ T_GroupClause
+} NodeTag;
+
+/*
+ * The first field of a node of any type is gauranteed to be the NodeTag.
+ * Hence the type of any node can be gotten by casting it to Node. Declaring
+ * a variable to be of Node * (instead of void *) can also facilitate
+ * debugging.
+ */
+typedef struct Node {
+ NodeTag type;
+} Node;
+
+#define nodeTag(_node_) ((Node*)_node_)->type
+
+#define makeNode(_node_) (_node_*)newNode(sizeof(_node_),T_##_node_)
+#define NodeSetTag(n, t) ((Node *)n)->type = t
+
+#define IsA(_node_,_tag_) (nodeTag(_node_) == T_##_tag_)
+
+/* ----------------------------------------------------------------
+ * IsA functions (no inheritence any more)
+ * ----------------------------------------------------------------
+ */
+#define IsA_JoinPath(jp) \
+ (nodeTag(jp)==T_JoinPath || nodeTag(jp)==T_MergePath || \
+ nodeTag(jp)==T_HashPath)
+
+#define IsA_Join(j) \
+ (nodeTag(j)==T_Join || nodeTag(j)==T_NestLoop || \
+ nodeTag(j)==T_MergeJoin || nodeTag(j)==T_HashJoin)
+
+#define IsA_Temp(t) \
+ (nodeTag(t)==T_Temp || nodeTag(t)==T_Material || nodeTag(t)==T_Sort || \
+ nodeTag(t)==T_Unique)
+
+/* ----------------------------------------------------------------
+ * extern declarations follow
+ * ----------------------------------------------------------------
+ */
+
+/*
+ * nodes/nodes.c
+ */
+extern Node *newNode(Size size, NodeTag tag);
+
+/*
+ * nodes/{outfuncs.c,print.c}
+ */
+#define nodeDisplay print
+
+extern char *nodeToString(void *obj);
+extern void print(void *obj);
+
+/*
+ * nodes/{readfuncs.c,read.c}
+ */
+extern void *stringToNode(char *str);
+
+/*
+ * nodes/copyfuncs.c
+ */
+extern void *copyObject(void *obj);
+
+/*
+ * nodes/equalfuncs.c
+ */
+extern bool equal(void *a, void *b);
+
+
+/* ----------------
+ * I don't know why this is here. Most likely a hack..
+ * -cim 6/3/90
+ * ----------------
+ */
+typedef float Cost;
+
+/*
+ * CmdType -
+ * enums for type of operation to aid debugging
+ *
+ * ??? could have put this in parsenodes.h but many files not in the
+ * optimizer also need this...
+ */
+typedef enum CmdType {
+ CMD_UNKNOWN,
+ CMD_SELECT, /* select stmt (formerly retrieve) */
+ CMD_UPDATE, /* update stmt (formerly replace) */
+ CMD_INSERT, /* insert stmt (formerly append) */
+ CMD_DELETE,
+ CMD_NOTIFY,
+ CMD_UTILITY /* cmds like create, destroy, copy, vacuum, etc. */
+} CmdType;
+
+
+#endif /* NODES_H */
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
new file mode 100644
index 0000000000..41e1e86b4f
--- /dev/null
+++ b/src/backend/nodes/outfuncs.c
@@ -0,0 +1,1670 @@
+/*-------------------------------------------------------------------------
+ *
+ * outfuncs.c--
+ * routines to convert a node to ascii representation
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header$
+ *
+ * NOTES
+ * Every (plan) node in POSTGRES has an associated "out" routine which
+ * knows how to create its ascii representation. These functions are
+ * useful for debugging as well as for storing plans in the system
+ * catalogs (eg. indexes). This is also the plan string sent out in
+ * Mariposa.
+ *
+ * These functions update the in/out argument of type StringInfo
+ * passed to them. This argument contains the string holding the ASCII
+ * representation plus some other information (string length, etc.)
+ *
+ *-------------------------------------------------------------------------
+ */
+#include <stdio.h>
+#include "postgres.h"
+
+#include "access/heapam.h"
+#include "access/htup.h"
+#include "utils/syscache.h"
+#include "utils/lsyscache.h"
+#include "fmgr.h"
+#include "utils/elog.h"
+#include "utils/datum.h"
+#include "utils/palloc.h"
+
+#include "nodes/nodes.h"
+#include "nodes/execnodes.h"
+#include "nodes/pg_list.h"
+#include "nodes/plannodes.h"
+#include "nodes/parsenodes.h"
+#include "nodes/primnodes.h"
+#include "nodes/relation.h"
+
+#include "catalog/pg_type.h"
+#include "lib/stringinfo.h"
+
+static void _outDatum(StringInfo str, Datum value, Oid type);
+static void _outNode(StringInfo str, void *obj);
+
+/*
+ * _outIntList -
+ * converts a List of integers
+ */
+void
+_outIntList(StringInfo str, List *list)
+{
+ List *l;
+ char buf[500];
+
+ appendStringInfo(str, "(");
+ foreach(l, list) {
+ sprintf(buf, "%d ", (int)lfirst(l));
+ appendStringInfo(str, buf);
+ }
+ appendStringInfo(str, ")");
+}
+
+static void
+_outQuery(StringInfo str, Query *node)
+{
+ char buf[500];
+
+ sprintf(buf, "QUERY");
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :command %d", node->commandType);
+ appendStringInfo(str,buf);
+ if (node->utilityStmt &&
+ nodeTag(node->utilityStmt) == T_NotifyStmt)
+ sprintf(buf," :utility %s",
+ ((NotifyStmt*)(node->utilityStmt))->relname);
+ else /* use "" to designate */
+ sprintf(buf," :utility \"\"");
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :resrel %d", node->resultRelation);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :rtable ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->rtable);
+ if (node->uniqueFlag)
+ sprintf(buf, " :unique %s", node->uniqueFlag);
+ else /* use "" to designate non-unique */
+ sprintf(buf, " :unique \"\"");
+ appendStringInfo(str,buf);
+ sprintf(buf, " :targetlist ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->targetList);
+ sprintf(buf, " :qual ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->qual);
+
+}
+
+/*
+ * print the basic stuff of all nodes that inherit from Plan
+ */
+static void
+_outPlanInfo(StringInfo str, Plan *node)
+{
+ char buf[500];
+
+ sprintf(buf, " :cost %g", node->cost );
+ appendStringInfo(str,buf);
+ sprintf(buf, " :size %d", node->plan_size);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :width %d", node->plan_width);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :state %s", (node->state == (EState*) NULL ?
+ "nil" : "non-NIL"));
+ appendStringInfo(str,buf);
+ sprintf(buf, " :qptargetlist ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->targetlist);
+ sprintf(buf, " :qpqual ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->qual);
+ sprintf(buf, " :lefttree ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->lefttree);
+ sprintf(buf, " :righttree ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->righttree);
+
+}
+
+/*
+ * Stuff from plannodes.h
+ */
+static void
+_outPlan(StringInfo str, Plan *node)
+{
+ char buf[500];
+
+ sprintf(buf, "PLAN");
+ appendStringInfo(str,buf);
+ _outPlanInfo(str, (Plan*) node);
+
+}
+
+static void
+_outResult(StringInfo str, Result *node)
+{
+ char buf[500];
+
+ sprintf(buf, "RESULT");
+ appendStringInfo(str,buf);
+ _outPlanInfo(str, (Plan*) node);
+
+ sprintf(buf, " :resconstantqual ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->resconstantqual);
+
+}
+
+/*
+ * Existential is a subclass of Plan.
+ */
+static void
+_outExistential(StringInfo str, Existential *node)
+{
+ char buf[500];
+
+ sprintf(buf, "EXISTENTIAL");
+ appendStringInfo(str,buf);
+ _outPlanInfo(str, (Plan*) node);
+
+
+}
+
+/*
+ * Append is a subclass of Plan.
+ */
+static void
+_outAppend(StringInfo str, Append *node)
+{
+ char buf[500];
+
+ sprintf(buf, "APPEND");
+ appendStringInfo(str,buf);
+ _outPlanInfo(str, (Plan*) node);
+
+ sprintf(buf, " :unionplans ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->unionplans);
+
+ sprintf(buf, " :unionrelid %d", node->unionrelid);
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :unionrtentries ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->unionrtentries);
+
+}
+
+/*
+ * Join is a subclass of Plan
+ */
+static void
+_outJoin(StringInfo str, Join *node)
+{
+ char buf[500];
+
+ sprintf(buf, "JOIN");
+ appendStringInfo(str,buf);
+ _outPlanInfo(str, (Plan*) node);
+
+}
+
+/*
+ * NestLoop is a subclass of Join
+ */
+static void
+_outNestLoop(StringInfo str, NestLoop *node)
+{
+ char buf[500];
+
+ sprintf(buf, "NESTLOOP");
+ appendStringInfo(str,buf);
+ _outPlanInfo(str, (Plan*) node);
+}
+
+/*
+ * MergeJoin is a subclass of Join
+ */
+static void
+_outMergeJoin(StringInfo str, MergeJoin *node)
+{
+ char buf[500];
+
+ sprintf(buf, "MERGEJOIN");
+ appendStringInfo(str,buf);
+ _outPlanInfo(str, (Plan*) node);
+
+ sprintf(buf, " :mergeclauses ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->mergeclauses);
+
+ sprintf(buf, " :mergesortop %d", node->mergesortop);
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :mergerightorder %d", node->mergerightorder[0]);
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :mergeleftorder %d", node->mergeleftorder[0]);
+ appendStringInfo(str, buf);
+}
+
+/*
+ * HashJoin is a subclass of Join.
+ */
+static void
+_outHashJoin(StringInfo str, HashJoin *node)
+{
+ char buf[500];
+
+ sprintf(buf, "HASHJOIN");
+ appendStringInfo(str,buf);
+ _outPlanInfo(str, (Plan*) node);
+
+ sprintf(buf, " :hashclauses ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->hashclauses);
+
+ sprintf(buf, " :hashjoinop %d",node->hashjoinop);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :hashjointable 0x%x", (int) node->hashjointable);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :hashjointablekey %d", node->hashjointablekey);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :hashjointablesize %d", node->hashjointablesize);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :hashdone %d", node->hashdone);
+ appendStringInfo(str,buf);
+}
+
+/*
+ * Scan is a subclass of Node
+ */
+static void
+_outScan(StringInfo str, Scan *node)
+{
+ char buf[500];
+
+ sprintf(buf, "SCAN");
+ appendStringInfo(str,buf);
+ _outPlanInfo(str, (Plan*) node);
+
+ sprintf(buf, " :scanrelid %d", node->scanrelid);
+ appendStringInfo(str,buf);
+
+}
+
+/*
+ * SeqScan is a subclass of Scan
+ */
+static void
+_outSeqScan(StringInfo str, SeqScan *node)
+{
+ char buf[500];
+
+ sprintf(buf, "SEQSCAN");
+ appendStringInfo(str,buf);
+ _outPlanInfo(str, (Plan*) node);
+
+ sprintf(buf, " :scanrelid %d", node->scanrelid);
+ appendStringInfo(str,buf);
+
+
+}
+
+/*
+ * IndexScan is a subclass of Scan
+ */
+static void
+_outIndexScan(StringInfo str, IndexScan *node)
+{
+ char buf[500];
+
+ sprintf(buf, "INDEXSCAN");
+ appendStringInfo(str,buf);
+ _outPlanInfo(str, (Plan*) node);
+
+ sprintf(buf, " :scanrelid %d", node->scan.scanrelid);
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :indxid ");
+ appendStringInfo(str,buf);
+ _outIntList(str, node->indxid);
+
+ sprintf(buf, " :indxqual ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->indxqual);
+
+}
+
+/*
+ * Temp is a subclass of Plan
+ */
+static void
+_outTemp(StringInfo str, Temp *node)
+{
+ char buf[500];
+
+ sprintf(buf, "TEMP");
+ appendStringInfo(str,buf);
+ _outPlanInfo(str, (Plan*) node);
+
+ sprintf(buf, " :tempid %d", node->tempid);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :keycount %d", node->keycount);
+ appendStringInfo(str,buf);
+
+}
+
+/*
+ * Sort is a subclass of Temp
+ */
+static void
+_outSort(StringInfo str, Sort *node)
+{
+ char buf[500];
+
+ sprintf(buf, "SORT");
+ appendStringInfo(str,buf);
+ _outPlanInfo(str, (Plan*) node);
+
+ sprintf(buf, " :tempid %d", node->tempid);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :keycount %d", node->keycount);
+ appendStringInfo(str,buf);
+
+}
+
+static void
+_outAgg(StringInfo str, Agg *node)
+{
+ char buf[500];
+ sprintf(buf, "AGG");
+ appendStringInfo(str,buf);
+ _outPlanInfo(str,(Plan*)node);
+
+ /* the actual Agg fields */
+ sprintf(buf, " :numagg %d ", node->numAgg);
+ appendStringInfo(str, buf);
+}
+
+static void
+_outGroup(StringInfo str, Group *node)
+{
+ char buf[500];
+ sprintf(buf, "GRP");
+ appendStringInfo(str,buf);
+ _outPlanInfo(str,(Plan*)node);
+
+ /* the actual Group fields */
+ sprintf(buf, " :numCols %d ", node->numCols);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :tuplePerGroup %s", node->tuplePerGroup ? "true" : "nil");
+ appendStringInfo(str, buf);
+}
+
+
+
+/*
+ * For some reason, unique is a subclass of Temp.
+ */
+static void
+_outUnique(StringInfo str, Unique *node)
+{
+ char buf[500];
+
+ sprintf(buf, "UNIQUE");
+ appendStringInfo(str,buf);
+ _outPlanInfo(str, (Plan*) node);
+
+ sprintf(buf, " :tempid %d", node->tempid);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :keycount %d", node->keycount);
+ appendStringInfo(str,buf);
+
+}
+
+
+/*
+ * Hash is a subclass of Temp
+ */
+static void
+_outHash(StringInfo str, Hash *node)
+{
+ char buf[500];
+
+ sprintf(buf, "HASH");
+ appendStringInfo(str,buf);
+ _outPlanInfo(str, (Plan*) node);
+
+ sprintf(buf, " :hashkey ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->hashkey);
+
+ sprintf(buf, " :hashtable 0x%x", (int) (node->hashtable));
+ appendStringInfo(str,buf);
+ sprintf(buf, " :hashtablekey %d", node->hashtablekey);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :hashtablesize %d", node->hashtablesize);
+ appendStringInfo(str,buf);
+}
+
+static void
+_outTee(StringInfo str, Tee *node)
+{
+ char buf[500];
+
+ sprintf(buf, "TEE");
+ appendStringInfo(str,buf);
+ _outPlanInfo(str, (Plan*) node);
+
+ sprintf(buf, " :leftParent %X", (int) (node->leftParent));
+ appendStringInfo(str,buf);
+ sprintf(buf, " :rightParent %X", (int) (node->rightParent));
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :rtentries ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->rtentries);
+}
+
+
+
+/*****************************************************************************
+ *
+ * Stuff from primnodes.h.
+ *
+ *****************************************************************************/
+
+
+/*
+ * Resdom is a subclass of Node
+ */
+static void
+_outResdom(StringInfo str, Resdom *node)
+{
+ char buf[500];
+
+ sprintf(buf, "RESDOM");
+ appendStringInfo(str,buf);
+ sprintf(buf, " :resno %hd", node->resno);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :restype %d", node->restype);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :reslen %d", node->reslen);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :resname \"%.*s\"", NAMEDATALEN,
+ ((node->resname) ? ((char *) node->resname) : "null"));
+ appendStringInfo(str,buf);
+ sprintf(buf, " :reskey %d", node->reskey);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :reskeyop %ld", (long int) node->reskeyop);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :resjunk %d", node->resjunk);
+ appendStringInfo(str,buf);
+
+}
+
+static void
+_outFjoin(StringInfo str, Fjoin *node)
+{
+ char buf[500];
+ int i;
+
+ sprintf(buf, "FJOIN");
+ appendStringInfo(str,buf);
+ sprintf(buf, " :initialized %s", node->fj_initialized ? "true":"nil");
+ appendStringInfo(str,buf);
+ sprintf(buf, " :nNodes %d", node->fj_nNodes);
+ appendStringInfo(str,buf);
+
+ appendStringInfo(str," :innerNode ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->fj_innerNode);
+
+ sprintf(buf, " :results @ 0x%x ", (int)(node->fj_results));
+ appendStringInfo(str, buf);
+
+ appendStringInfo( str, " :alwaysdone ");
+ for (i = 0; i<node->fj_nNodes; i++)
+ {
+ sprintf(buf, " %s ", ((node->fj_alwaysDone[i]) ? "true" : "nil"));
+ appendStringInfo(str, buf);
+ }
+}
+
+/*
+ * Expr is a subclass of Node
+ */
+static void
+_outExpr(StringInfo str, Expr *node)
+{
+ char buf[500];
+ char *opstr;
+
+ sprintf(buf, "EXPR");
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :typeOid %d", node->typeOid);
+ appendStringInfo(str,buf);
+ switch(node->opType) {
+ case OP_EXPR:
+ opstr = "op";
+ break;
+ case FUNC_EXPR:
+ opstr = "func";
+ break;
+ case OR_EXPR:
+ opstr = "or";
+ break;
+ case AND_EXPR:
+ opstr = "and";
+ break;
+ case NOT_EXPR:
+ opstr = "not";
+ break;
+ }
+ sprintf(buf, " :opType %s", opstr);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :oper ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->oper);
+ sprintf(buf, " :args ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->args);
+}
+
+/*
+ * Var is a subclass of Expr
+ */
+static void
+_outVar(StringInfo str, Var *node)
+{
+ char buf[500];
+
+ sprintf(buf, "VAR");
+ appendStringInfo(str,buf);
+ sprintf(buf, " :varno %d", node->varno);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :varattno %hd", node->varattno);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :vartype %d", node->vartype);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :varnoold %d", node->varnoold);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :varoattno %d", node->varoattno);
+ appendStringInfo(str,buf);
+}
+
+/*
+ * Const is a subclass of Expr
+ */
+static void
+_outConst(StringInfo str, Const *node)
+{
+ char buf[500];
+
+ sprintf(buf, "CONST");
+ appendStringInfo(str,buf);
+ sprintf(buf, " :consttype %d", node->consttype);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :constlen %hd", node->constlen);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :constisnull %s", (node->constisnull ? "true" : "nil"));
+ appendStringInfo(str,buf);
+ sprintf(buf, " :constvalue ");
+ appendStringInfo(str,buf);
+ if (node->constisnull) {
+ sprintf(buf, "NIL ");
+ appendStringInfo(str,buf);
+ } else {
+ _outDatum(str, node->constvalue, node->consttype);
+ }
+ sprintf(buf, " :constbyval %s", (node->constbyval ? "true" : "nil"));
+ appendStringInfo(str,buf);
+
+}
+
+/*
+ * Aggreg
+ */
+static void
+_outAggreg(StringInfo str, Aggreg *node)
+{
+ char buf[500];
+
+ sprintf(buf, "AGGREG");
+ appendStringInfo(str,buf);
+ sprintf(buf, " :aggname \"%.*s\"", NAMEDATALEN, (char*)node->aggname);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :basetype %d", node->basetype);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :aggtype %d", node->aggtype);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :aggno %d", node->aggno);
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :target ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->target);
+}
+
+/*
+ * Array is a subclass of Expr
+ */
+static void
+_outArray(StringInfo str, Array *node)
+{
+ char buf[500];
+ int i;
+ sprintf(buf, "ARRAY");
+ appendStringInfo(str, buf);
+ sprintf(buf, " :arrayelemtype %d", node->arrayelemtype);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :arrayelemlength %d", node->arrayelemlength);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :arrayelembyval %c", (node->arrayelembyval) ? 't' : 'f');
+ appendStringInfo(str, buf);
+ sprintf(buf, " :arrayndim %d", node->arrayndim);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :arraylow ");
+ appendStringInfo(str, buf);
+ for (i = 0; i < node->arrayndim; i++){
+ sprintf(buf, " %d", node->arraylow.indx[i]);
+ appendStringInfo(str, buf);
+ }
+ sprintf(buf, " :arrayhigh ");
+ appendStringInfo(str, buf);
+ for (i = 0; i < node->arrayndim; i++){
+ sprintf(buf, " %d", node->arrayhigh.indx[i]);
+ appendStringInfo(str, buf);
+ }
+ sprintf(buf, " :arraylen %d", node->arraylen);
+ appendStringInfo(str, buf);
+}
+
+/*
+ * ArrayRef is a subclass of Expr
+ */
+static void
+_outArrayRef(StringInfo str, ArrayRef *node)
+{
+ char buf[500];
+
+ sprintf(buf, "ARRAYREF");
+ appendStringInfo(str, buf);
+ sprintf(buf, " :refelemtype %d", node->refelemtype);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :refattrlength %d", node->refattrlength);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :refelemlength %d", node->refelemlength);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :refelembyval %c", (node->refelembyval) ? 't' : 'f');
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :refupperindex ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->refupperindexpr);
+
+ sprintf(buf, " :reflowerindex ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->reflowerindexpr);
+
+ sprintf(buf, " :refexpr ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->refexpr);
+
+ sprintf(buf, " :refassgnexpr ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->refassgnexpr);
+}
+
+/*
+ * Func is a subclass of Expr
+ */
+static void
+_outFunc(StringInfo str, Func *node)
+{
+ char buf[500];
+
+ sprintf(buf, "FUNC");
+ appendStringInfo(str,buf);
+ sprintf(buf, " :funcid %d", node->funcid);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :functype %d", node->functype);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :funcisindex %s",
+ (node->funcisindex ? "true" : "nil"));
+ appendStringInfo(str,buf);
+ sprintf(buf, " :funcsize %d", node->funcsize);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :func_fcache @ 0x%x", (int)(node->func_fcache));
+ appendStringInfo(str, buf);
+
+ appendStringInfo(str, " :func_tlist ");
+ _outNode(str, node->func_tlist);
+
+ appendStringInfo(str, " :func_planlist ");
+ _outNode(str, node->func_planlist);
+}
+
+/*
+ * Oper is a subclass of Expr
+ */
+static void
+_outOper(StringInfo str, Oper *node)
+{
+ char buf[500];
+
+ sprintf(buf, "OPER");
+ appendStringInfo(str,buf);
+ sprintf(buf, " :opno %d", node->opno);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :opid %d", node->opid);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :opresulttype %d", node->opresulttype);
+ appendStringInfo(str,buf);
+
+}
+
+/*
+ * Param is a subclass of Expr
+ */
+static void
+_outParam(StringInfo str, Param *node)
+{
+ char buf[500];
+
+ sprintf(buf, "PARAM");
+ appendStringInfo(str,buf);
+ sprintf(buf, " :paramkind %d", node->paramkind);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :paramid %hd", node->paramid);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :paramname \"%.*s\"", NAMEDATALEN, node->paramname);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :paramtype %d", node->paramtype);
+ appendStringInfo(str,buf);
+
+ appendStringInfo(str, " :param_tlist ");
+ _outNode(str, node->param_tlist);
+}
+
+/*
+ * Stuff from execnodes.h
+ */
+
+/*
+ * EState is a subclass of Node.
+ */
+static void
+_outEState(StringInfo str, EState *node)
+{
+ char buf[500];
+
+ sprintf(buf, "ESTATE");
+ appendStringInfo(str,buf);
+ sprintf(buf, " :direction %d", node->es_direction);
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :range_table ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->es_range_table);
+
+ sprintf(buf, " :result_relation_info @ 0x%x",
+ (int) (node->es_result_relation_info));
+ appendStringInfo(str,buf);
+
+}
+
+/*
+ * Stuff from relation.h
+ */
+static void
+_outRel(StringInfo str, Rel *node)
+{
+ char buf[500];
+
+ sprintf(buf, "REL");
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :relids ");
+ appendStringInfo(str,buf);
+ _outIntList(str, node->relids);
+
+ sprintf(buf, " :indexed %s", (node->indexed ? "true" : "nil"));
+ appendStringInfo(str,buf);
+ sprintf(buf, " :pages %u", node->pages);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :tuples %u", node->tuples);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :size %u", node->size);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :width %u", node->width);
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :targetlist ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->targetlist);
+
+ sprintf(buf, " :pathlist ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->pathlist);
+
+ /*
+ * Not sure if these are nodes or not. They're declared as
+ * struct Path *. Since i don't know, i'll just print the
+ * addresses for now. This can be changed later, if necessary.
+ */
+
+ sprintf(buf, " :unorderedpath @ 0x%x", (int)(node->unorderedpath));
+ appendStringInfo(str,buf);
+ sprintf(buf, " :cheapestpath @ 0x%x", (int)(node->cheapestpath));
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :pruneable %s", (node->pruneable ? "true" : "nil"));
+ appendStringInfo(str,buf);
+
+#if 0
+ sprintf(buf, " :classlist ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->classlist);
+
+ sprintf(buf, " :indexkeys ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->indexkeys);
+
+ sprintf(buf, " :ordering ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->ordering);
+#endif
+
+ sprintf(buf, " :clauseinfo ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->clauseinfo);
+
+ sprintf(buf, " :joininfo ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->joininfo);
+
+ sprintf(buf, " :innerjoin ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->innerjoin);
+
+}
+
+/*
+ * TargetEntry is a subclass of Node.
+ */
+static void
+_outTargetEntry(StringInfo str, TargetEntry *node)
+{
+ char buf[500];
+
+ sprintf(buf, "TLE");
+ appendStringInfo(str,buf);
+ sprintf(buf, " :resdom ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->resdom);
+
+ sprintf(buf, " :expr ");
+ appendStringInfo(str,buf);
+ if (node->expr) {
+ _outNode(str, node->expr);
+ }else {
+ appendStringInfo(str, "nil");
+ }
+}
+
+static void
+_outRangeTblEntry(StringInfo str, RangeTblEntry *node)
+{
+ char buf[500];
+
+ sprintf(buf, "RTE");
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :relname \"%.*s\"", NAMEDATALEN,
+ ((node->relname) ? ((char *) node->relname) : "null"));
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :inh %d ", node->inh);
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :refname \"%.*s\"", NAMEDATALEN,
+ ((node->refname) ? ((char *) node->refname) : "null"));
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :relid %d ", node->relid);
+ appendStringInfo(str,buf);
+}
+
+/*
+ * Path is a subclass of Node.
+ */
+static void
+_outPath(StringInfo str, Path *node)
+{
+ char buf[500];
+
+ sprintf(buf, "PATH");
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :pathtype %d", node->pathtype);
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :cost %f", node->path_cost);
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :keys ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->keys);
+
+}
+
+/*
+ * IndexPath is a subclass of Path.
+ */
+static void
+_outIndexPath(StringInfo str, IndexPath *node)
+{
+ char buf[500];
+
+ sprintf(buf, "INDEXPATH");
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :pathtype %d", node->path.pathtype);
+ appendStringInfo(str,buf);
+
+ /* sprintf(buf, " :parent ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->parent); */
+
+ sprintf(buf, " :cost %f", node->path.path_cost);
+ appendStringInfo(str,buf);
+
+#if 0
+ sprintf(buf, " :p_ordering ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->path.p_ordering);
+#endif
+ sprintf(buf, " :keys ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->path.keys);
+
+ sprintf(buf, " :indexid ");
+ appendStringInfo(str,buf);
+ _outIntList(str, node->indexid);
+
+ sprintf(buf, " :indexqual ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->indexqual);
+
+}
+
+/*
+ * JoinPath is a subclass of Path
+ */
+static void
+_outJoinPath(StringInfo str, JoinPath *node)
+{
+ char buf[500];
+
+ sprintf(buf, "JOINPATH");
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :pathtype %d", node->path.pathtype);
+ appendStringInfo(str,buf);
+
+ /* sprintf(buf, " :parent ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->parent); */
+
+ sprintf(buf, " :cost %f", node->path.path_cost);
+ appendStringInfo(str,buf);
+
+#if 0
+ sprintf(buf, " :p_ordering ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->path.p_ordering);
+#endif
+ sprintf(buf, " :keys ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->path.keys);
+
+ sprintf(buf, " :pathclauseinfo ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->pathclauseinfo);
+
+ /*
+ * Not sure if these are nodes; they're declared as "struct path *".
+ * For now, i'll just print the addresses.
+ */
+
+ sprintf(buf, " :outerjoinpath @ 0x%x", (int)(node->outerjoinpath));
+ appendStringInfo(str,buf);
+ sprintf(buf, " :innerjoinpath @ 0x%x", (int)(node->innerjoinpath));
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :outerjoincost %f", node->path.outerjoincost);
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :joinid ");
+ appendStringInfo(str,buf);
+ _outIntList(str, node->path.joinid);
+
+}
+
+/*
+ * MergePath is a subclass of JoinPath.
+ */
+static void
+_outMergePath(StringInfo str, MergePath *node)
+{
+ char buf[500];
+
+ sprintf(buf, "MERGEPATH");
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :pathtype %d", node->jpath.path.pathtype);
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :cost %f", node->jpath.path.path_cost);
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :keys ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->jpath.path.keys);
+
+ sprintf(buf, " :pathclauseinfo ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->jpath.pathclauseinfo);
+
+ /*
+ * Not sure if these are nodes; they're declared as "struct path *".
+ * For now, i'll just print the addresses.
+ */
+
+ sprintf(buf, " :outerjoinpath @ 0x%x", (int)(node->jpath.outerjoinpath));
+ appendStringInfo(str,buf);
+ sprintf(buf, " :innerjoinpath @ 0x%x", (int)(node->jpath.innerjoinpath));
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :outerjoincost %f", node->jpath.path.outerjoincost);
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :joinid ");
+ appendStringInfo(str,buf);
+ _outIntList(str, node->jpath.path.joinid);
+
+ sprintf(buf, " :path_mergeclauses ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->path_mergeclauses);
+
+ sprintf(buf, " :outersortkeys ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->outersortkeys);
+
+ sprintf(buf, " :innersortkeys ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->innersortkeys);
+
+}
+
+/*
+ * HashPath is a subclass of JoinPath.
+ */
+static void
+_outHashPath(StringInfo str, HashPath *node)
+{
+ char buf[500];
+
+ sprintf(buf, "HASHPATH");
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :pathtype %d", node->jpath.path.pathtype);
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :cost %f", node->jpath.path.path_cost);
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :keys ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->jpath.path.keys);
+
+ sprintf(buf, " :pathclauseinfo ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->jpath.pathclauseinfo);
+
+ /*
+ * Not sure if these are nodes; they're declared as "struct path *".
+ * For now, i'll just print the addresses.
+ */
+
+ sprintf(buf, " :outerjoinpath @ 0x%x", (int) (node->jpath.outerjoinpath));
+ appendStringInfo(str,buf);
+ sprintf(buf, " :innerjoinpath @ 0x%x", (int) (node->jpath.innerjoinpath));
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :outerjoincost %f", node->jpath.path.outerjoincost);
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :joinid ");
+ appendStringInfo(str,buf);
+ _outIntList(str, node->jpath.path.joinid);
+
+ sprintf(buf, " :path_hashclauses ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->path_hashclauses);
+
+ sprintf(buf, " :outerhashkeys ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->outerhashkeys);
+
+ sprintf(buf, " :innerhashkeys ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->innerhashkeys);
+
+}
+
+/*
+ * OrderKey is a subclass of Node.
+ */
+static void
+_outOrderKey(StringInfo str, OrderKey *node)
+{
+ char buf[500];
+
+ sprintf(buf, "ORDERKEY");
+ appendStringInfo(str,buf);
+ sprintf(buf, " :attribute_number %d", node->attribute_number);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :array_index %d", node->array_index);
+ appendStringInfo(str,buf);
+
+}
+
+/*
+ * JoinKey is a subclass of Node.
+ */
+static void
+_outJoinKey(StringInfo str, JoinKey *node)
+{
+ char buf[500];
+
+ sprintf(buf, "JOINKEY");
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :outer ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->outer);
+
+ sprintf(buf, " :inner ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->inner);
+
+}
+
+/*
+ * MergeOrder is a subclass of Node.
+ */
+static void
+_outMergeOrder(StringInfo str, MergeOrder *node)
+{
+ char buf[500];
+
+ sprintf(buf, "MERGEORDER");
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :join_operator %d", node->join_operator);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :left_operator %d", node->left_operator);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :right_operator %d", node->right_operator);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :left_type %d", node->left_type);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :right_type %d", node->right_type);
+ appendStringInfo(str,buf);
+
+}
+
+/*
+ * CInfo is a subclass of Node.
+ */
+static void
+_outCInfo(StringInfo str, CInfo *node)
+{
+ char buf[500];
+
+ sprintf(buf, "CINFO");
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :clause ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->clause);
+
+ sprintf(buf, " :selectivity %f", node->selectivity);
+ appendStringInfo(str,buf);
+ sprintf(buf, " :notclause %s", (node->notclause ? "true" : "nil"));
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :indexids ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->indexids);
+
+ sprintf(buf, " :mergesortorder ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->mergesortorder);
+
+ sprintf(buf, " :hashjoinoperator %d", node->hashjoinoperator);
+ appendStringInfo(str,buf);
+
+}
+
+/*
+ * JoinMethod is a subclass of Node.
+ */
+static void
+_outJoinMethod(StringInfo str, JoinMethod *node)
+{
+ char buf[500];
+
+ sprintf(buf, "JOINMETHOD");
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :jmkeys ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->jmkeys);
+
+ sprintf(buf, " :clauses ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->clauses);
+
+
+}
+
+/*
+ * HInfo is a subclass of JoinMethod.
+ */
+static void
+_outHInfo(StringInfo str, HInfo *node)
+{
+ char buf[500];
+
+ sprintf(buf, "HASHINFO");
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :hashop ");
+ appendStringInfo(str,buf);
+ sprintf(buf, "%d",node->hashop);
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :jmkeys ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->jmethod.jmkeys);
+
+ sprintf(buf, " :clauses ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->jmethod.clauses);
+
+}
+
+/*
+ * JInfo is a subclass of Node.
+ */
+static void
+_outJInfo(StringInfo str, JInfo *node)
+{
+ char buf[500];
+
+ sprintf(buf, "JINFO");
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :otherrels ");
+ appendStringInfo(str,buf);
+ _outIntList(str, node->otherrels);
+
+ sprintf(buf, " :jinfoclauseinfo ");
+ appendStringInfo(str,buf);
+ _outNode(str, node->jinfoclauseinfo);
+
+ sprintf(buf, " :mergesortable %s",
+ (node->mergesortable ? "true" : "nil"));
+ appendStringInfo(str,buf);
+ sprintf(buf, " :hashjoinable %s",
+ (node->hashjoinable ? "true" : "nil"));
+ appendStringInfo(str,buf);
+
+}
+
+/*
+ * Print the value of a Datum given its type.
+ */
+static void
+_outDatum(StringInfo str, Datum value, Oid type)
+{
+ char buf[500];
+ Size length, typeLength;
+ bool byValue;
+ int i;
+ char *s;
+
+ /*
+ * find some information about the type and the "real" length
+ * of the datum.
+ */
+ byValue = get_typbyval(type);
+ typeLength = get_typlen(type);
+ length = datumGetSize(value, type, byValue, typeLength);
+
+ if (byValue) {
+ s = (char *) (&value);
+ sprintf(buf, " %d [ ", length);
+ appendStringInfo(str,buf);
+ for (i=0; i<sizeof(Datum); i++) {
+ sprintf(buf, "%d ", (int) (s[i]) );
+ appendStringInfo(str,buf);
+ }
+ sprintf(buf, "] ");
+ appendStringInfo(str,buf);
+ } else { /* !byValue */
+ s = (char *) DatumGetPointer(value);
+ if (!PointerIsValid(s)) {
+ sprintf(buf, " 0 [ ] ");
+ appendStringInfo(str,buf);
+ } else {
+ /*
+ * length is unsigned - very bad to do < comparison to -1 without
+ * casting it to int first!! -mer 8 Jan 1991
+ */
+ if (((int)length) <= -1) {
+ length = VARSIZE(s);
+ }
+ sprintf(buf, " %d [ ", length);
+ appendStringInfo(str,buf);
+ for (i=0; i<length; i++) {
+ sprintf(buf, "%d ", (int) (s[i]) );
+ appendStringInfo(str,buf);
+ }
+ sprintf(buf, "] ");
+ appendStringInfo(str,buf);
+ }
+ }
+
+}
+
+static void
+_outIter(StringInfo str, Iter *node)
+{
+ appendStringInfo(str,"ITER");
+
+ appendStringInfo(str," :iterexpr ");
+ _outNode(str, node->iterexpr);
+}
+
+static void
+_outStream(StringInfo str, Stream *node)
+{
+ char buf[500];
+
+ appendStringInfo(str,"STREAM");
+
+ sprintf(buf, " :pathptr @ 0x%x", (int)(node->pathptr));
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :cinfo @ 0x%x", (int)(node->cinfo));
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :clausetype %d", (int)(node->clausetype));
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :upstream @ 0x%x", (int)(node->upstream));
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :downstream @ 0x%x", (int)(node->downstream));
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :groupup %d", node->groupup);
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :groupcost %f", node->groupcost);
+ appendStringInfo(str,buf);
+
+ sprintf(buf, " :groupsel %f", node->groupsel);
+ appendStringInfo(str,buf);
+}
+
+static void
+_outValue(StringInfo str, Value *value)
+{
+ char buf[500];
+
+ switch(value->type) {
+ case T_String:
+ sprintf(buf, "\"%s\"", value->val.str);
+ appendStringInfo(str, buf);
+ break;
+ case T_Integer:
+ sprintf(buf, "%ld", value->val.ival);
+ appendStringInfo(str, buf);
+ break;
+ case T_Float:
+ sprintf(buf, "%f", value->val.dval);
+ appendStringInfo(str, buf);
+ break;
+ default:
+ break;
+ }
+ return;
+}
+
+/*
+ * _outNode -
+ * converts a Node into ascii string and append it to 'str'
+ */
+static void
+_outNode(StringInfo str, void *obj)
+{
+ if (obj==NULL) {
+ appendStringInfo(str, "nil");
+ return;
+ }
+
+ if (nodeTag(obj)==T_List) {
+ List *l;
+ appendStringInfo(str, "(");
+ foreach(l, (List*)obj) {
+ _outNode(str, lfirst(l));
+ if (lnext(l))
+ appendStringInfo(str, " ");
+ }
+ appendStringInfo(str, ")");
+ }else {
+ appendStringInfo(str, "{");
+ switch(nodeTag(obj)) {
+ case T_Query:
+ _outQuery(str, obj);
+ break;
+ case T_Plan:
+ _outPlan(str, obj);
+ break;
+ case T_Result:
+ _outResult(str, obj);
+ break;
+ case T_Existential:
+ _outExistential(str, obj);
+ break;
+ case T_Append:
+ _outAppend(str, obj);
+ break;
+ case T_Join:
+ _outJoin(str, obj);
+ break;
+ case T_NestLoop:
+ _outNestLoop(str, obj);
+ break;
+ case T_MergeJoin:
+ _outMergeJoin(str, obj);
+ break;
+ case T_HashJoin:
+ _outHashJoin(str, obj);
+ break;
+ case T_Scan:
+ _outScan(str, obj);
+ break;
+ case T_SeqScan:
+ _outSeqScan(str, obj);
+ break;
+ case T_IndexScan:
+ _outIndexScan(str, obj);
+ break;
+ case T_Temp:
+ _outTemp(str, obj);
+ break;
+ case T_Sort:
+ _outSort(str, obj);
+ break;
+ case T_Agg:
+ _outAgg(str, obj);
+ break;
+ case T_Group:
+ _outGroup(str, obj);
+ break;
+ case T_Unique:
+ _outUnique(str, obj);
+ break;
+ case T_Hash:
+ _outHash(str, obj);
+ break;
+ case T_Tee:
+ _outTee(str, obj);
+ break;
+ case T_Resdom:
+ _outResdom(str, obj);
+ break;
+ case T_Fjoin:
+ _outFjoin(str, obj);
+ break;
+ case T_Expr:
+ _outExpr(str, obj);
+ break;
+ case T_Var:
+ _outVar(str, obj);
+ break;
+ case T_Const:
+ _outConst(str, obj);
+ break;
+ case T_Aggreg:
+ _outAggreg(str, obj);
+ break;
+ case T_Array:
+ _outArray(str, obj);
+ break;
+ case T_ArrayRef:
+ _outArrayRef(str, obj);
+ break;
+ case T_Func:
+ _outFunc(str, obj);
+ break;
+ case T_Oper:
+ _outOper(str, obj);
+ break;
+ case T_Param:
+ _outParam(str, obj);
+ break;
+ case T_EState:
+ _outEState(str, obj);
+ break;
+ case T_Rel:
+ _outRel(str, obj);
+ break;
+ case T_TargetEntry:
+ _outTargetEntry(str, obj);
+ break;
+ case T_RangeTblEntry:
+ _outRangeTblEntry(str, obj);
+ break;
+ case T_Path:
+ _outPath(str, obj);
+ break;
+ case T_IndexPath:
+ _outIndexPath (str, obj);
+ break;
+ case T_JoinPath:
+ _outJoinPath(str, obj);
+ break;
+ case T_MergePath:
+ _outMergePath(str, obj);
+ break;
+ case T_HashPath:
+ _outHashPath(str, obj);
+ break;
+ case T_OrderKey:
+ _outOrderKey(str, obj);
+ break;
+ case T_JoinKey:
+ _outJoinKey(str, obj);
+ break;
+ case T_MergeOrder:
+ _outMergeOrder(str, obj);
+ break;
+ case T_CInfo:
+ _outCInfo(str, obj);
+ break;
+ case T_JoinMethod:
+ _outJoinMethod(str, obj);
+ break;
+ case T_HInfo:
+ _outHInfo(str, obj);
+ break;
+ case T_JInfo:
+ _outJInfo(str, obj);
+ break;
+ case T_Iter:
+ _outIter(str, obj);
+ break;
+ case T_Stream:
+ _outStream(str, obj);
+ break;
+ case T_Integer: case T_String: case T_Float:
+ _outValue(str, obj);
+ break;
+ default:
+ elog(NOTICE, "_outNode: don't know how to print type %d",
+ nodeTag(obj));
+ break;
+ }
+ appendStringInfo(str, "}");
+ }
+ return;
+}
+
+/*
+ * nodeToString -
+ * returns the ascii representation of the Node
+ */
+char *
+nodeToString(void *obj)
+{
+ StringInfo str;
+ char *s;
+
+ if (obj==NULL)
+ return "";
+ Assert(obj!=NULL);
+ str = makeStringInfo();
+ _outNode(str, obj);
+ s = str->data;
+ pfree(str);
+
+ return s;
+}
diff --git a/src/backend/nodes/params.h b/src/backend/nodes/params.h
new file mode 100644
index 0000000000..79ae9458db
--- /dev/null
+++ b/src/backend/nodes/params.h
@@ -0,0 +1,90 @@
+/*-------------------------------------------------------------------------
+ *
+ * params.h--
+ * Declarations/definitions of stuff needed to handle parameterized plans.
+ *
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id$
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PARAMS_H
+#define PARAMS_H
+
+#include "postgres.h"
+#include "access/attnum.h"
+
+/* ----------------------------------------------------------------
+ *
+ * The following are the possible values for the 'paramkind'
+ * field of a Param node.
+ *
+ * PARAM_NAMED: The parameter has a name, i.e. something
+ * like `$.salary' or `$.foobar'.
+ * In this case field `paramname' must be a valid Name.
+ * and field `paramid' must be == 0.
+ *
+ * PARAM_NUM: The parameter has only a numeric identifier,
+ * i.e. something like `$1', `$2' etc.
+ * The number is contained in the `parmid' field.
+ *
+ * PARAM_NEW: Used in PRS2 rule, similar to PARAM_NAMED.
+ * The `paramname' & `paramid' refer to the "NEW" tuple
+ * `paramname' is the attribute name and `paramid' its
+ * attribute number.
+ *
+ * PARAM_OLD: Same as PARAM_NEW, but in this case we refer to
+ * the "OLD" tuple.
+ */
+
+#define PARAM_NAMED 11
+#define PARAM_NUM 12
+#define PARAM_NEW 13
+#define PARAM_OLD 14
+#define PARAM_INVALID 100
+
+
+/* ----------------------------------------------------------------
+ * ParamListInfo
+ *
+ * Information needed in order for the executor to handle
+ * parameterized plans (you know, $.salary, $.name etc. stuff...).
+ *
+ * ParamListInfoData contains information needed when substituting a
+ * Param node with a Const node.
+ *
+ * kind : the kind of parameter.
+ * name : the parameter name (valid if kind == PARAM_NAMED,
+ * PARAM_NEW or PARAM_OLD)
+ * id : the parameter id (valid if kind == PARAM_NUM)
+ * or the attrno (if kind == PARAM_NEW or PARAM_OLD)
+ * type : PG_TYPE OID of the value
+ * length : length in bytes of the value
+ * isnull : true if & only if the value is null (if true then
+ * the fields 'length' and 'value' are undefined).
+ * value : the value that has to be substituted in the place
+ * of the parameter.
+ *
+ * ParamListInfo is to be used as an array of ParamListInfoData
+ * records. An 'InvalidName' in the name field of such a record
+ * indicates that this is the last record in the array.
+ *
+ * ----------------------------------------------------------------
+ */
+
+typedef struct ParamListInfoData {
+ int kind;
+ char *name;
+ AttrNumber id;
+ Oid type;
+ Size length;
+ bool isnull;
+ bool byval;
+ Datum value;
+} ParamListInfoData;
+
+typedef ParamListInfoData *ParamListInfo;
+
+#endif /* PARAMS_H */
diff --git a/src/backend/nodes/parsenodes.h b/src/backend/nodes/parsenodes.h
new file mode 100644
index 0000000000..3109cdaea3
--- /dev/null
+++ b/src/backend/nodes/parsenodes.h
@@ -0,0 +1,731 @@
+/*-------------------------------------------------------------------------
+ *
+ * parsenodes.h--
+ * definitions for parse tree nodes
+ *
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id$
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PARSENODES_H
+#define PARSENODES_H
+
+#include "nodes/nodes.h"
+#include "nodes/pg_list.h"
+#include "nodes/primnodes.h"
+#include "utils/tqual.h"
+
+/*****************************************************************************
+ * Query Tree
+ *****************************************************************************/
+
+/*
+ * Query -
+ * all statments are turned into a Query tree (via transformStmt)
+ * for further processing by the optimizer
+ * utility statements (i.e. non-optimizable statements)
+ * have the *utilityStmt field set.
+ *
+ * we need the isPortal flag because portal names can be null too; can
+ * get rid of it if we support CURSOR as a commandType.
+ *
+ */
+typedef struct Query {
+ NodeTag type;
+
+ CmdType commandType; /* select|insert|update|delete|utility */
+
+ Node *utilityStmt; /* non-null if this is a non-optimizable
+ statement */
+
+ int resultRelation; /* target relation (index to rtable) */
+ char *into; /* portal (cursor) name */
+ bool isPortal; /* is this a retrieve into portal? */
+ bool isBinary; /* binary portal? */
+
+ char *uniqueFlag; /* NULL, '*', or Unique attribute name */
+ List *sortClause; /* a list of SortClause's */
+
+ List *rtable; /* list of range table entries */
+ List *targetList; /* target list (of TargetEntry) */
+ Node *qual; /* qualifications */
+
+ List *groupClause; /* list of columns to specified in GROUP BY */
+ Node *havingQual; /* qualification of each group */
+
+ int qry_numAgg; /* number of aggregates in the target list */
+ Aggreg **qry_aggs; /* the aggregates */
+
+ /* internal to planner */
+ List *base_relation_list_; /* base relation list */
+ List *join_relation_list_; /* list of relations generated by joins */
+ bool query_is_archival_; /* archival query flag */
+} Query;
+
+
+/*****************************************************************************
+ * Other Statements (no optimizations required)
+ *
+ * Some of them require a little bit of transformation (which is also
+ * done by transformStmt). The whole structure is then passed on to
+ * ProcessUtility (by-passing the optimization step) as the utilityStmt
+ * field in Query.
+ *****************************************************************************/
+
+/* ----------------------
+ * Add Column Statement
+ * ----------------------
+ */
+typedef struct AddAttrStmt {
+ NodeTag type;
+ char *relname; /* the relation to add attr */
+ bool inh; /* add recursively to children? */
+ struct ColumnDef *colDef; /* the attribute definition */
+} AddAttrStmt;
+
+/* ----------------------
+ * Change ACL Statement
+ * ----------------------
+ */
+typedef struct ChangeACLStmt {
+ NodeTag type;
+ struct AclItem *aclitem;
+ unsigned modechg;
+ List *relNames;
+} ChangeACLStmt;
+
+/* ----------------------
+ * Close Portal Statement
+ * ----------------------
+ */
+typedef struct ClosePortalStmt {
+ NodeTag type;
+ char *portalname; /* name of the portal (cursor) */
+} ClosePortalStmt;
+
+/* ----------------------
+ * Copy Statement
+ * ----------------------
+ */
+typedef struct CopyStmt {
+ NodeTag type;
+ bool binary; /* is a binary copy? */
+ char *relname; /* the relation to copy */
+ int direction; /* TO or FROM */
+ char *filename; /* if NULL, use stdin/stdout */
+ char *delimiter; /* delimiter character, \t by default*/
+} CopyStmt;
+
+/* ----------------------
+ * Create Table Statement
+ * ----------------------
+ */
+typedef enum ArchType {
+ ARCH_NONE, ARCH_LIGHT, ARCH_HEAVY /* archive mode */
+} ArchType;
+
+typedef struct CreateStmt {
+ NodeTag type;
+ char *relname; /* the relation to create */
+ List *tableElts; /* column definitions
+ list of ColumnDef */
+ List *inhRelnames; /* relations to inherit from
+ list of Value (string) */
+ ArchType archiveType; /* archive mode (ARCH_NONE if none */
+ int location; /* smgrid (-1 if none) */
+ int archiveLoc; /* smgrid (-1 if none) */
+} CreateStmt;
+
+/* ----------------------
+ * Create Version Statement
+ * ----------------------
+ */
+typedef struct VersionStmt {
+ NodeTag type;
+ char *relname; /* the new relation */
+ int direction; /* FORWARD | BACKWARD */
+ char *fromRelname; /* relation to create a version */
+ char *date; /* date of the snapshot */
+} VersionStmt;
+
+/* ----------------------
+ * Create {Operator|Type|Aggregate} Statement
+ * ----------------------
+ */
+typedef struct DefineStmt {
+ NodeTag type;
+ int defType; /* OPERATOR|P_TYPE|AGGREGATE*/
+ char *defname;
+ List *definition; /* a list of DefElem */
+} DefineStmt;
+
+/* ----------------------
+ * Drop Table Statement
+ * ----------------------
+ */
+typedef struct DestroyStmt {
+ NodeTag type;
+ List *relNames; /* relations to be dropped */
+} DestroyStmt;
+
+/* ----------------------
+ * Extend Index Statement
+ * ----------------------
+ */
+typedef struct ExtendStmt {
+ NodeTag type;
+ char *idxname; /* name of the index */
+ Node *whereClause; /* qualifications */
+ List *rangetable; /* range table, filled in
+ by transformStmt() */
+} ExtendStmt;
+
+/* ----------------------
+ * Begin Recipe Statement
+ * ----------------------
+ */
+typedef struct RecipeStmt {
+ NodeTag type;
+ char *recipeName; /* name of the recipe*/
+} RecipeStmt;
+
+/* ----------------------
+ * Fetch Statement
+ * ----------------------
+ */
+typedef struct FetchStmt {
+ NodeTag type;
+ int direction; /* FORWARD or BACKWARD */
+ int howMany; /* amount to fetch ("ALL" --> 0) */
+ char *portalname; /* name of portal (cursor) */
+} FetchStmt;
+
+/* ----------------------
+ * Create Index Statement
+ * ----------------------
+ */
+typedef struct IndexStmt {
+ NodeTag type;
+ char *idxname; /* name of the index */
+ char *relname; /* name of relation to index on */
+ char *accessMethod; /* name of acess methood (eg. btree) */
+ List *indexParams; /* a list of IndexElem */
+ List *withClause; /* a list of ParamString */
+ Node *whereClause; /* qualifications */
+ List *rangetable; /* range table, filled in
+ by transformStmt() */
+} IndexStmt;
+
+/* ----------------------
+ * Move Statement (Not implemented)
+ * ----------------------
+ */
+typedef struct MoveStmt {
+ NodeTag type;
+ int direction; /* FORWARD or BACKWARD */
+ bool to;
+ int where;
+ char *portalname;
+} MoveStmt;
+
+/* ----------------------
+ * Create Function Statement
+ * ----------------------
+ */
+typedef struct ProcedureStmt {
+ NodeTag type;
+ char *funcname; /* name of function to create */
+ List *defArgs; /* list of definitions
+ a list of strings (as Value *) */
+ Node *returnType; /* the return type (as a string or
+ a TypeName (ie.setof) */
+ List *withClause; /* a list of ParamString */
+ char *as; /* the SQL statement or filename */
+ char *language; /* C or SQL */
+} ProcedureStmt;
+
+/* ----------------------
+ * Purge Statement
+ * ----------------------
+ */
+typedef struct PurgeStmt {
+ NodeTag type;
+ char *relname; /* relation to purge */
+ char *beforeDate; /* purge before this date */
+ char *afterDate; /* purge after this date */
+} PurgeStmt;
+
+/* ----------------------
+ * Drop Function Statement
+ * ----------------------
+ */
+typedef struct RemoveFuncStmt {
+ NodeTag type;
+ char *funcname; /* function to drop */
+ List *args; /* types of the arguments */
+} RemoveFuncStmt;
+
+/* ----------------------
+ * Drop Operator Statement
+ * ----------------------
+ */
+typedef struct RemoveOperStmt {
+ NodeTag type;
+ char *opname; /* operator to drop */
+ List *args; /* types of the arguments */
+} RemoveOperStmt;
+
+/* ----------------------
+ * Drop {Aggregate|Type|Index|Rule|View} Statement
+ * ----------------------
+ */
+typedef struct RemoveStmt {
+ NodeTag type;
+ int removeType; /* AGGREGATE|P_TYPE|INDEX|RULE|VIEW */
+ char *name; /* name to drop */
+} RemoveStmt;
+
+/* ----------------------
+ * Alter Table Statement
+ * ----------------------
+ */
+typedef struct RenameStmt {
+ NodeTag type;
+ char *relname; /* relation to be altered */
+ bool inh; /* recursively alter children? */
+ char *column; /* if NULL, rename the relation name
+ to the new name. Otherwise, rename
+ this column name. */
+ char *newname; /* the new name */
+} RenameStmt;
+
+/* ----------------------
+ * Create Rule Statement
+ * ----------------------
+ */
+typedef struct RuleStmt {
+ NodeTag type;
+ char *rulename; /* name of the rule */
+ Node *whereClause; /* qualifications */
+ CmdType event; /* RETRIEVE */
+ struct Attr *object; /* object affected */
+ bool instead; /* is a 'do instead'? */
+ List *actions; /* the action statements */
+} RuleStmt;
+
+/* ----------------------
+ * Notify Statement
+ * ----------------------
+ */
+typedef struct NotifyStmt {
+ NodeTag type;
+ char *relname; /* relation to notify */
+} NotifyStmt;
+
+/* ----------------------
+ * Listen Statement
+ * ----------------------
+ */
+typedef struct ListenStmt {
+ NodeTag type;
+ char *relname; /* relation to listen on */
+} ListenStmt;
+
+/* ----------------------
+ * {Begin|Abort|End} Transaction Statement
+ * ----------------------
+ */
+typedef struct TransactionStmt {
+ NodeTag type;
+ int command; /* BEGIN|END|ABORT */
+} TransactionStmt;
+
+/* ----------------------
+ * Create View Statement
+ * ----------------------
+ */
+typedef struct ViewStmt {
+ NodeTag type;
+ char *viewname; /* name of the view */
+ Query *query; /* the SQL statement */
+} ViewStmt;
+
+/* ----------------------
+ * Load Statement
+ * ----------------------
+ */
+typedef struct LoadStmt {
+ NodeTag type;
+ char *filename; /* file to load */
+} LoadStmt;
+
+/* ----------------------
+ * Createdb Statement
+ * ----------------------
+ */
+typedef struct CreatedbStmt {
+ NodeTag type;
+ char *dbname; /* database to create */
+} CreatedbStmt;
+
+/* ----------------------
+ * Destroydb Statement
+ * ----------------------
+ */
+typedef struct DestroydbStmt {
+ NodeTag type;
+ char *dbname; /* database to drop */
+} DestroydbStmt;
+
+/* ----------------------
+ * Cluster Statement (support pbrown's cluster index implementation)
+ * ----------------------
+ */
+typedef struct ClusterStmt {
+ NodeTag type;
+ char *relname; /* relation being indexed */
+ char *indexname; /* original index defined */
+} ClusterStmt;
+
+/* ----------------------
+ * Vacuum Statement
+ * ----------------------
+ */
+typedef struct VacuumStmt {
+ NodeTag type;
+ char *vacrel; /* table to vacuum */
+} VacuumStmt;
+
+/* ----------------------
+ * Explain Statement
+ * ----------------------
+ */
+typedef struct ExplainStmt {
+ NodeTag type;
+ Query *query; /* the query */
+ List *options;
+} ExplainStmt;
+
+
+/*****************************************************************************
+ * Optimizable Statements
+ *****************************************************************************/
+
+/* ----------------------
+ * Insert Statement
+ * ----------------------
+ */
+typedef struct AppendStmt {
+ NodeTag type;
+ char *relname; /* relation to insert into */
+ List *cols; /* names of the columns */
+ List *exprs; /* the expressions (same order as
+ the columns) */
+ List *fromClause; /* the from clause */
+ Node *whereClause; /* qualifications */
+} AppendStmt;
+
+/* ----------------------
+ * Delete Statement
+ * ----------------------
+ */
+typedef struct DeleteStmt {
+ NodeTag type;
+ char *relname; /* relation to delete from */
+ Node *whereClause; /* qualifications */
+} DeleteStmt;
+
+/* ----------------------
+ * Update Statement
+ * ----------------------
+ */
+typedef struct ReplaceStmt {
+ NodeTag type;
+ char *relname; /* relation to update */
+ List *targetList; /* the target list (of ResTarget) */
+ Node *whereClause; /* qualifications */
+ List *fromClause; /* the from clause */
+} ReplaceStmt;
+
+/* ----------------------
+ * Create Cursor Statement
+ * ----------------------
+ */
+typedef struct CursorStmt {
+ NodeTag type;
+ char *portalname; /* the portal (cursor) to create */
+ bool binary; /* a binary (internal) portal? */
+ char *unique; /* NULL, "*", or unique attribute name */
+ List *targetList; /* the target list (of ResTarget) */
+ List *fromClause; /* the from clause */
+ Node *whereClause; /* qualifications */
+ List *orderClause; /* sort clause (a list of SortBy's) */
+} CursorStmt;
+
+/* ----------------------
+ * Select Statement
+ * ----------------------
+ */
+typedef struct RetrieveStmt {
+ NodeTag type;
+ char *unique; /* NULL, '*', or unique attribute name */
+ char *into; /* name of table (for select into
+ table) */
+ List *targetList; /* the target list (of ResTarget) */
+ List *fromClause; /* the from clause */
+ Node *whereClause; /* qualifications */
+ List *groupClause; /* group by clause */
+ Node *havingClause; /* having conditional-expression */
+ List *orderClause; /* sort clause (a list of SortBy's) */
+} RetrieveStmt;
+
+
+/****************************************************************************
+ * Supporting data structures for Parse Trees
+ ****************************************************************************/
+
+/*
+ * TypeName - specifies a type in definitions
+ */
+typedef struct TypeName {
+ NodeTag type;
+ char *name; /* name of the type */
+ bool setof; /* is a set? */
+ List *arrayBounds; /* array bounds */
+ int typlen; /* length for char() and varchar() */
+} TypeName;
+
+/*
+ * ParamNo - specifies a parameter reference
+ */
+typedef struct ParamNo {
+ NodeTag type;
+ int number; /* the number of the parameter */
+ TypeName *typename; /* the typecast */
+} ParamNo;
+
+/*
+ * A_Expr - binary expressions
+ */
+typedef struct A_Expr {
+ NodeTag type;
+ int oper; /* type of operation
+ {OP,OR,AND,NOT,ISNULL,NOTNULL} */
+ char *opname; /* name of operator/function */
+ Node *lexpr; /* left argument */
+ Node *rexpr; /* right argument */
+} A_Expr;
+
+/*
+ * Attr -
+ * specifies an Attribute (ie. a Column); could have nested dots or
+ * array references.
+ *
+ */
+typedef struct Attr {
+ NodeTag type;
+ char *relname; /* name of relation (can be "*") */
+ ParamNo *paramNo; /* or a parameter */
+ List *attrs; /* attributes (possibly nested);
+ list of Values (strings) */
+ List *indirection; /* array refs (list of A_Indices') */
+} Attr;
+
+/*
+ * A_Const - a constant expression
+ */
+typedef struct A_Const {
+ NodeTag type;
+ Value val; /* the value (with the tag) */
+ TypeName *typename; /* typecast */
+} A_Const;
+
+/*
+ * ColumnDef - column definition (used in various creates)
+ */
+typedef struct ColumnDef {
+ NodeTag type;
+ char *colname; /* name of column */
+ TypeName *typename; /* type of column */
+} ColumnDef;
+
+/*
+ * Ident -
+ * an identifier (could be an attribute or a relation name). Depending
+ * on the context at transformStmt time, the identifier is treated as
+ * either a relation name (in which case, isRel will be set) or an
+ * attribute (in which case, it will be transformed into an Attr).
+ */
+typedef struct Ident {
+ NodeTag type;
+ char *name; /* its name */
+ List *indirection; /* array references */
+ bool isRel; /* is a relation - filled in by
+ transformExpr() */
+} Ident;
+
+/*
+ * FuncCall - a function/aggregate invocation
+ */
+typedef struct FuncCall {
+ NodeTag type;
+ char *funcname; /* name of function */
+ List *args; /* the arguments (list of exprs) */
+} FuncCall;
+
+/*
+ * A_Indices - array reference or bounds ([lidx:uidx] or [uidx])
+ */
+typedef struct A_Indices {
+ NodeTag type;
+ Node *lidx; /* could be NULL */
+ Node *uidx;
+} A_Indices;
+
+/*
+ * ResTarget -
+ * result target (used in target list of pre-transformed Parse trees)
+ */
+typedef struct ResTarget {
+ NodeTag type;
+ char *name; /* name of the result column */
+ List *indirection; /* array references */
+ Node *val; /* the value of the result
+ (A_Expr or Attr) */
+} ResTarget;
+
+/*
+ * ParamString - used in with clauses
+ */
+typedef struct ParamString {
+ NodeTag type;
+ char *name;
+ char *val;
+} ParamString;
+
+/*
+ * TimeRange - specifies a time range
+ */
+typedef struct TimeRange {
+ NodeTag type;
+ char *startDate;
+ char *endDate; /* snapshot if NULL */
+} TimeRange;
+
+/*
+ * RelExpr - relation expressions
+ */
+typedef struct RelExpr {
+ NodeTag type;
+ char *relname; /* the relation name */
+ bool inh; /* inheritance query */
+ TimeRange *timeRange; /* the time range */
+} RelExpr;
+
+/*
+ * Sortby - for order by clause
+ */
+typedef struct SortBy {
+ NodeTag type;
+ char *name; /* name of column to sort on */
+ char *useOp; /* operator to use */
+} SortBy;
+
+/*
+ * RangeVar - range variable, used in from clauses
+ */
+typedef struct RangeVar {
+ NodeTag type;
+ RelExpr *relExpr; /* the relation expression */
+ char *name; /* the name to be referenced
+ (optional) */
+} RangeVar;
+
+/*
+ * IndexElem - index parameters (used in create index)
+ */
+typedef struct IndexElem {
+ NodeTag type;
+ char *name; /* name of index */
+ List *args; /* if not NULL, function index */
+ char *class;
+} IndexElem;
+
+/*
+ * DefElem -
+ * a definition (used in definition lists in the form of defname = arg)
+ */
+typedef struct DefElem {
+ NodeTag type;
+ char *defname;
+ Node *arg; /* a (Value *) or a (TypeName *) */
+} DefElem;
+
+
+/****************************************************************************
+ * Nodes for a Query tree
+ ****************************************************************************/
+
+/*
+ * TargetEntry -
+ * a target entry (used in the transformed target list)
+ *
+ * one of resdom or fjoin is not NULL. a target list is
+ * ((<resdom | fjoin> expr) (<resdom | fjoin> expr) ...)
+ */
+typedef struct TargetEntry {
+ NodeTag type;
+ Resdom *resdom; /* fjoin overload this to be a list??*/
+ Fjoin *fjoin;
+ Node *expr; /* can be a list too */
+} TargetEntry;
+
+/*
+ * RangeTblEntry -
+ * used in range tables. Some of the following are only used in one of
+ * the parsing, optimizing, execution stages.
+ *
+ * inFromCl marks those range variables that are listed in the from clause.
+ * In SQL, the targetlist can only refer to range variables listed in the
+ * from clause but POSTQUEL allows you to refer to tables not specified, in
+ * which case a range table entry will be generated. We use POSTQUEL
+ * semantics which is more powerful. However, we need SQL semantics in
+ * some cases (eg. when expanding a '*')
+ */
+typedef struct RangeTblEntry {
+ NodeTag type;
+ char *relname; /* real name of the relation */
+ TimeRange *timeRange; /* time range */
+ char *refname; /* the reference name (specified in
+ the from clause) */
+ Oid relid;
+ bool inh; /* inheritance? */
+ bool archive; /* filled in by plan_archive */
+ bool inFromCl; /* comes from From Clause */
+ TimeQual timeQual; /* filled in by pg_plan */
+} RangeTblEntry;
+
+/*
+ * SortClause -
+ * used in the sort clause for retrieves and cursors
+ */
+typedef struct SortClause {
+ NodeTag type;
+ Resdom *resdom; /* attributes in tlist to be sorted */
+ Oid opoid; /* sort operators */
+} SortClause;
+
+/*
+ * GroupClause -
+ * used in the GROUP BY clause
+ */
+typedef struct GroupClause {
+ NodeTag type;
+ Var *grpAttr; /* attributes to group on */
+ Oid grpOpoid; /* the sort operator to use */
+} GroupClause;
+
+#endif /* PARSENODES_H */
diff --git a/src/backend/nodes/pg_list.h b/src/backend/nodes/pg_list.h
new file mode 100644
index 0000000000..20554dc8b8
--- /dev/null
+++ b/src/backend/nodes/pg_list.h
@@ -0,0 +1,112 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_list.h--
+ * POSTGRES generic list package
+ *
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id$
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PG_LIST_H
+#define PG_LIST_H
+
+#include <stdio.h>
+#include "c.h"
+#include "nodes/nodes.h"
+
+/* ----------------------------------------------------------------
+ * node definitions
+ * ----------------------------------------------------------------
+ */
+
+/*----------------------
+ * Value node
+ *----------------------
+ */
+typedef struct Value {
+ NodeTag type; /* tag appropriately (eg. T_String) */
+ union ValUnion {
+ char *str; /* string */
+ long ival;
+ double dval;
+ } val;
+} Value;
+
+#define intVal(v) (((Value *)v)->val.ival)
+#define floatVal(v) (((Value *)v)->val.dval)
+#define strVal(v) (((Value *)v)->val.str)
+
+
+/*----------------------
+ * List node
+ *----------------------
+ */
+typedef struct List {
+ NodeTag type;
+ void *elem;
+ struct List *next;
+} List;
+
+#define NIL ((List *) NULL)
+
+/* ----------------
+ * accessor macros
+ * ----------------
+ */
+#define lfirst(l) ((l)->elem)
+#define lnext(l) ((l)->next)
+#define lsecond(l) (lfirst(lnext(l)))
+
+/*
+ * foreach -
+ * a convenience macro which loops through the list
+ */
+#define foreach(_elt_,_list_) \
+ for(_elt_=_list_; _elt_!=NIL;_elt_=lnext(_elt_))
+
+
+/*
+ * function prototypes in nodes/list.c
+ */
+extern int length(List *list);
+extern List *append(List *list1, List *list2);
+extern List *nconc(List *list1, List *list2);
+extern List *lcons(void *datum, List *list);
+extern bool member(void *foo, List *bar);
+extern Value *makeInteger(long i);
+extern Value *makeFloat(double d);
+extern Value *makeString(char *str);
+extern List *makeList(void *elem, ...);
+extern List *lappend(List *list, void *obj);
+extern List *lremove(void *elem, List *list);
+extern void freeList(List *list);
+
+extern void *nth(int n, List *l);
+extern void set_nth(List *l, int n, void *elem);
+
+/* hack for now */
+#define lconsi(i,l) lcons((void*)i,l)
+#define lfirsti(l) ((int)lfirst(l))
+#define lappendi(l,i) lappend(l,(void*)i)
+extern bool intMember(int, List *);
+extern List *intAppend(List *list1, List *list2);
+
+extern List *nreverse(List *);
+extern List *set_difference(List *, List *);
+extern List *set_differencei(List *, List *);
+extern List *LispRemove(void *, List *);
+extern List *intLispRemove(int, List *);
+extern List *LispUnion(List *foo, List *bar);
+extern List *LispUnioni(List *foo, List *bar);
+extern bool same(List *foo, List *bar);
+
+/* should be in nodes.h but needs List */
+extern bool equali(List *a, List *b);
+
+/* in copyfuncs.c */
+extern List *listCopy(List *);
+
+#endif /* PG_LIST_H */
diff --git a/src/backend/nodes/plannodes.h b/src/backend/nodes/plannodes.h
new file mode 100644
index 0000000000..d78b5256e5
--- /dev/null
+++ b/src/backend/nodes/plannodes.h
@@ -0,0 +1,330 @@
+/*-------------------------------------------------------------------------
+ *
+ * plannodes.h--
+ * definitions for query plan nodes
+ *
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id$
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PLANNODES_H
+#define PLANNODES_H
+
+#include "postgres.h"
+
+#include "nodes/nodes.h"
+#include "nodes/pg_list.h"
+#include "nodes/primnodes.h"
+
+/* ----------------------------------------------------------------
+ * Executor State types are used in the plannode structures
+ * so we have to include their definitions too.
+ *
+ * Node Type node information used by executor
+ *
+ * control nodes
+ *
+ * Existential ExistentialState exstate;
+ * Result ResultState resstate;
+ * Append AppendState unionstate;
+ *
+ * scan nodes
+ *
+ * Scan *** CommonScanState scanstate;
+ * IndexScan IndexScanState indxstate;
+ *
+ * (*** nodes which inherit Scan also inherit scanstate)
+ *
+ * join nodes
+ *
+ * NestLoop NestLoopState nlstate;
+ * MergeJoin MergeJoinState mergestate;
+ * HashJoin HashJoinState hashjoinstate;
+ *
+ * materialize nodes
+ *
+ * Material MaterialState matstate;
+ * Sort SortState sortstate;
+ * Unique UniqueState uniquestate;
+ * Hash HashState hashstate;
+ *
+ * ----------------------------------------------------------------
+ */
+#include "nodes/execnodes.h" /* XXX move executor types elsewhere */
+
+
+/* ----------------------------------------------------------------
+ * node definitions
+ * ----------------------------------------------------------------
+ */
+
+/* ----------------
+ * Plan node
+ * ----------------
+ */
+
+typedef struct Plan {
+ NodeTag type;
+ Cost cost;
+ int plan_size;
+ int plan_width;
+ int plan_tupperpage;
+ EState *state; /* at execution time, state's of individual
+ nodes point to one EState for the
+ whole top-level plan */
+ List *targetlist;
+ List *qual; /* Node* or List* ?? */
+ struct Plan *lefttree;
+ struct Plan *righttree;
+} Plan;
+
+/* ----------------
+ * these are are defined to avoid confusion problems with "left"
+ * and "right" and "inner" and "outer". The convention is that
+ * the "left" plan is the "outer" plan and the "right" plan is
+ * the inner plan, but these make the code more readable.
+ * ----------------
+ */
+#define innerPlan(node) (((Plan *)(node))->righttree)
+#define outerPlan(node) (((Plan *)(node))->lefttree)
+
+
+/*
+ * ===============
+ * Top-level nodes
+ * ===============
+ */
+
+/* all plan nodes "derive" from the Plan structure by having the
+ Plan structure as the first field. This ensures that everything works
+ when nodes are cast to Plan's. (node pointers are frequently cast to Plan*
+ when passed around generically in the executor */
+
+
+/* ----------------
+ * existential node
+ * ----------------
+ */
+typedef Plan Existential;
+
+/* ----------------
+ * result node -
+ * returns tuples from outer plan that satisfy the qualifications
+ * ----------------
+ */
+typedef struct Result {
+ Plan plan;
+ Node *resconstantqual;
+ ResultState *resstate;
+} Result;
+
+/* ----------------
+ * append node
+ * ----------------
+ */
+typedef struct Append {
+ Plan plan;
+ List *unionplans;
+ Index unionrelid;
+ List *unionrtentries;
+ AppendState *unionstate;
+} Append;
+
+/*
+ * ==========
+ * Scan nodes
+ * ==========
+ */
+typedef struct Scan {
+ Plan plan;
+ Index scanrelid; /* relid is index into the range table */
+ CommonScanState *scanstate;
+} Scan;
+
+/* ----------------
+ * sequential scan node
+ * ----------------
+ */
+typedef Scan SeqScan;
+
+/* ----------------
+ * index scan node
+ * ----------------
+ */
+typedef struct IndexScan {
+ Scan scan;
+ List *indxid;
+ List *indxqual;
+ IndexScanState *indxstate;
+} IndexScan;
+
+/*
+ * ==========
+ * Join nodes
+ * ==========
+ */
+
+/* ----------------
+ * Join node
+ * ----------------
+ */
+typedef Plan Join;
+
+/* ----------------
+ * nest loop join node
+ * ----------------
+ */
+typedef struct NestLoop {
+ Join join;
+ NestLoopState *nlstate;
+} NestLoop;
+
+/* ----------------
+ * merge join node
+ * ----------------
+ */
+typedef struct MergeJoin {
+ Join join;
+ List *mergeclauses;
+ Oid mergesortop;
+ Oid *mergerightorder; /* inner sort operator */
+ Oid *mergeleftorder; /* outer sort operator */
+ MergeJoinState *mergestate;
+} MergeJoin;
+
+/* ----------------
+ * hash join (probe) node
+ * ----------------
+ */
+typedef struct HashJoin {
+ Join join;
+ List *hashclauses;
+ Oid hashjoinop;
+ HashJoinState *hashjoinstate;
+ HashJoinTable hashjointable;
+ IpcMemoryKey hashjointablekey;
+ int hashjointablesize;
+ bool hashdone;
+} HashJoin;
+
+/* ---------------
+ * aggregate node
+ * ---------------
+ */
+typedef struct Agg {
+ Plan plan;
+ int numAgg;
+ Aggreg **aggs;
+ AggState *aggstate;
+} Agg;
+
+/* ---------------
+ * group node -
+ * use for queries with GROUP BY specified.
+ *
+ * If tuplePerGroup is true, one tuple (with group columns only) is
+ * returned for each group and NULL is returned when there are no more
+ * groups. Otherwise, all the tuples of a group are returned with a
+ * NULL returned at the end of each group. (see nodeGroup.c for details)
+ * ---------------
+ */
+typedef struct Group {
+ Plan plan;
+ bool tuplePerGroup; /* what tuples to return (see above) */
+ int numCols; /* number of group columns */
+ AttrNumber *grpColIdx; /* index into the target list */
+ GroupState *grpstate;
+} Group;
+
+/*
+ * ==========
+ * Temp nodes
+ * ==========
+ */
+typedef struct Temp {
+ Plan plan;
+ Oid tempid;
+ int keycount;
+} Temp;
+
+/* ----------------
+ * materialization node
+ * ----------------
+ */
+typedef struct Material {
+ Plan plan; /* temp node flattened out */
+ Oid tempid;
+ int keycount;
+ MaterialState *matstate;
+} Material;
+
+/* ----------------
+ * sort node
+ * ----------------
+ */
+typedef struct Sort {
+ Plan plan; /* temp node flattened out */
+ Oid tempid;
+ int keycount;
+ SortState *sortstate;
+} Sort;
+
+/* ----------------
+ * unique node
+ * ----------------
+ */
+typedef struct Unique {
+ Plan plan; /* temp node flattened out */
+ Oid tempid;
+ int keycount;
+ char *uniqueAttr; /* NULL if all attrs,
+ or unique attribute name */
+ AttrNumber uniqueAttrNum; /* attribute number of attribute
+ to select distinct on */
+ UniqueState *uniquestate;
+} Unique;
+
+/* ----------------
+ * hash build node
+ * ----------------
+ */
+typedef struct Hash {
+ Plan plan;
+ Var *hashkey;
+ HashState *hashstate;
+ HashJoinTable hashtable;
+ IpcMemoryKey hashtablekey;
+ int hashtablesize;
+} Hash;
+
+/* ---------------------
+ * choose node
+ * ---------------------
+ */
+typedef struct Choose {
+ Plan plan;
+ List *chooseplanlist;
+} Choose;
+
+/* -------------------
+ * Tee node information
+ *
+ * leftParent : the left parent of this node
+ * rightParent: the right parent of this node
+ * -------------------
+*/
+typedef struct Tee {
+ Plan plan;
+ Plan* leftParent;
+ Plan* rightParent;
+ TeeState *teestate;
+ char *teeTableName; /* the name of the table to materialize
+ the tee into */
+ List *rtentries; /* the range table for the plan below the Tee
+ may be different than the parent plans */
+} Tee;
+
+#endif /* PLANNODES_H */
diff --git a/src/backend/nodes/primnodes.h b/src/backend/nodes/primnodes.h
new file mode 100644
index 0000000000..6596253d57
--- /dev/null
+++ b/src/backend/nodes/primnodes.h
@@ -0,0 +1,318 @@
+/*-------------------------------------------------------------------------
+ *
+ * primnodes.h--
+ * Definitions for parse tree/query tree ("primitive") nodes.
+ *
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id$
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PRIMNODES_H
+#define PRIMNODES_H
+
+#include "postgres.h"
+
+#include "access/attnum.h"
+#include "storage/buf.h"
+#include "utils/rel.h"
+#include "utils/fcache.h"
+#include "nodes/params.h"
+
+#include "nodes/nodes.h"
+#include "nodes/pg_list.h"
+
+/* ----------------------------------------------------------------
+ * node definitions
+ * ----------------------------------------------------------------
+ */
+
+/* ----------------
+ * Resdom (Result Domain)
+ * resno - attribute number
+ * restype - type of the resdom
+ * reslen - length (in bytes) of the result
+ * resname - name of the resdom (could be NULL)
+ * reskey - order of key in a sort (for those > 0)
+ * reskeyop - sort operator Oid
+ * resjunk - set to nonzero to eliminate the attribute
+ * from final target list e.g., ctid for replace
+ * and delete
+ *
+ * ----------------
+ */
+typedef struct Resdom {
+ NodeTag type;
+ AttrNumber resno;
+ Oid restype;
+ int reslen;
+ char *resname;
+ Index reskey;
+ Oid reskeyop;
+ int resjunk;
+} Resdom;
+
+/* -------------
+ * Fjoin
+ * initialized - true if the Fjoin has already been initialized for
+ * the current target list evaluation
+ * nNodes - The number of Iter nodes returning sets that the
+ * node will flatten
+ * outerList - 1 or more Iter nodes
+ * inner - exactly one Iter node. We eval every node in the
+ * outerList once then eval the inner node to completion
+ * pair the outerList result vector with each inner
+ * result to form the full result. When the inner has
+ * been exhausted, we get the next outer result vector
+ * and reset the inner.
+ * results - The complete (flattened) result vector
+ * alwaysNull - a null vector to indicate sets with a cardinality of
+ * 0, we treat them as the set {NULL}.
+ */
+typedef struct Fjoin {
+ NodeTag type;
+ bool fj_initialized;
+ int fj_nNodes;
+ List *fj_innerNode;
+ DatumPtr fj_results;
+ BoolPtr fj_alwaysDone;
+} Fjoin;
+
+/* ----------------
+ * Expr
+ * typeOid - oid of the type of this expression
+ * opType - type of this expression
+ * oper - the Oper node if it is an OPER_EXPR or the
+ * Func node if it is a FUNC_EXPR
+ * args - arguments to this expression
+ * ----------------
+ */
+typedef enum OpType {
+ OP_EXPR, FUNC_EXPR, OR_EXPR, AND_EXPR, NOT_EXPR
+} OpType;
+
+typedef struct Expr {
+ NodeTag type;
+ Oid typeOid; /* oid of the type of this expr */
+ OpType opType; /* type of the op */
+ Node *oper; /* could be Oper or Func */
+ List *args; /* list of argument nodes */
+} Expr;
+
+/* ----------------
+ * Var
+ * varno - index of this var's relation in the range table
+ * (could be INNER or OUTER)
+ * varattno - attribute number of this var
+ * vartype - pg_type tuple oid for the type of this var
+ * varnoold - keep varno around in case it got changed to INNER/
+ * OUTER (see match_varid)
+ * varoattno - attribute number of this var
+ * [ '(varnoold varoattno) was varid -ay 2/95]
+ * ----------------
+ */
+#define INNER 65000
+#define OUTER 65001
+
+#define PRS2_CURRENT_VARNO 1
+#define PRS2_NEW_VARNO 2
+
+typedef struct Var {
+ NodeTag type;
+ Index varno;
+ AttrNumber varattno;
+ Oid vartype;
+ Index varnoold; /* only used by optimizer */
+ AttrNumber varoattno; /* only used by optimizer */
+} Var;
+
+/* ----------------
+ * Oper
+ * opno - PG_OPERATOR OID of the operator
+ * opid - PG_PROC OID for the operator
+ * opresulttype - PG_TYPE OID of the operator's return value
+ * opsize - size of return result (cached by executor)
+ * op_fcache - XXX comment me.
+ *
+ * ----
+ * NOTE: in the good old days 'opno' used to be both (or either, or
+ * neither) the pg_operator oid, and/or the pg_proc oid depending
+ * on the postgres module in question (parser->pg_operator,
+ * executor->pg_proc, planner->both), the mood of the programmer,
+ * and the phase of the moon (rumors that it was also depending on the day
+ * of the week are probably false). To make things even more postgres-like
+ * (i.e. a mess) some comments were referring to 'opno' using the name
+ * 'opid'. Anyway, now we have two separate fields, and of course that
+ * immediately removes all bugs from the code... [ sp :-) ].
+ * ----------------
+ */
+typedef struct Oper {
+ NodeTag type;
+ Oid opno;
+ Oid opid;
+ Oid opresulttype;
+ int opsize;
+ FunctionCachePtr op_fcache;
+} Oper;
+
+
+/* ----------------
+ * Const
+ * consttype - PG_TYPE OID of the constant's value
+ * constlen - length in bytes of the constant's value
+ * constvalue - the constant's value
+ * constisnull - whether the constant is null
+ * (if true, the other fields are undefined)
+ * constbyval - whether the information in constvalue
+ * if passed by value. If true, then all the information
+ * is stored in the datum. If false, then the datum
+ * contains a pointer to the information.
+ * constisset - whether the const represents a set. The const
+ * value corresponding will be the query that defines
+ * the set.
+ * ----------------
+ */
+typedef struct Const {
+ NodeTag type;
+ Oid consttype;
+ Size constlen;
+ Datum constvalue;
+ bool constisnull;
+ bool constbyval;
+ bool constisset;
+} Const;
+
+/* ----------------
+ * Param
+ * paramkind - specifies the kind of parameter. The possible values
+ * for this field are specified in "params.h", and they are:
+ *
+ * PARAM_NAMED: The parameter has a name, i.e. something
+ * like `$.salary' or `$.foobar'.
+ * In this case field `paramname' must be a valid Name.
+ *
+ * PARAM_NUM: The parameter has only a numeric identifier,
+ * i.e. something like `$1', `$2' etc.
+ * The number is contained in the `paramid' field.
+ *
+ * PARAM_NEW: Used in PRS2 rule, similar to PARAM_NAMED.
+ * The `paramname' and `paramid' refer to the "NEW" tuple
+ * The `pramname' is the attribute name and `paramid'
+ * is the attribute number.
+ *
+ * PARAM_OLD: Same as PARAM_NEW, but in this case we refer to
+ * the "OLD" tuple.
+ *
+ * paramid - numeric identifier for literal-constant parameters ("$1")
+ * paramname - attribute name for tuple-substitution parameters ("$.foo")
+ * paramtype - PG_TYPE OID of the parameter's value
+ * param_tlist - allows for projection in a param node.
+ * ----------------
+ */
+typedef struct Param {
+ NodeTag type;
+ int paramkind;
+ AttrNumber paramid;
+ char *paramname;
+ Oid paramtype;
+ List *param_tlist;
+} Param;
+
+
+/* ----------------
+ * Func
+ * funcid - PG_FUNCTION OID of the function
+ * functype - PG_TYPE OID of the function's return value
+ * funcisindex - the function can be evaluated by scanning an index
+ * (set during query optimization)
+ * funcsize - size of return result (cached by executor)
+ * func_fcache - runtime state while running this function. Where
+ * we are in the execution of the function if it
+ * returns more than one value, etc.
+ * See utils/fcache.h
+ * func_tlist - projection of functions returning tuples
+ * func_planlist - result of planning this func, if it's a PQ func
+ * ----------------
+ */
+typedef struct Func {
+ NodeTag type;
+ Oid funcid;
+ Oid functype;
+ bool funcisindex;
+ int funcsize;
+ FunctionCachePtr func_fcache;
+ List *func_tlist;
+ List *func_planlist;
+} Func;
+
+/* ----------------
+ * Aggreg
+ * aggname - name of the aggregate
+ * basetype - base type Oid of the aggregate
+ * aggtype - type Oid of final result of the aggregate
+ * query - XXX comment me
+ * target - XXX comment me
+ * ----------------
+ */
+typedef struct Aggreg {
+ NodeTag type;
+ char *aggname;
+ Oid basetype; /* base type of the aggregate */
+ Oid aggtype; /* type of final result */
+ Node *target; /* attribute to aggreg on */
+ int aggno; /* index to ecxt_values */
+} Aggreg;
+
+/* ----------------
+ * Array
+ * arrayelemtype - base type of the array's elements (homogenous!)
+ * arrayelemlength - length of that type
+ * arrayelembyval - can you pass this element by value?
+ * arrayndim - number of dimensions of the array
+ * arraylow - base for array indexing
+ * arrayhigh - limit for array indexing
+ * arraylen -
+ * ----------------
+ *
+ * memo from mao: the array support we inherited from 3.1 is just
+ * wrong. when time exists, we should redesign this stuff to get
+ * around a bunch of unfortunate implementation decisions made there.
+ */
+typedef struct Array {
+ NodeTag type;
+ Oid arrayelemtype;
+ int arrayelemlength;
+ bool arrayelembyval;
+ int arrayndim;
+ IntArray arraylow;
+ IntArray arrayhigh;
+ int arraylen;
+} Array;
+
+/* ----------------
+ * ArrayRef:
+ * refelemtype - type of the element referenced here
+ * refelemlength - length of that type
+ * refelembyval - can you pass this element type by value?
+ * refupperindexpr - expressions that evaluate to upper array index
+ * reflowerexpr- the expressions that evaluate to a lower array index
+ * refexpr - the expression that evaluates to an array
+ * refassignexpr- the expression that evaluates to the new value
+ * to be assigned to the array in case of replace.
+ * ----------------
+ */
+typedef struct ArrayRef {
+ NodeTag type;
+ int refattrlength;
+ int refelemlength;
+ Oid refelemtype;
+ bool refelembyval;
+ List *refupperindexpr;
+ List *reflowerindexpr;
+ Node *refexpr;
+ Node *refassgnexpr;
+} ArrayRef;
+
+#endif /* PRIMNODES_H */
diff --git a/src/backend/nodes/print.c b/src/backend/nodes/print.c
new file mode 100644
index 0000000000..a7c4cb9524
--- /dev/null
+++ b/src/backend/nodes/print.c
@@ -0,0 +1,377 @@
+/*-------------------------------------------------------------------------
+ *
+ * print.c--
+ * various print routines (used mostly for debugging)
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header$
+ *
+ * HISTORY
+ * AUTHOR DATE MAJOR EVENT
+ * Andrew Yu Oct 26, 1994 file creation
+ *
+ *-------------------------------------------------------------------------
+ */
+#include <stdio.h>
+#include "postgres.h"
+#include "access/printtup.h"
+#include "nodes/pg_list.h"
+#include "nodes/execnodes.h"
+#include "nodes/parsenodes.h"
+
+#include "parser/parsetree.h"
+#include "parser/catalog_utils.h"
+#include "access/heapam.h"
+#include "utils/lsyscache.h"
+#include "nodes/nodes.h"
+#include "nodes/plannodes.h"
+#include "optimizer/clauses.h"
+/*
+ * print--
+ * print contents of Node to stdout
+ */
+void
+print(void *obj)
+{
+ char *s;
+
+ s = nodeToString(obj);
+ printf("%s\n", s);
+ fflush(stdout);
+ return;
+}
+
+/*
+ * pretty print hack extraordinaire. -ay 10/94
+ */
+void
+pprint(void *obj)
+{
+ char *s;
+ int i;
+ char line[80];
+ int indentLev;
+ int j;
+
+ s = nodeToString(obj);
+
+ indentLev = 0;
+ i = 0;
+ for(;;) {
+ for(j=0; j<indentLev*3; j++) {
+ line[j] = ' ';
+ }
+ for( ; j<75 && s[i]!='\0'; i++, j++) {
+ line[j] = s[i];
+ switch (line[j]) {
+ case '}':
+ if (j != indentLev*3) {
+ line[j] = '\0';
+ printf("%s\n",line);
+ line[indentLev*3] = '\0';
+ printf("%s}\n",line);
+ }else {
+ line[j] = '\0';
+ printf("%s}\n",line);
+ }
+ indentLev--;
+ j = indentLev*3-1; /* print the line before : and resets */
+ break;
+ case ')':
+ line[j+1] = '\0';
+ printf("%s\n", line);
+ j = indentLev*3-1;
+ break;
+ case '{':
+ indentLev++;
+ /* !!! FALLS THROUGH */
+ case ':':
+ if (j != 0) {
+ line[j] = '\0';
+ printf("%s\n",line);
+ /* print the line before : and resets */
+ for(j=0; j<indentLev*3; j++) {
+ line[j] = ' ';
+ }
+ }
+ line[j] = s[i];
+ break;
+ }
+ }
+ line[j] = '\0';
+ if (s[i]=='\0')
+ break;
+ printf("%s\n", line);
+ }
+ if (j!=0) {
+ printf("%s\n", line);
+ }
+ fflush(stdout);
+ return;
+}
+
+/*
+ * print_rt--
+ * print contents of range table
+ */
+void
+print_rt(List *rtable)
+{
+ List *l;
+ int i=1;
+
+ printf("resno\trelname(refname)\trelid\tinFromCl\n");
+ printf("-----\t----------------\t-----\t--------\n");
+ foreach(l, rtable) {
+ RangeTblEntry *rte = lfirst(l);
+ printf("%d\t%s(%s)\t%d\t%d\t%s\n",
+ i,rte->relname,rte->refname,rte->relid,
+ rte->inFromCl,
+ (rte->inh?"inh":""));
+ i++;
+ }
+}
+
+
+/*
+ * print_expr--
+ * print an expression
+ */
+void
+print_expr(Node *expr, List *rtable)
+{
+ if (expr==NULL) {
+ printf("nil");
+ return;
+ }
+
+ if (IsA(expr,Var)) {
+ Var *var = (Var*)expr;
+ RangeTblEntry *rt;
+ char *relname, *attname;
+
+ switch (var->varno) {
+ case INNER:
+ relname = "INNER";
+ attname = "?";
+ break;
+ case OUTER:
+ relname = "OUTER";
+ attname = "?";
+ break;
+ default:
+ {
+ Relation r;
+ rt = rt_fetch(var->varno, rtable);
+ relname = rt->relname;
+ r = heap_openr(relname);
+ if (rt->refname)
+ relname = rt->refname; /* table renamed */
+ attname = getAttrName(r, var->varattno);
+ heap_close(r);
+ }
+ break;
+ }
+ printf("%s.%s",relname,attname);
+ } else if (IsA(expr,Expr)) {
+ Expr *e = (Expr*)expr;
+ if (is_opclause(expr)) {
+ char *opname;
+
+ print_expr((Node*)get_leftop(e), rtable);
+ opname = get_opname(((Oper*)e->oper)->opno);
+ printf(" %s ", opname);
+ print_expr((Node*)get_rightop(e), rtable);
+ } else {
+ printf("an expr");
+ }
+ } else {
+ printf("not an expr");
+ }
+}
+
+/*
+ * print_keys -
+ * temporary here. where is keys list of list??
+ */
+void
+print_keys(List *keys, List *rtable)
+{
+ List *k;
+
+ printf("(");
+ foreach(k, keys) {
+ Node *var = lfirst((List*)lfirst(k));
+ print_expr(var, rtable);
+ if (lnext(k)) printf(", ");
+ }
+ printf(")\n");
+}
+
+/*
+ * print_tl --
+ * print targetlist in a more legible way.
+ */
+void
+print_tl(List *tlist, List *rtable)
+{
+ List *tl;
+
+ printf("(\n");
+ foreach(tl, tlist) {
+ TargetEntry *tle = lfirst(tl);
+
+ printf("\t%d %s\t", tle->resdom->resno, tle->resdom->resname);
+ if (tle->resdom->reskey!=0) {
+ printf("(%d):\t", tle->resdom->reskey);
+ } else {
+ printf(" :\t");
+ }
+ print_expr(tle->expr, rtable);
+ printf("\n");
+ }
+ printf(")\n");
+}
+
+/*
+ * print_slot--
+ * print out the tuple with the given TupleTableSlot
+ */
+void
+print_slot(TupleTableSlot *slot)
+{
+ if (!slot->val) {
+ printf("tuple is null.\n");
+ return;
+ }
+ if (!slot->ttc_tupleDescriptor) {
+ printf("no tuple descriptor.\n");
+ return;
+ }
+
+ debugtup(slot->val, slot->ttc_tupleDescriptor);
+}
+
+char*
+plannode_type (Plan* p)
+{
+ switch(nodeTag(p)) {
+ case T_Plan:
+ return "PLAN";
+ break;
+ case T_Existential:
+ return "EXISTENTIAL";
+ break;
+ case T_Result:
+ return "RESULT";
+ break;
+ case T_Append:
+ return "APPEND";
+ break;
+ case T_Scan:
+ return "SCAN";
+ break;
+ case T_SeqScan:
+ return "SEQSCAN";
+ break;
+ case T_IndexScan:
+ return "INDEXSCAN";
+ break;
+ case T_Join:
+ return "JOIN";
+ break;
+ case T_NestLoop:
+ return "NESTLOOP";
+ break;
+ case T_MergeJoin:
+ return "MERGEJOIN";
+ break;
+ case T_HashJoin:
+ return "HASHJOIN";
+ break;
+ case T_Temp:
+ return "TEMP";
+ break;
+ case T_Material:
+ return "MATERIAL";
+ break;
+ case T_Sort:
+ return "SORT";
+ break;
+ case T_Agg:
+ return "AGG";
+ break;
+ case T_Unique:
+ return "UNIQUE";
+ break;
+ case T_Hash:
+ return "HASH";
+ break;
+ case T_Tee:
+ return "TEE";
+ break;
+ case T_Choose:
+ return "CHOOSE";
+ break;
+ case T_Group:
+ return "GROUP";
+ break;
+ default:
+ return "UNKNOWN";
+ break;
+ }
+}
+/*
+ prints the ascii description of the plan nodes
+ does this recursively by doing a depth-first traversal of the
+ plan tree. for SeqScan and IndexScan, the name of the table is also
+ printed out
+
+*/
+void
+print_plan_recursive (Plan* p, Query *parsetree, int indentLevel, char* label)
+{
+ int i;
+ char extraInfo[100];
+
+ if (!p)
+ return;
+ for (i=0;i<indentLevel;i++)
+ printf(" ");
+ printf("%s%s :c=%.4f :s=%d :w=%d ",label, plannode_type(p),
+ p->cost, p->plan_size, p->plan_width);
+ if (IsA(p,Scan) || IsA(p,SeqScan)) {
+ RangeTblEntry *rte;
+ rte = rt_fetch(((Scan*)p)->scanrelid, parsetree->rtable);
+ strncpy(extraInfo, rte->relname, NAMEDATALEN);
+ extraInfo[NAMEDATALEN] = '\0';
+ } else
+ if (IsA(p,IndexScan)) {
+ strncpy(extraInfo,
+ ((RangeTblEntry*)(nth(((IndexScan*)p)->scan.scanrelid - 1,
+ parsetree->rtable)))->relname,
+ NAMEDATALEN);
+ extraInfo[NAMEDATALEN] = '\0';
+ } else
+ extraInfo[0] = '\0';
+ if (extraInfo[0] != '\0')
+ printf(" ( %s )\n", extraInfo);
+ else
+ printf("\n");
+ print_plan_recursive(p->lefttree, parsetree, indentLevel + 3, "l: ");
+ print_plan_recursive(p->righttree, parsetree, indentLevel + 3, "r: ");
+}
+
+/* print_plan
+ prints just the plan node types */
+
+void
+print_plan (Plan* p, Query* parsetree)
+{
+ print_plan_recursive(p, parsetree, 0, "");
+}
+
+
diff --git a/src/backend/nodes/read.c b/src/backend/nodes/read.c
new file mode 100644
index 0000000000..54fb45e164
--- /dev/null
+++ b/src/backend/nodes/read.c
@@ -0,0 +1,270 @@
+/*-------------------------------------------------------------------------
+ *
+ * read.c--
+ * routines to convert a string (legal ascii representation of node) back
+ * to nodes
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header$
+ *
+ * HISTORY
+ * AUTHOR DATE MAJOR EVENT
+ * Andrew Yu Nov 2, 1994 file creation
+ *
+ *-------------------------------------------------------------------------
+ */
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "postgres.h"
+#include "nodes/pg_list.h"
+#include "nodes/readfuncs.h"
+#include "utils/elog.h"
+
+/*
+ * stringToNode -
+ * returns a Node with a given legal ascii representation
+ */
+void *
+stringToNode(char *str)
+{
+ void *retval;
+
+ (void) lsptok(str, NULL); /* set the string used in lsptok */
+ retval = nodeRead(true); /* start reading */
+
+ return retval;
+}
+
+/*****************************************************************************
+ *
+ * the lisp token parser
+ *
+ *****************************************************************************/
+
+#define RIGHT_PAREN (1000000 + 1)
+#define LEFT_PAREN (1000000 + 2)
+#define PLAN_SYM (1000000 + 3)
+#define AT_SYMBOL (1000000 + 4)
+#define ATOM_TOKEN (1000000 + 5)
+
+/*
+ * nodeTokenType -
+ * returns the type of the node token contained in token.
+ * It returns one of the following valid NodeTags:
+ * T_Integer, T_Float, T_String
+ * and some of its own:
+ * RIGHT_PAREN, LEFT_PAREN, PLAN_SYM, AT_SYMBOL, ATOM_TOKEN
+ *
+ * Assumption: the ascii representation is legal
+ */
+static NodeTag
+nodeTokenType(char *token, int length)
+{
+ NodeTag retval;
+
+ /*
+ * Check if the token is a number (decimal or integer,
+ * positive or negative
+ */
+ if (isdigit(*token) ||
+ (length>=2 && *token=='-' && isdigit(*(token+1)) ))
+ {
+ /*
+ * skip the optional '-' (i.e. negative number)
+ */
+ if (*token == '-') {
+ token++;
+ }
+
+ /*
+ * See if there is a decimal point
+ */
+
+ for (; length && *token != '.'; token++, length--);
+
+ /*
+ * if there isn't, token's an int, otherwise it's a float.
+ */
+
+ retval = (*token != '.') ? T_Integer : T_Float;
+ }
+ else if (isalpha(*token))
+ retval = ATOM_TOKEN;
+ else if (*token == '(')
+ retval = LEFT_PAREN;
+ else if (*token == ')')
+ retval = RIGHT_PAREN;
+ else if (*token == '@')
+ retval = AT_SYMBOL;
+ else if (*token == '\"')
+ retval = T_String;
+ else if (*token == '{')
+ retval = PLAN_SYM;
+ return(retval);
+}
+
+/*
+ * Works kinda like strtok, except it doesn't put nulls into string.
+ *
+ * Returns the length in length instead. The string can be set without
+ * returning a token by calling lsptok with length == NULL.
+ *
+ */
+char *
+lsptok(char *string, int *length)
+{
+ static char *local_str;
+ char *ret_string;
+
+ if (string != NULL) {
+ local_str = string;
+ if (length == NULL) {
+ return(NULL);
+ }
+ }
+
+ for (; *local_str == ' '
+ || *local_str == '\n'
+ || *local_str == '\t'; local_str++);
+
+ /*
+ * Now pointing at next token.
+ */
+ ret_string = local_str;
+ if (*local_str == '\0') return(NULL);
+ *length = 1;
+
+ if (*local_str == '\"') {
+ for (local_str++; *local_str != '\"'; (*length)++, local_str++);
+ (*length)++; local_str++;
+ }else if (*local_str == ')' || *local_str == '(' ||
+ *local_str == '}' || *local_str == '{') {
+ local_str++;
+ }else {
+ for (; *local_str != ' '
+ && *local_str != '\n'
+ && *local_str != '\t'
+ && *local_str != '{'
+ && *local_str != '}'
+ && *local_str != '('
+ && *local_str != ')'; local_str++, (*length)++);
+ (*length)--;
+ }
+ return(ret_string);
+}
+
+/*
+ * This guy does all the reading.
+ *
+ * Secrets: He assumes that lsptok already has the string (see below).
+ * Any callers should set read_car_only to true.
+ */
+void *
+nodeRead(bool read_car_only)
+{
+ char *token;
+ NodeTag type;
+ Node *this_value, *return_value;
+ int tok_len;
+ char tmp;
+ bool make_dotted_pair_cell = false;
+
+ token = lsptok(NULL, &tok_len);
+
+ if (token == NULL) return(NULL);
+
+ type = nodeTokenType(token, tok_len);
+
+ switch(type) {
+ case PLAN_SYM:
+ this_value = parsePlanString();
+ token = lsptok(NULL, &tok_len);
+ if (token[0] != '}') return(NULL);
+
+ if (!read_car_only)
+ make_dotted_pair_cell = true;
+ else
+ make_dotted_pair_cell = false;
+ break;
+ case LEFT_PAREN:
+ if (!read_car_only) {
+ List *l = makeNode(List);
+
+ lfirst(l) = nodeRead(false);
+ lnext(l) = nodeRead(false);
+ this_value = (Node*)l;
+ }else {
+ this_value = nodeRead(false);
+ }
+ break;
+ case RIGHT_PAREN:
+ this_value = NULL;
+ break;
+ case AT_SYMBOL:
+ break;
+ case ATOM_TOKEN:
+ if (!strncmp(token, "nil", 3)) {
+ this_value = NULL;
+ /*
+ * It might be "nil" but it is an atom!
+ */
+ if (read_car_only) {
+ make_dotted_pair_cell = false;
+ } else {
+ make_dotted_pair_cell = true;
+ }
+ }else {
+ tmp = token[tok_len];
+ token[tok_len] = '\0';
+ this_value = (Node*)pstrdup(token); /* !attention! not a Node.
+ use with caution */
+ token[tok_len] = tmp;
+ make_dotted_pair_cell = true;
+ }
+ break;
+ case T_Float:
+ tmp = token[tok_len];
+ token[tok_len] = '\0';
+ this_value = (Node*)makeFloat(atof(token));
+ token[tok_len] = tmp;
+ make_dotted_pair_cell = true;
+ break;
+ case T_Integer:
+ tmp = token[tok_len];
+ token[tok_len] = '\0';
+ this_value = (Node*)makeInteger(atoi(token));
+ token[tok_len] = tmp;
+ make_dotted_pair_cell = true;
+ break;
+ case T_String:
+ tmp = token[tok_len - 1];
+ token[tok_len - 1] = '\0';
+ token++;
+ this_value = (Node*)makeString(token); /* !! not strdup'd */
+ token[tok_len - 2] = tmp;
+ make_dotted_pair_cell = true;
+ break;
+ default:
+ elog(WARN, "nodeRead: Bad type %d", type);
+ break;
+ }
+ if (make_dotted_pair_cell) {
+ List *l = makeNode(List);
+
+ lfirst(l) = this_value;
+ if (!read_car_only) {
+ lnext(l) = nodeRead(false);
+ }else {
+ lnext(l) = NULL;
+ }
+ return_value = (Node*)l;
+ }else {
+ return_value = this_value;
+ }
+ return(return_value);
+}
+
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
new file mode 100644
index 0000000000..75832d9460
--- /dev/null
+++ b/src/backend/nodes/readfuncs.c
@@ -0,0 +1,1948 @@
+/*-------------------------------------------------------------------------
+ *
+ * readfuncs.c--
+ * Reader functions for Postgres tree nodes.
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header$
+ *
+ * NOTES
+ * Most of the read functions for plan nodes are tested. (In fact, they
+ * pass the regression test as of 11/8/94.) The rest (for path selection)
+ * are probably never used. No effort has been made to get them to work.
+ * The simplest way to test these functions is by doing the following in
+ * ProcessQuery (before executing the plan):
+ * plan = stringToNode(nodeToString(plan));
+ * Then, run the regression test. Let's just say you'll notice if either
+ * of the above function are not properly done.
+ * - ay 11/94
+ *
+ *-------------------------------------------------------------------------
+ */
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+
+#include "postgres.h"
+
+#include "access/heapam.h"
+#include "access/htup.h"
+#include "fmgr.h"
+#include "utils/builtins.h"
+#include "utils/elog.h"
+#include "utils/palloc.h"
+
+#include "utils/lsyscache.h"
+#include "utils/syscache.h"
+#include "catalog/pg_type.h"
+
+#include "nodes/primnodes.h"
+#include "nodes/plannodes.h"
+#include "nodes/parsenodes.h"
+#include "nodes/execnodes.h"
+#include "nodes/relation.h"
+#include "nodes/readfuncs.h"
+
+/* ----------------
+ * node creator declarations
+ * ----------------
+ */
+
+static Datum readDatum(Oid type);
+
+static List *toIntList(List *list)
+{
+ List *l;
+ foreach(l, list) {
+ /* ugly manipulation, should probably free the Value node too */
+ lfirst(l) = (void*)intVal(lfirst(l));
+ }
+ return list;
+}
+
+/* ----------------
+ * _readQuery
+ * ----------------
+ */
+static Query *
+_readQuery()
+{
+ Query *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Query);
+
+ token = lsptok(NULL, &length); /* skip the :command */
+ token = lsptok(NULL, &length); /* get the commandType */
+ local_node->commandType = atoi(token);
+
+ token = lsptok(NULL, &length); /* skip the :utility */
+ token = lsptok(NULL, &length); /* get the notify name if any*/
+ if (token[0] == '"' && token[1] == '"')
+ local_node->utilityStmt = NULL;
+ else {
+ NotifyStmt *n = makeNode(NotifyStmt);
+ n->relname = palloc(length + 1);
+ strncpy(n->relname,token,length);
+ n->relname[length] = '\0';
+ local_node->utilityStmt = (Node*)n;
+ }
+
+ token = lsptok(NULL, &length); /* skip the :resrel */
+ token = lsptok(NULL, &length); /* get the resultRelation */
+ local_node->resultRelation = atoi(token);
+
+ token = lsptok(NULL, &length); /* skip :rtable */
+ local_node->rtable = nodeRead(true);
+
+ token = lsptok(NULL, &length); /* skip the :unique */
+ token = lsptok(NULL, &length); /* get the uniqueFlag */
+/* local_node->uniqueFlag = (bool)atoi(token); */
+ if (token[0]=='"' && token[1] == '"') /* non-unique */
+ local_node->uniqueFlag = NULL;
+ else {
+ local_node->uniqueFlag = palloc(length + 1);
+ strncpy(local_node->uniqueFlag,token,length);
+ local_node->uniqueFlag[length] = '\0';
+ }
+
+ token = lsptok(NULL, &length); /* skip :targetlist */
+ local_node->targetList = nodeRead(true);
+
+ token = lsptok(NULL, &length); /* skip :qual */
+ local_node->qual = nodeRead(true);
+
+ return (local_node);
+}
+
+/* ----------------
+ * _getPlan
+ * ----------------
+ */
+static void
+_getPlan(Plan *node)
+{
+ char *token;
+ int length;
+
+ token = lsptok(NULL, &length); /* first token is :cost */
+ token = lsptok(NULL, &length); /* next is the actual cost */
+ node->cost = (Cost) atof(token);
+
+ token = lsptok(NULL, &length); /* skip the :size */
+ token = lsptok(NULL, &length); /* get the plan_size */
+ node->plan_size = atoi(token);
+
+ token = lsptok(NULL, &length); /* skip the :width */
+ token = lsptok(NULL, &length); /* get the plan_width */
+ node->plan_width = atoi(token);
+
+ token = lsptok(NULL, &length); /* eat the :state stuff */
+ token = lsptok(NULL, &length); /* now get the state */
+
+ if (!strncmp(token, "nil", 3)) {
+ node->state = (EState*) NULL;
+ }else { /* Disgusting hack until I figure out what to do here */
+ node->state = (EState*) ! NULL;
+ }
+
+ token = lsptok(NULL, &length); /* eat :qptargetlist */
+ node->targetlist = nodeRead(true);
+
+ token = lsptok(NULL, &length); /* eat :qpqual */
+ node->qual = nodeRead(true);
+
+ token = lsptok(NULL, &length); /* eat :lefttree */
+ node->lefttree = (Plan*) nodeRead(true);
+
+ token = lsptok(NULL, &length); /* eat :righttree */
+ node->righttree = (Plan*) nodeRead(true);
+
+ return;
+}
+
+/*
+ * Stuff from plannodes.h
+ */
+
+/* ----------------
+ * _readPlan
+ * ----------------
+ */
+static Plan *
+_readPlan()
+{
+ Plan *local_node;
+
+ local_node = makeNode(Plan);
+
+ _getPlan(local_node);
+
+ return (local_node);
+}
+
+/* ----------------
+ * _readResult
+ *
+ * Does some obscene, possibly unportable, magic with
+ * sizes of things.
+ * ----------------
+ */
+static Result *
+_readResult()
+{
+ Result *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Result);
+
+ _getPlan((Plan*)local_node);
+
+ token = lsptok(NULL, &length); /* eat :resconstantqual */
+ local_node->resconstantqual = nodeRead(true); /* now read it */
+
+ return( local_node );
+}
+
+/* ----------------
+ * _readExistential
+ *
+ * Existential nodes are only used by the planner.
+ * ----------------
+ */
+static Existential *
+_readExistential()
+{
+ Existential *local_node;
+
+ local_node = makeNode(Existential);
+
+ _getPlan((Plan*)local_node);
+
+ return( local_node );
+}
+
+/* ----------------
+ * _readAppend
+ *
+ * Append is a subclass of Plan.
+ * ----------------
+ */
+
+static Append *
+_readAppend()
+{
+ Append *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Append);
+
+ _getPlan((Plan*)local_node);
+
+ token = lsptok(NULL, &length); /* eat :unionplans */
+ local_node->unionplans = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* eat :unionrelid */
+ token = lsptok(NULL, &length); /* get unionrelid */
+ local_node->unionrelid = atoi(token);
+
+ token = lsptok(NULL, &length); /* eat :unionrtentries */
+ local_node->unionrtentries = nodeRead(true); /* now read it */
+
+ return(local_node);
+}
+
+/* ----------------
+ * _getJoin
+ *
+ * In case Join is not the same structure as Plan someday.
+ * ----------------
+ */
+static void
+_getJoin(Join *node)
+{
+ _getPlan((Plan*)node);
+}
+
+
+/* ----------------
+ * _readJoin
+ *
+ * Join is a subclass of Plan
+ * ----------------
+ */
+static Join *
+_readJoin()
+{
+ Join *local_node;
+
+ local_node = makeNode(Join);
+
+ _getJoin(local_node);
+
+ return( local_node );
+}
+
+/* ----------------
+ * _readNestLoop
+ *
+ * NestLoop is a subclass of Join
+ * ----------------
+ */
+
+static NestLoop *
+_readNestLoop()
+{
+ NestLoop *local_node;
+
+ local_node = makeNode(NestLoop);
+
+ _getJoin((Join*)local_node);
+
+ return( local_node );
+}
+
+/* ----------------
+ * _readMergeJoin
+ *
+ * MergeJoin is a subclass of Join
+ * ----------------
+ */
+static MergeJoin *
+_readMergeJoin()
+{
+ MergeJoin *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(MergeJoin);
+
+ _getJoin((Join*)local_node);
+ token = lsptok(NULL, &length); /* eat :mergeclauses */
+ local_node->mergeclauses = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* eat :mergesortop */
+ token = lsptok(NULL, &length); /* get mergesortop */
+ local_node->mergesortop = atol(token);
+
+ return( local_node );
+}
+
+/* ----------------
+ * _readHashJoin
+ *
+ * HashJoin is a subclass of Join.
+ * ----------------
+ */
+static HashJoin *
+_readHashJoin()
+{
+ HashJoin *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(HashJoin);
+
+ _getJoin((Join*)local_node);
+
+ token = lsptok(NULL, &length); /* eat :hashclauses */
+ local_node->hashclauses = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* eat :hashjoinop */
+ token = lsptok(NULL, &length); /* get hashjoinop */
+ local_node->hashjoinop = atoi(token);
+
+ token = lsptok(NULL, &length); /* eat :hashjointable */
+ token = lsptok(NULL, &length); /* eat hashjointable */
+ local_node->hashjointable = NULL;
+
+ token = lsptok(NULL, &length); /* eat :hashjointablekey */
+ token = lsptok(NULL, &length); /* eat hashjointablekey */
+ local_node->hashjointablekey = 0;
+
+ token = lsptok(NULL, &length); /* eat :hashjointablesize */
+ token = lsptok(NULL, &length); /* eat hashjointablesize */
+ local_node->hashjointablesize = 0;
+
+ token = lsptok(NULL, &length); /* eat :hashdone */
+ token = lsptok(NULL, &length); /* eat hashdone */
+ local_node->hashdone = false;
+
+ return( local_node );
+}
+
+/* ----------------
+ * _getScan
+ *
+ * Scan is a subclass of Node
+ * (Actually, according to the plannodes.h include file, it is a
+ * subclass of Plan. This is why _getPlan is used here.)
+ *
+ * Scan gets its own get function since stuff inherits it.
+ * ----------------
+ */
+static void
+_getScan(Scan *node)
+{
+ char *token;
+ int length;
+
+ _getPlan((Plan*)node);
+
+ token = lsptok(NULL, &length); /* eat :scanrelid */
+ token = lsptok(NULL, &length); /* get scanrelid */
+ node->scanrelid = atoi(token);
+}
+
+/* ----------------
+ * _readScan
+ *
+ * Scan is a subclass of Plan (Not Node, see above).
+ * ----------------
+ */
+static Scan *
+_readScan()
+{
+ Scan *local_node;
+
+ local_node = makeNode(Scan);
+
+ _getScan(local_node);
+
+ return(local_node);
+}
+
+/* ----------------
+ * _readSeqScan
+ *
+ * SeqScan is a subclass of Scan
+ * ----------------
+ */
+static SeqScan *
+_readSeqScan()
+{
+ SeqScan *local_node;
+
+ local_node = makeNode(SeqScan);
+
+ _getScan((Scan*)local_node);
+
+ return(local_node);
+}
+
+/* ----------------
+ * _readIndexScan
+ *
+ * IndexScan is a subclass of Scan
+ * ----------------
+ */
+static IndexScan *
+_readIndexScan()
+{
+ IndexScan *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(IndexScan);
+
+ _getScan((Scan*)local_node);
+
+ token = lsptok(NULL, &length); /* eat :indxid */
+ local_node->indxid =
+ toIntList(nodeRead(true)); /* now read it */
+
+ token = lsptok(NULL, &length); /* eat :indxqual */
+ local_node->indxqual = nodeRead(true); /* now read it */
+
+ return(local_node);
+}
+
+/* ----------------
+ * _readTemp
+ *
+ * Temp is a subclass of Plan
+ * ----------------
+ */
+static Temp *
+_readTemp()
+{
+ Temp *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Temp);
+
+ _getPlan((Plan*)local_node);
+
+ token = lsptok(NULL, &length); /* eat :tempid */
+ token = lsptok(NULL, &length); /* get tempid */
+ local_node->tempid = atol(token);
+
+ token = lsptok(NULL, &length); /* eat :keycount */
+ token = lsptok(NULL, &length); /* get keycount */
+ local_node->keycount = atoi(token);
+
+ return(local_node);
+}
+
+/* ----------------
+ * _readSort
+ *
+ * Sort is a subclass of Temp
+ * ----------------
+ */
+static Sort *
+_readSort()
+{
+ Sort *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Sort);
+
+ _getPlan((Plan*)local_node);
+
+ token = lsptok(NULL, &length); /* eat :tempid */
+ token = lsptok(NULL, &length); /* get tempid */
+ local_node->tempid = atol(token);
+
+ token = lsptok(NULL, &length); /* eat :keycount */
+ token = lsptok(NULL, &length); /* get keycount */
+ local_node->keycount = atoi(token);
+
+ return(local_node);
+}
+
+static Agg *
+_readAgg()
+{
+ Agg *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Agg);
+ _getPlan((Plan*)local_node);
+
+ token = lsptok(NULL, &length); /* eat :numagg */
+ token = lsptok(NULL, &length); /* get numagg */
+ local_node->numAgg = atoi(token);
+
+ return(local_node);
+}
+
+/* ----------------
+ * _readUnique
+ *
+ * For some reason, unique is a subclass of Temp.
+ */
+static Unique *
+_readUnique()
+{
+ Unique *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Unique);
+
+ _getPlan((Plan*)local_node);
+
+ token = lsptok(NULL, &length); /* eat :tempid */
+ token = lsptok(NULL, &length); /* get :tempid */
+ local_node->tempid = atol(token);
+
+ token = lsptok(NULL, &length); /* eat :keycount */
+ token = lsptok(NULL, &length); /* get :keycount */
+ local_node->keycount = atoi(token);
+
+ return(local_node);
+}
+
+/* ----------------
+ * _readHash
+ *
+ * Hash is a subclass of Temp
+ * ----------------
+ */
+static Hash *
+_readHash()
+{
+ Hash *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Hash);
+
+ _getPlan((Plan*)local_node);
+
+ token = lsptok(NULL, &length); /* eat :hashkey */
+ local_node->hashkey = (Var*) nodeRead(true);
+
+ token = lsptok(NULL, &length); /* eat :hashtable */
+ token = lsptok(NULL, &length); /* eat hashtable address*/
+ local_node->hashtable = NULL;
+
+ token = lsptok(NULL, &length); /* eat :hashtablekey*/
+ token = lsptok(NULL, &length); /* get hashtablekey */
+ local_node->hashtablekey = 0;
+
+ token = lsptok(NULL, &length); /* eat :hashtablesize*/
+ token = lsptok(NULL, &length); /* get hashtablesize */
+ local_node->hashtablesize = 0;
+
+ return(local_node);
+}
+
+/*
+ * Stuff from primnodes.h.
+ */
+
+/* ----------------
+ * _readResdom
+ *
+ * Resdom is a subclass of Node
+ * ----------------
+ */
+static Resdom *
+_readResdom()
+{
+ Resdom *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Resdom);
+
+ token = lsptok(NULL, &length); /* eat :resno */
+ token = lsptok(NULL, &length); /* get resno */
+ local_node->resno = atoi(token);
+
+ token = lsptok(NULL, &length); /* eat :restype */
+ token = lsptok(NULL, &length); /* get restype */
+ local_node->restype = atol(token);
+
+ token = lsptok(NULL, &length); /* eat :reslen */
+ token = lsptok(NULL, &length); /* get reslen */
+ local_node->reslen = atoi(token);
+
+ token = lsptok(NULL, &length); /* eat :resname */
+ token = lsptok(NULL, &length); /* get the name */
+
+ if (!strncmp(token, "\"null\"", 5)) {
+ local_node->resname = NULL;
+ }else {
+ /*
+ * Peel off ""'s, then make a true copy.
+ */
+
+ token++;
+ token[length - 2] = '\0';
+
+ local_node->resname = palloc(length);
+ strcpy(local_node->resname, token);
+ token[length - 2] = '\"';
+ }
+
+ token = lsptok(NULL, &length); /* eat :reskey */
+ token = lsptok(NULL, &length); /* get reskey */
+ local_node->reskey = atoi(token);
+
+ token = lsptok(NULL, &length); /* eat :reskeyop */
+ token = lsptok(NULL, &length); /* get reskeyop */
+ local_node->reskeyop = (Oid) atol(token);
+
+ token = lsptok(NULL, &length); /* eat :resjunk */
+ token = lsptok(NULL, &length); /* get resjunk */
+ local_node->resjunk = atoi(token);
+
+ return(local_node);
+}
+
+/* ----------------
+ * _readExpr
+ *
+ * Expr is a subclass of Node
+ * ----------------
+ */
+static Expr *
+_readExpr()
+{
+ Expr *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Expr);
+
+ token = lsptok(NULL, &length); /* eat :typeOid */
+ token = lsptok(NULL, &length); /* get typeOid */
+ local_node->typeOid = (Oid)atol(token);
+
+ token = lsptok(NULL, &length); /* eat :opType */
+ token = lsptok(NULL, &length); /* get opType */
+ if (!strncmp(token, "op", 2)) {
+ local_node->opType = OP_EXPR;
+ } else if (!strncmp(token, "func", 4)) {
+ local_node->opType = FUNC_EXPR;
+ } else if (!strncmp(token, "or", 2)) {
+ local_node->opType = OR_EXPR;
+ } else if (!strncmp(token, "and", 3)) {
+ local_node->opType = AND_EXPR;
+ } else if (!strncmp(token, "not", 3)) {
+ local_node->opType = NOT_EXPR;
+ }
+
+ token = lsptok(NULL, &length); /* eat :oper */
+ local_node->oper = nodeRead(true);
+
+ token = lsptok(NULL, &length); /* eat :args */
+ local_node->args = nodeRead(true); /* now read it */
+
+ return(local_node);
+}
+
+/* ----------------
+ * _readVar
+ *
+ * Var is a subclass of Expr
+ * ----------------
+ */
+static Var *
+_readVar()
+{
+ Var *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Var);
+
+ token = lsptok(NULL, &length); /* eat :varno */
+ token = lsptok(NULL, &length); /* get varno */
+ local_node->varno = atoi(token);
+
+ token = lsptok(NULL, &length); /* eat :varattno */
+ token = lsptok(NULL, &length); /* get varattno */
+ local_node->varattno = atoi(token);
+
+ token = lsptok(NULL, &length); /* eat :vartype */
+ token = lsptok(NULL, &length); /* get vartype */
+ local_node->vartype = (Oid) atol(token);
+
+ token = lsptok(NULL, &length); /* eat :varnoold */
+ token = lsptok(NULL, &length); /* get varnoold */
+ local_node->varnoold = (Oid) atol(token);
+
+ token = lsptok(NULL, &length); /* eat :varoattno */
+ token = lsptok(NULL, &length); /* eat :varoattno */
+ local_node->varoattno = (int) atol(token);
+
+ return(local_node);
+}
+
+/* ----------------
+ * _readArray
+ *
+ * Array is a subclass of Expr
+ * ----------------
+ */
+static Array *
+_readArray()
+{
+ Array *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Array);
+
+ token = lsptok(NULL, &length); /* eat :arrayelemtype */
+ token = lsptok(NULL, &length); /* get arrayelemtype */
+ local_node->arrayelemtype = (Oid) atoi(token);
+
+ token = lsptok(NULL, &length); /* eat :arrayelemlength */
+ token = lsptok(NULL, &length); /* get arrayelemlength */
+ local_node->arrayelemlength = atoi(token);
+
+ token = lsptok(NULL, &length); /* eat :arrayelembyval */
+ token = lsptok(NULL, &length); /* get arrayelembyval */
+ local_node->arrayelembyval = (token[0] == 't') ? true : false;
+
+ token = lsptok(NULL, &length); /* eat :arraylow */
+ token = lsptok(NULL, &length); /* get arraylow */
+ local_node->arraylow.indx[0] = atoi(token);
+
+ token = lsptok(NULL, &length); /* eat :arrayhigh */
+ token = lsptok(NULL, &length); /* get arrayhigh */
+ local_node->arrayhigh.indx[0] = atoi(token);
+
+ token = lsptok(NULL, &length); /* eat :arraylen */
+ token = lsptok(NULL, &length); /* get arraylen */
+ local_node->arraylen = atoi(token);
+
+ return(local_node);
+}
+
+/* ----------------
+ * _readArrayRef
+ *
+ * ArrayRef is a subclass of Expr
+ * ----------------
+ */
+static ArrayRef *
+_readArrayRef()
+{
+ ArrayRef *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(ArrayRef);
+
+ token = lsptok(NULL, &length); /* eat :refelemtype */
+ token = lsptok(NULL, &length); /* get refelemtype */
+ local_node->refelemtype = (Oid) atoi(token);
+
+ token = lsptok(NULL, &length); /* eat :refattrlength */
+ token = lsptok(NULL, &length); /* get refattrlength */
+ local_node->refattrlength = atoi(token);
+
+ token = lsptok(NULL, &length); /* eat :refelemlength */
+ token = lsptok(NULL, &length); /* get refelemlength */
+ local_node->refelemlength = atoi(token);
+
+ token = lsptok(NULL, &length); /* eat :refelembyval */
+ token = lsptok(NULL, &length); /* get refelembyval */
+ local_node->refelembyval = (token[0] == 't') ? true : false;
+
+ token = lsptok(NULL, &length); /* eat :refupperindex */
+ local_node->refupperindexpr = nodeRead(true);
+
+ token = lsptok(NULL, &length); /* eat :reflowerindex */
+ local_node->reflowerindexpr = nodeRead(true);
+
+ token = lsptok(NULL, &length); /* eat :refexpr */
+ local_node->refexpr = nodeRead(true);
+
+ token = lsptok(NULL, &length); /* eat :refassgnexpr */
+ local_node->refassgnexpr = nodeRead(true);
+
+ return(local_node);
+}
+
+/* ----------------
+ * _readConst
+ *
+ * Const is a subclass of Expr
+ * ----------------
+ */
+static Const *
+_readConst()
+{
+ Const *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Const);
+
+ token = lsptok(NULL, &length); /* get :consttype */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->consttype = atol(token);
+
+
+ token = lsptok(NULL, &length); /* get :constlen */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->constlen = atoi(token);
+
+ token = lsptok(NULL, &length); /* get :constisnull */
+ token = lsptok(NULL, &length); /* now read it */
+
+ if (!strncmp(token, "true", 4)) {
+ local_node->constisnull = true;
+ }else {
+ local_node->constisnull = false;
+ }
+
+
+ token = lsptok(NULL, &length); /* get :constvalue */
+
+ if (local_node->constisnull) {
+ token = lsptok(NULL, &length); /* skip "NIL" */
+ }else {
+ /*
+ * read the value
+ */
+ local_node->constvalue = readDatum(local_node->consttype);
+ }
+
+ token = lsptok(NULL, &length); /* get :constbyval */
+ token = lsptok(NULL, &length); /* now read it */
+
+ if (!strncmp(token, "true", 4)) {
+ local_node->constbyval = true;
+ }else {
+ local_node->constbyval = false;
+ }
+
+ return(local_node);
+}
+
+/* ----------------
+ * _readFunc
+ *
+ * Func is a subclass of Expr
+ * ----------------
+ */
+static Func *
+_readFunc()
+{
+ Func *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Func);
+
+ token = lsptok(NULL, &length); /* get :funcid */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->funcid = atol(token);
+
+ token = lsptok(NULL, &length); /* get :functype */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->functype = atol(token);
+
+ token = lsptok(NULL, &length); /* get :funcisindex */
+ token = lsptok(NULL, &length); /* now read it */
+
+ if (!strncmp(token, "true", 4)) {
+ local_node->funcisindex = true;
+ }else {
+ local_node->funcisindex = false;
+ }
+
+ token = lsptok(NULL, &length); /* get :funcsize */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->funcsize = atol(token);
+
+ token = lsptok(NULL, &length); /* get :func_fcache */
+ token = lsptok(NULL, &length); /* get @ */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->func_fcache = (FunctionCache *) NULL;
+
+ token = lsptok(NULL, &length); /* get :func_tlist */
+ local_node->func_tlist = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :func_planlist */
+ local_node->func_planlist = nodeRead(true); /* now read it */
+
+ return(local_node);
+}
+
+/* ----------------
+ * _readOper
+ *
+ * Oper is a subclass of Expr
+ * ----------------
+ */
+static Oper *
+_readOper()
+{
+ Oper *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Oper);
+
+ token = lsptok(NULL, &length); /* get :opno */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->opno = atol(token);
+
+ token = lsptok(NULL, &length); /* get :opid */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->opid = atol(token);
+
+ token = lsptok(NULL, &length); /* get :opresulttype */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->opresulttype = atol(token);
+
+ /*
+ * NOTE: Alternatively we can call 'replace_opid'
+ * which initializes both 'opid' and 'op_fcache'.
+ */
+ local_node->op_fcache = (FunctionCache *) NULL;
+
+ return(local_node);
+}
+
+/* ----------------
+ * _readParam
+ *
+ * Param is a subclass of Expr
+ * ----------------
+ */
+static Param *
+_readParam()
+{
+ Param *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Param);
+
+ token = lsptok(NULL, &length); /* get :paramkind */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->paramkind = atoi(token);
+
+ token = lsptok(NULL, &length); /* get :paramid */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->paramid = atol(token);
+
+ token = lsptok(NULL, &length); /* get :paramname */
+ token = lsptok(NULL, &length); /* now read it */
+ token++; /* skip the first `"' */
+ token[length - 2] = '\0'; /* this is the 2nd `"' */
+
+ local_node->paramname = pstrdup(token);
+ token[length - 2] = '\"'; /* restore the 2nd `"' */
+
+ token = lsptok(NULL, &length); /* get :paramtype */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->paramtype = atol(token);
+ token = lsptok(NULL, &length); /* get :param_tlist */
+ local_node->param_tlist = nodeRead(true); /* now read it */
+
+ return(local_node);
+}
+
+/*
+ * Stuff from execnodes.h
+ */
+
+/* ----------------
+ * _readEState
+ *
+ * EState is a subclass of Node.
+ * ----------------
+ */
+static EState *
+_readEState()
+{
+ EState *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(EState);
+
+ token = lsptok(NULL, &length); /* get :direction */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->es_direction = atoi(token);
+
+ token = lsptok(NULL, &length); /* get :range_table */
+
+ local_node->es_range_table = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :result_relation_info */
+ token = lsptok(NULL, &length); /* get @ */
+ token = lsptok(NULL, &length); /* now read it */
+
+ sscanf(token, "%x", &local_node->es_result_relation_info);
+
+ return(local_node);
+}
+
+/*
+ * Stuff from relation.h
+ */
+
+/* ----------------
+ * _readRel
+ * ----------------
+ */
+static Rel *
+_readRel()
+{
+ Rel *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Rel);
+
+ token = lsptok(NULL, &length); /* get :relids */
+ local_node->relids =
+ toIntList(nodeRead(true)); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :indexed */
+ token = lsptok(NULL, &length); /* now read it */
+
+ if (!strncmp(token, "true", 4))
+ {
+ local_node->indexed = true;
+ }
+ else
+ {
+ local_node->indexed = false;
+ }
+
+ token = lsptok(NULL, &length); /* get :pages */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->pages = (unsigned int) atoi(token);
+
+ token = lsptok(NULL, &length); /* get :tuples */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->tuples = (unsigned int) atoi(token);
+
+ token = lsptok(NULL, &length); /* get :size */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->size = (unsigned int) atoi(token);
+
+ token = lsptok(NULL, &length); /* get :width */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->width = (unsigned int) atoi(token);
+
+ token = lsptok(NULL, &length); /* get :targetlist */
+ local_node->targetlist = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :pathlist */
+ local_node->pathlist = nodeRead(true); /* now read it */
+
+ /*
+ * Not sure if these are nodes or not. They're declared as
+ * struct Path *. Since i don't know, i'll just print the
+ * addresses for now. This can be changed later, if necessary.
+ */
+
+ token = lsptok(NULL, &length); /* get :unorderpath */
+ token = lsptok(NULL, &length); /* get @ */
+ token = lsptok(NULL, &length); /* now read it */
+
+ sscanf(token, "%x", &local_node->unorderedpath);
+
+ token = lsptok(NULL, &length); /* get :cheapestpath */
+ token = lsptok(NULL, &length); /* get @ */
+ token = lsptok(NULL, &length); /* now read it */
+
+ sscanf(token, "%x", &local_node->cheapestpath);
+
+
+ token = lsptok(NULL, &length); /* get :clauseinfo */
+ local_node->clauseinfo = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :joininfo */
+ local_node->joininfo = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :innerjoin */
+ local_node->innerjoin = nodeRead(true); /* now read it */
+
+ return(local_node);
+}
+
+/* ----------------
+ * _readTargetEntry
+ * ----------------
+ */
+static TargetEntry *
+_readTargetEntry()
+{
+ TargetEntry *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(TargetEntry);
+
+ token = lsptok(NULL, &length); /* get :resdom */
+ local_node->resdom = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :expr */
+ local_node->expr = nodeRead(true); /* now read it */
+
+ return (local_node);
+}
+
+/* ----------------
+ * _readTargetEntry
+ * ----------------
+ */
+static RangeTblEntry *
+_readRangeTblEntry()
+{
+ RangeTblEntry *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(RangeTblEntry);
+
+ token = lsptok(NULL, &length); /* eat :relname */
+ token = lsptok(NULL, &length); /* get :relname */
+ if (!strncmp(token, "\"null\"", 5)) {
+ local_node->relname = NULL;
+ }else {
+ /*
+ * Peel off ""'s, then make a true copy.
+ */
+
+ token++;
+ token[length - 2] = '\0';
+
+ local_node->relname = (Name) palloc(NAMEDATALEN);
+ namestrcpy(local_node->relname, token);
+ token[length - 2] = '\"';
+ }
+
+ token = lsptok(NULL, &length); /* eat :inh */
+ token = lsptok(NULL, &length); /* get :inh */
+ local_node->inh = atoi(token);
+
+ token = lsptok(NULL, &length); /* eat :refname */
+ token = lsptok(NULL, &length); /* get :refname */
+ if (!strncmp(token, "\"null\"", 5)) {
+ local_node->refname = NULL;
+ }else {
+ /*
+ * Peel off ""'s, then make a true copy.
+ */
+
+ token++;
+ token[length - 2] = '\0';
+
+ local_node->refname = (char*)pstrdup(token);
+ token[length - 2] = '\"';
+ }
+
+ token = lsptok(NULL, &length); /* eat :relid */
+ token = lsptok(NULL, &length); /* get :relid */
+ local_node->relid = atoi(token);
+
+ return (local_node);
+}
+
+/* ----------------
+ * _readPath
+ *
+ * Path is a subclass of Node.
+ * ----------------
+ */
+static Path *
+_readPath()
+{
+ Path *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Path);
+
+ token = lsptok(NULL, &length); /* get :pathtype */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->pathtype = atol(token);
+
+ token = lsptok(NULL, &length); /* get :cost */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->path_cost = (Cost) atof(token);
+
+#if 0
+ token = lsptok(NULL, &length); /* get :p_ordering */
+ local_node->p_ordering =
+ nodeRead(true); /* now read it */
+#endif
+
+ token = lsptok(NULL, &length); /* get :keys */
+ local_node->keys = nodeRead(true); /* now read it */
+
+ return(local_node);
+}
+
+/* ----------------
+ * _readIndexPath
+ *
+ * IndexPath is a subclass of Path.
+ * ----------------
+ */
+static IndexPath *
+_readIndexPath()
+{
+ IndexPath *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(IndexPath);
+
+ 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);
+
+#if 0
+ token = lsptok(NULL, &length); /* get :p_ordering */
+ local_node->path.p_ordering = nodeRead(true); /* now read it */
+#endif
+
+ token = lsptok(NULL, &length); /* get :keys */
+ local_node->path.keys = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :indexid */
+ local_node->indexid =
+ toIntList(nodeRead(true));
+
+ token = lsptok(NULL, &length); /* get :indexqual */
+ local_node->indexqual = nodeRead(true); /* now read it */
+
+ return(local_node);
+}
+
+/* ----------------
+ * _readJoinPath
+ *
+ * JoinPath is a subclass of Path
+ * ----------------
+ */
+static JoinPath *
+_readJoinPath()
+{
+ JoinPath *local_node;
+ char *token;
+ int length;
+
+
+ local_node = makeNode(JoinPath);
+
+ 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);
+
+#if 0
+ token = lsptok(NULL, &length); /* get :p_ordering */
+ local_node->path.p_ordering = nodeRead(true); /* now read it */
+#endif
+
+ token = lsptok(NULL, &length); /* get :keys */
+ local_node->path.keys = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :pathclauseinfo */
+ local_node->pathclauseinfo = nodeRead(true); /* now read it */
+
+ /*
+ * Not sure if these are nodes; they're declared as "struct path *".
+ * For now, i'll just print the addresses.
+ *
+ * GJK: Since I am parsing this stuff, I'll just ignore the addresses,
+ * and initialize these pointers to NULL.
+ */
+
+ token = lsptok(NULL, &length); /* get :outerjoinpath */
+ token = lsptok(NULL, &length); /* get @ */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->outerjoinpath = NULL;
+
+ token = lsptok(NULL, &length); /* get :innerjoinpath */
+ token = lsptok(NULL, &length); /* get @ */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->innerjoinpath = NULL;
+
+ token = lsptok(NULL, &length); /* get :outerjoincost */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->path.outerjoincost = (Cost) atof(token);
+
+ token = lsptok(NULL, &length); /* get :joinid */
+ local_node->path.joinid =
+ toIntList(nodeRead(true)); /* now read it */
+
+ return(local_node);
+}
+
+/* ----------------
+ * _readMergePath
+ *
+ * MergePath is a subclass of JoinPath.
+ * ----------------
+ */
+static MergePath *
+_readMergePath()
+{
+ MergePath *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(MergePath);
+
+ token = lsptok(NULL, &length); /* get :pathtype */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->jpath.path.pathtype = atol(token);
+
+ token = lsptok(NULL, &length); /* get :cost */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->jpath.path.path_cost = (Cost) atof(token);
+
+#if 0
+ token = lsptok(NULL, &length); /* get :p_ordering */
+ local_node->jpath.path.p_ordering = nodeRead(true); /* now read it */
+#endif
+
+ token = lsptok(NULL, &length); /* get :keys */
+ local_node->jpath.path.keys = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :pathclauseinfo */
+ local_node->jpath.pathclauseinfo = nodeRead(true); /* now read it */
+
+ /*
+ * Not sure if these are nodes; they're declared as "struct path *".
+ * For now, i'll just print the addresses.
+ *
+ * GJK: Since I am parsing this stuff, I'll just ignore the addresses,
+ * and initialize these pointers to NULL.
+ */
+
+ token = lsptok(NULL, &length); /* get :outerjoinpath */
+ token = lsptok(NULL, &length); /* get @ */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->jpath.outerjoinpath = NULL;
+
+ token = lsptok(NULL, &length); /* get :innerjoinpath */
+ token = lsptok(NULL, &length); /* get @ */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->jpath.innerjoinpath = NULL;
+
+ token = lsptok(NULL, &length); /* get :outerjoincost */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->jpath.path.outerjoincost = (Cost) atof(token);
+
+ token = lsptok(NULL, &length); /* get :joinid */
+ local_node->jpath.path.joinid =
+ toIntList(nodeRead(true)); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :path_mergeclauses */
+ local_node->path_mergeclauses = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :outersortkeys */
+ local_node->outersortkeys = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :innersortkeys */
+ local_node->innersortkeys = nodeRead(true); /* now read it */
+
+ return(local_node);
+}
+
+/* ----------------
+ * _readHashPath
+ *
+ * HashPath is a subclass of JoinPath.
+ * ----------------
+ */
+static HashPath *
+_readHashPath()
+{
+ HashPath *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(HashPath);
+
+ token = lsptok(NULL, &length); /* get :pathtype */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->jpath.path.pathtype = atol(token);
+
+ token = lsptok(NULL, &length); /* get :cost */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->jpath.path.path_cost = (Cost) atof(token);
+
+#if 0
+ token = lsptok(NULL, &length); /* get :p_ordering */
+ local_node->jpath.path.p_ordering = nodeRead(true); /* now read it */
+#endif
+
+ token = lsptok(NULL, &length); /* get :keys */
+ local_node->jpath.path.keys = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :pathclauseinfo */
+ local_node->jpath.pathclauseinfo = nodeRead(true); /* now read it */
+
+ /*
+ * Not sure if these are nodes; they're declared as "struct path *".
+ * For now, i'll just print the addresses.
+ *
+ * GJK: Since I am parsing this stuff, I'll just ignore the addresses,
+ * and initialize these pointers to NULL.
+ */
+
+ token = lsptok(NULL, &length); /* get :outerjoinpath */
+ token = lsptok(NULL, &length); /* get @ */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->jpath.outerjoinpath = NULL;
+
+ token = lsptok(NULL, &length); /* get :innerjoinpath */
+ token = lsptok(NULL, &length); /* get @ */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->jpath.innerjoinpath = NULL;
+
+ token = lsptok(NULL, &length); /* get :outerjoincost */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->jpath.path.outerjoincost = (Cost) atof(token);
+
+ token = lsptok(NULL, &length); /* get :joinid */
+ local_node->jpath.path.joinid =
+ toIntList(nodeRead(true)); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :path_hashclauses */
+ local_node->path_hashclauses = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :outerhashkeys */
+ local_node->outerhashkeys = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :innerhashkeys */
+ local_node->innerhashkeys = nodeRead(true); /* now read it */
+
+ return(local_node);
+}
+
+/* ----------------
+ * _readOrderKey
+ *
+ * OrderKey is a subclass of Node.
+ * ----------------
+ */
+static OrderKey *
+_readOrderKey()
+{
+ OrderKey *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(OrderKey);
+
+ token = lsptok(NULL, &length); /* get :attribute_number */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->attribute_number = atoi(token);
+
+ token = lsptok(NULL, &length); /* get :array_index */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->array_index = atoi(token);
+
+ return(local_node);
+}
+
+/* ----------------
+ * _readJoinKey
+ *
+ * JoinKey is a subclass of Node.
+ * ----------------
+ */
+static JoinKey *
+_readJoinKey()
+{
+ JoinKey *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(JoinKey);
+
+ token = lsptok(NULL, &length); /* get :outer */
+ local_node->outer = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :inner */
+ local_node->inner = nodeRead(true); /* now read it */
+
+ return(local_node);
+}
+
+/* ----------------
+ * _readMergeOrder
+ *
+ * MergeOrder is a subclass of Node.
+ * ----------------
+ */
+static MergeOrder *
+_readMergeOrder()
+{
+ MergeOrder *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(MergeOrder);
+ token = lsptok(NULL, &length); /* get :join_operator */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->join_operator = atol(token);
+
+ token = lsptok(NULL, &length); /* get :left_operator */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->left_operator = atol(token);
+
+ token = lsptok(NULL, &length); /* get :right_operator */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->right_operator = atol(token);
+
+ token = lsptok(NULL, &length); /* get :left_type */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->left_type = atol(token);
+
+ token = lsptok(NULL, &length); /* get :right_type */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->right_type = atol(token);
+
+ return(local_node);
+}
+
+/* ----------------
+ * _readCInfo
+ *
+ * CInfo is a subclass of Node.
+ * ----------------
+ */
+static CInfo *
+_readCInfo()
+{
+ CInfo *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(CInfo);
+
+ token = lsptok(NULL, &length); /* get :clause */
+ local_node->clause = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :selectivity */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->selectivity = atof(token);
+
+ token = lsptok(NULL, &length); /* get :notclause */
+ token = lsptok(NULL, &length); /* now read it */
+
+ if (!strncmp(token, "true", 4))
+ {
+ local_node->notclause = true;
+ }
+ else
+ {
+ local_node->notclause = false;
+ }
+
+ token = lsptok(NULL, &length); /* get :indexids */
+ local_node->indexids = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :mergesortorder */
+ local_node->mergesortorder = (MergeOrder*) nodeRead(true);
+
+ token = lsptok(NULL, &length); /* get :hashjoinoperator */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->hashjoinoperator = atol(token);
+
+ return(local_node);
+}
+
+/* ----------------
+ * _readJoinMethod
+ *
+ * JoinMethod is a subclass of Node.
+ * ----------------
+ */
+static JoinMethod *
+_readJoinMethod()
+{
+ JoinMethod *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(JoinMethod);
+
+ token = lsptok(NULL, &length); /* get :jmkeys */
+ local_node->jmkeys = nodeRead(true);/* now read it */
+
+ token = lsptok(NULL, &length); /* get :clauses */
+ local_node->clauses = nodeRead(true); /* now read it */
+
+ return(local_node);
+}
+
+/* ----------------
+ * _readHInfo
+ *
+ * HInfo is a subclass of JoinMethod.
+ * ----------------
+ */
+static HInfo *
+_readHInfo()
+{
+ HInfo *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(HInfo);
+
+ token = lsptok(NULL, &length); /* get :hashop */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->hashop = atoi(token);
+
+ token = lsptok(NULL, &length); /* get :jmkeys */
+ local_node->jmethod.jmkeys = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :clauses */
+ local_node->jmethod.clauses = nodeRead(true); /* now read it */
+
+ return(local_node);
+}
+
+/* ----------------
+ * _readJInfo()
+ *
+ * JInfo is a subclass of Node.
+ * ----------------
+ */
+static JInfo *
+_readJInfo()
+{
+ JInfo *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(JInfo);
+
+ token = lsptok(NULL, &length); /* get :otherrels */
+ local_node->otherrels =
+ toIntList(nodeRead(true)); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :jinfoclauseinfo */
+ local_node->jinfoclauseinfo = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :mergesortable */
+
+ if (!strncmp(token, "true", 4))
+ {
+ local_node->mergesortable = true;
+ }
+ else
+ {
+ local_node->mergesortable = false;
+ }
+
+ token = lsptok(NULL, &length); /* get :hashjoinable */
+
+ if (!strncmp(token, "true", 4))
+ {
+ local_node->hashjoinable = true;
+ }
+ else
+ {
+ local_node->hashjoinable = false;
+ }
+
+ return(local_node);
+}
+
+/* ----------------
+ * _readIter()
+ *
+ * ----------------
+ */
+static Iter *
+_readIter()
+{
+ Iter *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Iter);
+
+ token = lsptok(NULL, &length); /* eat :iterexpr */
+ local_node->iterexpr = nodeRead(true); /* now read it */
+
+ return(local_node);
+}
+
+
+/* ----------------
+ * parsePlanString
+ *
+ * Given a character string containing a plan, parsePlanString sets up the
+ * plan structure representing that plan.
+ *
+ * The string passed to parsePlanString must be null-terminated.
+ * ----------------
+ */
+Node *
+parsePlanString()
+{
+ char *token;
+ int length;
+ void *return_value;
+
+ token = lsptok(NULL, &length);
+
+ if (!strncmp(token, "PLAN", 4)) {
+ return_value = _readPlan();
+ }else if (!strncmp(token, "RESULT", 6)) {
+ return_value = _readResult();
+ }else if (!strncmp(token, "EXISTENTIAL", 11)) {
+ return_value = _readExistential();
+ }else if (!strncmp(token, "APPEND", 6)) {
+ return_value = _readAppend();
+ }else if (!strncmp(token, "JOIN", 4)) {
+ return_value = _readJoin();
+ }else if (!strncmp(token, "NESTLOOP", 8)) {
+ return_value = _readNestLoop();
+ }else if (!strncmp(token, "MERGEJOIN", 9)) {
+ return_value = _readMergeJoin();
+ }else if (!strncmp(token, "HASHJOIN", 8)) {
+ return_value = _readHashJoin();
+ }else if (!strncmp(token, "SCAN", 4)) {
+ return_value = _readScan();
+ }else if (!strncmp(token, "SEQSCAN", 7)) {
+ return_value = _readSeqScan();
+ }else if (!strncmp(token, "INDEXSCAN", 9)) {
+ return_value = _readIndexScan();
+ }else if (!strncmp(token, "TEMP", 4)) {
+ return_value = _readTemp();
+ }else if (!strncmp(token, "SORT", 4)) {
+ return_value = _readSort();
+ }else if (!strncmp(token, "AGG", 3)) {
+ return_value = _readAgg();
+ }else if (!strncmp(token, "UNIQUE", 4)) {
+ return_value = _readUnique();
+ }else if (!strncmp(token, "HASH", 4)) {
+ return_value = _readHash();
+ }else if (!strncmp(token, "RESDOM", 6)) {
+ return_value = _readResdom();
+ }else if (!strncmp(token, "EXPR", 4)) {
+ return_value = _readExpr();
+ }else if (!strncmp(token, "ARRAYREF", 7)) {
+ /* make sure this strncmp is done before that of ARRAY */
+ return_value = _readArrayRef();
+ }else if (!strncmp(token, "ARRAY", 5)) {
+ return_value = _readArray();
+ }else if (!strncmp(token, "VAR", 3)) {
+ return_value = _readVar();
+ }else if (!strncmp(token, "CONST", 5)) {
+ return_value = _readConst();
+ }else if (!strncmp(token, "FUNC", 4)) {
+ return_value = _readFunc();
+ }else if (!strncmp(token, "OPER", 4)) {
+ return_value = _readOper();
+ }else if (!strncmp(token, "PARAM", 5)) {
+ return_value = _readParam();
+ }else if (!strncmp(token, "ESTATE", 6)) {
+ return_value = _readEState();
+ }else if (!strncmp(token, "REL", 3)) {
+ return_value = _readRel();
+ }else if (!strncmp(token, "TLE", 3)) {
+ return_value = _readTargetEntry();
+ }else if (!strncmp(token, "RTE", 3)) {
+ return_value = _readRangeTblEntry();
+ }else if (!strncmp(token, "PATH", 4)) {
+ return_value = _readPath();
+ }else if (!strncmp(token, "INDEXPATH", 9)) {
+ return_value = _readIndexPath();
+ }else if (!strncmp(token, "JOINPATH", 8)) {
+ return_value = _readJoinPath();
+ }else if (!strncmp(token, "MERGEPATH", 9)) {
+ return_value = _readMergePath();
+ }else if (!strncmp(token, "HASHPATH", 8)) {
+ return_value = _readHashPath();
+ }else if (!strncmp(token, "ORDERKEY", 8)) {
+ return_value = _readOrderKey();
+ }else if (!strncmp(token, "JOINKEY", 7)) {
+ return_value = _readJoinKey();
+ }else if (!strncmp(token, "MERGEORDER", 10)) {
+ return_value = _readMergeOrder();
+ }else if (!strncmp(token, "CINFO", 5)) {
+ return_value = _readCInfo();
+ }else if (!strncmp(token, "JOINMETHOD", 10)) {
+ return_value = _readJoinMethod();
+ }else if (!strncmp(token, "JINFO", 5)) {
+ return_value = _readJInfo();
+ }else if (!strncmp(token, "HINFO", 5)) {
+ return_value = _readHInfo();
+ }else if (!strncmp(token, "ITER", 4)) {
+ return_value = _readIter();
+ }else if (!strncmp(token, "QUERY", 5)) {
+ return_value = _readQuery();
+ }else {
+ elog(WARN, "badly formatted planstring \"%.10s\"...\n", token);
+ }
+
+ return ((Node*)return_value);
+}
+/*------------------------------------------------------------*/
+
+/* ----------------
+ * readDatum
+ *
+ * given a string representation of the value of the given type,
+ * create the appropriate Datum
+ * ----------------
+ */
+static Datum
+readDatum(Oid type)
+{
+ int length;
+ int tokenLength;
+ char *token;
+ bool byValue;
+ Datum res;
+ char *s;
+ int i;
+
+ byValue = get_typbyval(type);
+
+ /*
+ * read the actual length of the value
+ */
+ token = lsptok(NULL, &tokenLength);
+ length = atoi(token);
+ token = lsptok(NULL, &tokenLength); /* skip the '[' */
+
+ if (byValue) {
+ if (length > sizeof(Datum)) {
+ elog(WARN, "readValue: byval & length = %d", length);
+ }
+ s = (char *) (&res);
+ for (i=0; i<sizeof(Datum); i++) {
+ token = lsptok(NULL, &tokenLength);
+ s[i] = (char) atoi(token);
+ }
+ } else if (length <= 0) {
+ s = NULL;
+ } else if (length >= 1) {
+ s = (char*)palloc(length);
+ Assert( s!=NULL );
+ for (i=0; i<length; i++) {
+ token = lsptok(NULL, &tokenLength);
+ s[i] = (char) atoi(token);
+ }
+ res = PointerGetDatum(s);
+ }
+
+ token = lsptok(NULL, &tokenLength); /* skip the ']' */
+ if (token[0] != ']') {
+ elog(WARN, "readValue: ']' expected, length =%d", length);
+ }
+
+ return(res);
+}
diff --git a/src/backend/nodes/readfuncs.h b/src/backend/nodes/readfuncs.h
new file mode 100644
index 0000000000..de8b818bfc
--- /dev/null
+++ b/src/backend/nodes/readfuncs.h
@@ -0,0 +1,27 @@
+/*-------------------------------------------------------------------------
+ *
+ * readfuncs.h--
+ * header file for read.c and readfuncs.c. These functions are internal
+ * to the stringToNode interface and should not be used by anyone else.
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id$
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef READFUNCS_H
+#define READFUNCS_H
+
+/*
+ * prototypes for functions in read.c (the lisp token parser)
+ */
+extern char *lsptok(char *string, int *length);
+extern void *nodeRead(bool read_car_only);
+
+/*
+ * prototypes for functions in readfuncs.c
+ */
+extern Node *parsePlanString();
+
+#endif /* READFUNCS_H */
diff --git a/src/backend/nodes/relation.h b/src/backend/nodes/relation.h
new file mode 100644
index 0000000000..50b3e62a29
--- /dev/null
+++ b/src/backend/nodes/relation.h
@@ -0,0 +1,279 @@
+/*-------------------------------------------------------------------------
+ *
+ * relation.h--
+ * Definitions for internal planner nodes.
+ *
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id$
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef RELATION_H
+#define RELATION_H
+
+#include "c.h"
+#include "nodes/pg_list.h"
+#include "nodes/primnodes.h"
+#include "nodes/parsenodes.h"
+#include "nodes/nodes.h"
+
+/*
+ * Relid
+ * List of relation identifiers (indexes into the rangetable).
+ */
+
+typedef List *Relid;
+
+/*
+ * Rel
+ * Per-base-relation information
+ *
+ * Parts of this data structure are specific to various scan and join
+ * mechanisms. It didn't seem worth creating new node types for them.
+ *
+ * relids - List of relation indentifiers
+ * indexed - true if the relation has secondary indices
+ * pages - number of pages in the relation
+ * tuples - number of tuples in the relation
+ * size - number of tuples in the relation after restrictions clauses
+ * have been applied
+ * width - number of bytes per tuple in the relation after the
+ * appropriate projections have been done
+ * targetlist - List of TargetList nodes
+ * pathlist - List of Path nodes, one for each possible method of
+ * generating the relation
+ * unorderedpath - a Path node generating this relation whose resulting
+ * tuples are unordered (this isn't necessarily a
+ * sequential scan path, e.g., scanning with a hash index
+ * leaves the tuples unordered)
+ * cheapestpath - least expensive Path (regardless of final order)
+ * pruneable - flag to let the planner know whether it can prune the plan
+ * space of this Rel or not. -- JMH, 11/11/92
+ *
+ * * If the relation is a (secondary) index it will have the following
+ * three fields:
+ *
+ * classlist - List of PG_AMOPCLASS OIDs for the index
+ * indexkeys - List of base-relation attribute numbers that are index keys
+ * ordering - List of PG_OPERATOR OIDs which order the indexscan result
+ * relam - the OID of the pg_am of the index
+ *
+ * * The presence of the remaining fields depends on the restrictions
+ * and joins which the relation participates in:
+ *
+ * clauseinfo - List of ClauseInfo nodes, containing info about each
+ * qualification clause in which this relation participates
+ * joininfo - List of JoinInfo nodes, containing info about each join
+ * clause in which this relation participates
+ * innerjoin - List of Path nodes that represent indices that may be used
+ * as inner paths of nestloop joins
+ *
+ * NB. the last element of the arrays classlist, indexkeys and ordering
+ * is always 0. 2/95 - ay
+ */
+
+typedef struct Rel {
+ NodeTag type;
+
+ /* all relations: */
+ Relid relids;
+
+ /* catalog statistics information */
+ bool indexed;
+ int pages;
+ int tuples;
+ int size;
+ int width;
+
+ /* materialization information */
+ List *targetlist;
+ List *pathlist;
+ struct Path *unorderedpath;
+ struct Path *cheapestpath;
+ bool pruneable;
+
+ /* used solely by indices: */
+ Oid *classlist; /* classes of AM operators */
+ int *indexkeys; /* keys over which we're indexing */
+ Oid relam; /* OID of the access method (in pg_am) */
+
+ Oid indproc;
+ List *indpred;
+
+ /* used by various scans and joins: */
+ Oid *ordering; /* OID of operators in sort order */
+ List *clauseinfo; /* restriction clauses */
+ List *joininfo; /* join clauses */
+ List *innerjoin;
+ List *superrels;
+} Rel;
+
+extern Var *get_expr(TargetEntry *foo);
+
+typedef struct MergeOrder {
+ NodeTag type;
+ Oid join_operator;
+ Oid left_operator;
+ Oid right_operator;
+ Oid left_type;
+ Oid right_type;
+} MergeOrder;
+
+typedef enum OrderType {
+ MERGE_ORDER, SORTOP_ORDER
+} OrderType;
+
+typedef struct PathOrder {
+ OrderType ordtype;
+ union {
+ Oid *sortop;
+ MergeOrder *merge;
+ } ord;
+} PathOrder;
+
+typedef struct Path {
+ NodeTag type;
+
+ Rel *parent;
+ Cost path_cost;
+
+ NodeTag pathtype;
+
+ PathOrder p_ordering;
+
+ List *keys;
+ Cost outerjoincost;
+ Relid joinid;
+ List *locclauseinfo;
+} Path;
+
+typedef struct IndexPath {
+ Path path;
+ List *indexid;
+ List *indexqual;
+} IndexPath;
+
+typedef struct JoinPath {
+ Path path;
+ List *pathclauseinfo;
+ Path *outerjoinpath;
+ Path *innerjoinpath;
+} JoinPath;
+
+typedef struct MergePath {
+ JoinPath jpath;
+ List *path_mergeclauses;
+ List *outersortkeys;
+ List *innersortkeys;
+} MergePath;
+
+typedef struct HashPath {
+ JoinPath jpath;
+ List *path_hashclauses;
+ List *outerhashkeys;
+ List *innerhashkeys;
+} HashPath;
+
+/******
+ * Keys
+ ******/
+
+typedef struct OrderKey {
+ NodeTag type;
+ int attribute_number;
+ Index array_index;
+} OrderKey;
+
+typedef struct JoinKey {
+ NodeTag type;
+ Var *outer;
+ Var *inner;
+} JoinKey;
+
+/*******
+ * clause info
+ *******/
+
+typedef struct CInfo {
+ NodeTag type;
+ Expr *clause; /* should be an OP clause */
+ Cost selectivity;
+ bool notclause;
+ List *indexids;
+
+ /* mergesort only */
+ MergeOrder *mergesortorder;
+
+ /* hashjoin only */
+ Oid hashjoinoperator;
+ Relid cinfojoinid;
+} CInfo;
+
+typedef struct JoinMethod {
+ NodeTag type;
+ List *jmkeys;
+ List *clauses;
+} JoinMethod;
+
+typedef struct HInfo {
+ JoinMethod jmethod;
+ Oid hashop;
+} HInfo;
+
+typedef struct MInfo {
+ JoinMethod jmethod;
+ MergeOrder *m_ordering;
+} MInfo;
+
+typedef struct JInfo {
+ NodeTag type;
+ List *otherrels;
+ List *jinfoclauseinfo;
+ bool mergesortable;
+ bool hashjoinable;
+ bool inactive;
+} JInfo;
+
+typedef struct Iter {
+ NodeTag type;
+ Node *iterexpr;
+ Oid itertype; /* type of the iter expr (use for type
+ checking) */
+} Iter;
+
+/*
+** Stream:
+** A stream represents a root-to-leaf path in a plan tree (i.e. a tree of
+** JoinPaths and Paths). The stream includes pointers to all Path nodes,
+** as well as to any clauses that reside above Path nodes. This structure
+** is used to make Path nodes and clauses look similar, so that Predicate
+** Migration can run.
+**
+** pathptr -- pointer to the current path node
+** cinfo -- if NULL, this stream node referes to the path node.
+** Otherwise this is a pointer to the current clause.
+** clausetype -- whether cinfo is in locclauseinfo or pathclauseinfo in the
+** path node
+** upstream -- linked list pointer upwards
+** downstream -- ditto, downwards
+** groupup -- whether or not this node is in a group with the node upstream
+** groupcost -- total cost of the group that node is in
+** groupsel -- total selectivity of the group that node is in
+*/
+typedef struct Stream *StreamPtr;
+
+typedef struct Stream {
+ NodeTag type;
+ Path *pathptr;
+ CInfo *cinfo;
+ int *clausetype;
+ struct Stream *upstream;
+ struct Stream *downstream;
+ bool groupup;
+ Cost groupcost;
+ Cost groupsel;
+} Stream;
+
+#endif /* RELATION_H */