diff options
Diffstat (limited to 'src/backend/nodes')
| -rw-r--r-- | src/backend/nodes/Makefile.inc | 33 | ||||
| -rw-r--r-- | src/backend/nodes/README | 65 | ||||
| -rw-r--r-- | src/backend/nodes/copyfuncs.c | 1675 | ||||
| -rw-r--r-- | src/backend/nodes/equalfuncs.c | 703 | ||||
| -rw-r--r-- | src/backend/nodes/execnodes.h | 689 | ||||
| -rw-r--r-- | src/backend/nodes/list.c | 438 | ||||
| -rw-r--r-- | src/backend/nodes/makefuncs.c | 117 | ||||
| -rw-r--r-- | src/backend/nodes/makefuncs.h | 48 | ||||
| -rw-r--r-- | src/backend/nodes/memnodes.h | 101 | ||||
| -rw-r--r-- | src/backend/nodes/nodeFuncs.c | 116 | ||||
| -rw-r--r-- | src/backend/nodes/nodeFuncs.h | 23 | ||||
| -rw-r--r-- | src/backend/nodes/nodes.c | 45 | ||||
| -rw-r--r-- | src/backend/nodes/nodes.h | 299 | ||||
| -rw-r--r-- | src/backend/nodes/outfuncs.c | 1670 | ||||
| -rw-r--r-- | src/backend/nodes/params.h | 90 | ||||
| -rw-r--r-- | src/backend/nodes/parsenodes.h | 731 | ||||
| -rw-r--r-- | src/backend/nodes/pg_list.h | 112 | ||||
| -rw-r--r-- | src/backend/nodes/plannodes.h | 330 | ||||
| -rw-r--r-- | src/backend/nodes/primnodes.h | 318 | ||||
| -rw-r--r-- | src/backend/nodes/print.c | 377 | ||||
| -rw-r--r-- | src/backend/nodes/read.c | 270 | ||||
| -rw-r--r-- | src/backend/nodes/readfuncs.c | 1948 | ||||
| -rw-r--r-- | src/backend/nodes/readfuncs.h | 27 | ||||
| -rw-r--r-- | src/backend/nodes/relation.h | 279 |
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 */ |
