postgresql/src/backend/nodes/outfuncs.c

1658 lines
37 KiB
C
Raw Normal View History

/*
*
* outfuncs.c
* routines to convert a node to ascii representation
*
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.113 2000/03/24 02:58:25 tgl Exp $
*
* 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 <ctype.h>
#include "postgres.h"
#include "access/heapam.h"
#include "access/htup.h"
1999-07-16 07:00:38 +02:00
#include "catalog/pg_type.h"
#include "fmgr.h"
1999-07-16 07:00:38 +02:00
#include "lib/stringinfo.h"
#include "nodes/execnodes.h"
1999-07-16 07:00:38 +02:00
#include "nodes/nodes.h"
#include "nodes/parsenodes.h"
#include "nodes/pg_list.h"
#include "nodes/plannodes.h"
#include "nodes/primnodes.h"
#include "nodes/relation.h"
1999-07-16 07:00:38 +02:00
#include "utils/datum.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
#include "../parse.h"
static void _outDatum(StringInfo str, Datum value, Oid type);
static void _outNode(StringInfo str, void *obj);
/*
* _outToken
* Convert an ordinary string (eg, an identifier) into a form that
* will be decoded back to a plain token by read.c's functions.
*
* If a null or empty string is given, it is encoded as "<>".
*/
static void
_outToken(StringInfo str, char *s)
{
if (s == NULL || *s == '\0')
{
appendStringInfo(str, "<>");
return;
}
/*
* Look for characters or patterns that are treated specially by
* read.c (either in lsptok() or in nodeRead()), and therefore need
* a protective backslash.
*/
/* These characters only need to be quoted at the start of the string */
if (*s == '<' ||
*s == '\"' ||
*s == '@' ||
isdigit(*s) ||
(*s == '-' && isdigit(s[1])))
appendStringInfoChar(str, '\\');
while (*s)
{
/* These chars must be backslashed anywhere in the string */
if (*s == ' ' || *s == '\n' || *s == '\t' ||
*s == '(' || *s == ')' || *s == '{' || *s == '}' ||
*s == '\\')
appendStringInfoChar(str, '\\');
appendStringInfoChar(str, *s++);
}
}
/*
* _outIntList -
* converts a List of integers
*/
static void
_outIntList(StringInfo str, List *list)
{
1999-05-25 18:15:34 +02:00
List *l;
appendStringInfoChar(str, '(');
foreach(l, list)
appendStringInfo(str, " %d", lfirsti(l));
appendStringInfoChar(str, ')');
}
static void
_outCreateStmt(StringInfo str, CreateStmt *node)
{
appendStringInfo(str, " CREATE :relname ");
_outToken(str, node->relname);
appendStringInfo(str, " :istemp %s ",
1999-05-25 18:15:34 +02:00
node->istemp ? "true" : "false");
appendStringInfo(str, " :columns ");
_outNode(str, node->tableElts);
1998-12-20 08:13:36 +01:00
appendStringInfo(str, " :inhRelnames ");
_outNode(str, node->inhRelnames);
1998-12-20 08:13:36 +01:00
appendStringInfo(str, " :constraints ");
_outNode(str, node->constraints);
}
static void
_outIndexStmt(StringInfo str, IndexStmt *node)
{
appendStringInfo(str, " INDEX :idxname ");
_outToken(str, node->idxname);
appendStringInfo(str, " :relname ");
_outToken(str, node->relname);
appendStringInfo(str, " :accessMethod ");
_outToken(str, node->accessMethod);
appendStringInfo(str, " :indexParams ");
_outNode(str, node->indexParams);
1998-12-20 08:13:36 +01:00
appendStringInfo(str, " :withClause ");
_outNode(str, node->withClause);
1998-12-20 08:13:36 +01:00
appendStringInfo(str, " :whereClause ");
_outNode(str, node->whereClause);
1998-12-20 08:13:36 +01:00
appendStringInfo(str, " :rangetable ");
_outNode(str, node->rangetable);
appendStringInfo(str, " :lossy %s :unique %s ",
1999-05-25 18:15:34 +02:00
node->lossy ? "true" : "false",
node->unique ? "true" : "false");
}
static void
_outSelectStmt(StringInfo str, SelectStmt *node)
{
appendStringInfo(str, "SELECT :where ");
_outNode(str, node->whereClause);
}
static void
_outFuncCall(StringInfo str, FuncCall *node)
{
appendStringInfo(str, "FUNCTION ");
_outToken(str, node->funcname);
appendStringInfo(str, " :args ");
_outNode(str, node->args);
appendStringInfo(str, " :agg_star %s :agg_distinct %s ",
node->agg_star ? "true" : "false",
node->agg_distinct ? "true" : "false");
}
static void
_outColumnDef(StringInfo str, ColumnDef *node)
{
appendStringInfo(str, " COLUMNDEF :colname ");
_outToken(str, node->colname);
appendStringInfo(str, " :typename ");
_outNode(str, node->typename);
appendStringInfo(str, " :is_not_null %s :is_sequence %s :raw_default ",
1999-05-25 18:15:34 +02:00
node->is_not_null ? "true" : "false",
node->is_sequence ? "true" : "false");
_outNode(str, node->raw_default);
appendStringInfo(str, " :cooked_default ");
_outToken(str, node->cooked_default);
appendStringInfo(str, " :constraints ");
_outNode(str, node->constraints);
}
static void
_outTypeName(StringInfo str, TypeName *node)
{
appendStringInfo(str, " TYPENAME :name ");
_outToken(str, node->name);
appendStringInfo(str, " :timezone %s :setof %s typmod %d :arrayBounds ",
1999-05-25 18:15:34 +02:00
node->timezone ? "true" : "false",
node->setof ? "true" : "false",
node->typmod);
_outNode(str, node->arrayBounds);
}
static void
_outTypeCast(StringInfo str, TypeCast *node)
{
appendStringInfo(str, " TYPECAST :arg ");
_outNode(str, node->arg);
appendStringInfo(str, " :typename ");
_outNode(str, node->typename);
}
static void
_outIndexElem(StringInfo str, IndexElem *node)
{
appendStringInfo(str, " INDEXELEM :name ");
_outToken(str, node->name);
appendStringInfo(str, " :args ");
_outNode(str, node->args);
appendStringInfo(str, " :class ");
_outToken(str, node->class);
appendStringInfo(str, " :typename ");
1998-08-26 07:22:58 +02:00
_outNode(str, node->typename);
}
static void
_outQuery(StringInfo str, Query *node)
{
1999-01-21 17:08:55 +01:00
appendStringInfo(str, " QUERY :command %d ", node->commandType);
if (node->utilityStmt)
{
switch (nodeTag(node->utilityStmt))
{
case T_CreateStmt:
appendStringInfo(str, " :create ");
_outToken(str, ((CreateStmt *) (node->utilityStmt))->relname);
appendStringInfo(str, " ");
_outNode(str, node->utilityStmt);
break;
case T_IndexStmt:
appendStringInfo(str, " :index ");
_outToken(str, ((IndexStmt *) (node->utilityStmt))->idxname);
appendStringInfo(str, " on ");
_outToken(str, ((IndexStmt *) (node->utilityStmt))->relname);
appendStringInfo(str, " ");
_outNode(str, node->utilityStmt);
break;
case T_NotifyStmt:
appendStringInfo(str, " :utility ");
_outToken(str, ((NotifyStmt *) (node->utilityStmt))->relname);
break;
default:
appendStringInfo(str, " :utility ? ");
}
}
else
appendStringInfo(str, " :utility <>");
appendStringInfo(str, " :resultRelation %u :into ",
node->resultRelation);
_outToken(str, node->into);
1999-05-25 18:15:34 +02:00
appendStringInfo(str,
" :isPortal %s :isBinary %s :isTemp %s :unionall %s :distinctClause ",
1999-05-25 18:15:34 +02:00
node->isPortal ? "true" : "false",
node->isBinary ? "true" : "false",
node->isTemp ? "true" : "false",
node->unionall ? "true" : "false");
_outNode(str, node->distinctClause);
appendStringInfo(str, " :sortClause ");
_outNode(str, node->sortClause);
appendStringInfo(str, " :rtable ");
_outNode(str, node->rtable);
appendStringInfo(str, " :targetlist ");
_outNode(str, node->targetList);
appendStringInfo(str, " :qual ");
_outNode(str, node->qual);
appendStringInfo(str, " :groupClause ");
_outNode(str, node->groupClause);
appendStringInfo(str, " :havingQual ");
_outNode(str, node->havingQual);
appendStringInfo(str, " :hasAggs %s :hasSubLinks %s :unionClause ",
1999-05-25 18:15:34 +02:00
node->hasAggs ? "true" : "false",
node->hasSubLinks ? "true" : "false");
_outNode(str, node->unionClause);
Hi! INTERSECT and EXCEPT is available for postgresql-v6.4! The patch against v6.4 is included at the end of the current text (in uuencoded form!) I also included the text of my Master's Thesis. (a postscript version). I hope that you find something of it useful and would be happy if parts of it find their way into the PostgreSQL documentation project (If so, tell me, then I send the sources of the document!) The contents of the document are: -) The first chapter might be of less interest as it gives only an overview on SQL. -) The second chapter gives a description on much of PostgreSQL's features (like user defined types etc. and how to use these features) -) The third chapter starts with an overview of PostgreSQL's internal structure with focus on the stages a query has to pass (i.e. parser, planner/optimizer, executor). Then a detailed description of the implementation of the Having clause and the Intersect/Except logic is given. Originally I worked on v6.3.2 but never found time enough to prepare and post a patch. Now I applied the changes to v6.4 to get Intersect and Except working with the new version. Chapter 3 of my documentation deals with the changes against v6.3.2, so keep that in mind when comparing the parts of the code printed there with the patched sources of v6.4. Here are some remarks on the patch. There are some things that have still to be done but at the moment I don't have time to do them myself. (I'm doing my military service at the moment) Sorry for that :-( -) I used a rewrite technique for the implementation of the Except/Intersect logic which rewrites the query to a semantically equivalent query before it is handed to the rewrite system (for views, rules etc.), planner, executor etc. -) In v6.3.2 the types of the attributes of two select statements connected by the UNION keyword had to match 100%. In v6.4 the types only need to be familiar (i.e. int and float can be mixed). Since this feature did not exist when I worked on Intersect/Except it does not work correctly for Except/Intersect queries WHEN USED IN COMBINATION WITH UNIONS! (i.e. sometimes the wrong type is used for the resulting table. This is because until now the types of the attributes of the first select statement have been used for the resulting table. When Intersects and/or Excepts are used in combination with Unions it might happen, that the first select statement of the original query appears at another position in the query which will be executed. The reason for this is the technique used for the implementation of Except/Intersect which does a query rewrite!) NOTE: It is NOT broken for pure UNION queries and pure INTERSECT/EXCEPT queries!!! -) I had to add the field intersect_clause to some data structures but did not find time to implement printfuncs for the new field. This does NOT break the debug modes but when an Except/Intersect is used the query debug output will be the already rewritten query. -) Massive changes to the grammar rules for SELECT and INSERT statements have been necessary (see comments in gram.y and documentation for deatails) in order to be able to use mixed queries like (SELECT ... UNION (SELECT ... EXCEPT SELECT)) INTERSECT SELECT...; -) When using UNION/EXCEPT/INTERSECT you will get: NOTICE: equal: "Don't know if nodes of type xxx are equal". I did not have time to add comparsion support for all the needed nodes, but the default behaviour of the function equal met my requirements. I did not dare to supress this message! That's the reason why the regression test for union will fail: These messages are also included in the union.out file! -) Somebody of you changed the union_planner() function for v6.4 (I copied the targetlist to new_tlist and that was removed and replaced by a cleanup of the original targetlist). These chnages violated some having queries executed against views so I changed it back again. I did not have time to examine the differences between the two versions but now it works :-) If you want to find out, try the file queries/view_having.sql on both versions and compare the results . Two queries won't produce a correct result with your version. regards Stefan
1999-01-18 01:10:17 +01:00
appendStringInfo(str, " :intersectClause ");
_outNode(str, node->intersectClause);
1998-10-22 15:52:24 +02:00
appendStringInfo(str, " :limitOffset ");
_outNode(str, node->limitOffset);
1998-10-22 15:52:24 +02:00
appendStringInfo(str, " :limitCount ");
_outNode(str, node->limitCount);
1999-01-21 17:08:55 +01:00
appendStringInfo(str, " :rowMark ");
_outNode(str, node->rowMark);
}
static void
_outSortClause(StringInfo str, SortClause *node)
{
appendStringInfo(str, " SORTCLAUSE :tleSortGroupRef %d :sortop %u ",
node->tleSortGroupRef, node->sortop);
}
static void
_outGroupClause(StringInfo str, GroupClause *node)
{
appendStringInfo(str, " GROUPCLAUSE :tleSortGroupRef %d :sortop %u ",
node->tleSortGroupRef, node->sortop);
}
/*
* print the basic stuff of all nodes that inherit from Plan
*/
static void
_outPlanInfo(StringInfo str, Plan *node)
{
1999-05-25 18:15:34 +02:00
appendStringInfo(str,
":startup_cost %.2f :total_cost %.2f :rows %.0f :width %d :state %s :qptargetlist ",
node->startup_cost,
node->total_cost,
node->plan_rows,
1999-05-25 18:15:34 +02:00
node->plan_width,
node->state ? "not-NULL" : "<>");
_outNode(str, node->targetlist);
appendStringInfo(str, " :qpqual ");
_outNode(str, node->qual);
appendStringInfo(str, " :lefttree ");
_outNode(str, node->lefttree);
appendStringInfo(str, " :righttree ");
_outNode(str, node->righttree);
appendStringInfo(str, " :extprm ");
_outIntList(str, node->extParam);
appendStringInfo(str, " :locprm ");
_outIntList(str, node->locParam);
appendStringInfo(str, " :initplan ");
_outNode(str, node->initPlan);
1998-12-15 03:32:57 +01:00
appendStringInfo(str, " :nprm %d ", node->nParamExec);
}
/*
* Stuff from plannodes.h
*/
static void
_outPlan(StringInfo str, Plan *node)
{
appendStringInfo(str, " PLAN ");
_outPlanInfo(str, (Plan *) node);
}
static void
_outResult(StringInfo str, Result *node)
{
appendStringInfo(str, " RESULT ");
_outPlanInfo(str, (Plan *) node);
appendStringInfo(str, " :resconstantqual ");
_outNode(str, node->resconstantqual);
}
/*
* Append is a subclass of Plan.
*/
static void
1997-09-08 22:59:27 +02:00
_outAppend(StringInfo str, Append *node)
{
appendStringInfo(str, " APPEND ");
_outPlanInfo(str, (Plan *) node);
appendStringInfo(str, " :appendplans ");
_outNode(str, node->appendplans);
appendStringInfo(str, " :unionrtables ");
_outNode(str, node->unionrtables);
1999-05-25 18:15:34 +02:00
appendStringInfo(str,
" :inheritrelid %u :inheritrtable ",
node->inheritrelid);
_outNode(str, node->inheritrtable);
}
/*
* Join is a subclass of Plan
*/
static void
_outJoin(StringInfo str, Join *node)
{
appendStringInfo(str, " JOIN ");
_outPlanInfo(str, (Plan *) node);
}
/*
* NestLoop is a subclass of Join
*/
static void
_outNestLoop(StringInfo str, NestLoop *node)
{
appendStringInfo(str, " NESTLOOP ");
_outPlanInfo(str, (Plan *) node);
}
/*
* MergeJoin is a subclass of Join
*/
static void
_outMergeJoin(StringInfo str, MergeJoin *node)
{
appendStringInfo(str, " MERGEJOIN ");
_outPlanInfo(str, (Plan *) node);
appendStringInfo(str, " :mergeclauses ");
_outNode(str, node->mergeclauses);
}
/*
* HashJoin is a subclass of Join.
*/
static void
_outHashJoin(StringInfo str, HashJoin *node)
{
appendStringInfo(str, " HASHJOIN ");
_outPlanInfo(str, (Plan *) node);
appendStringInfo(str, " :hashclauses ");
_outNode(str, node->hashclauses);
1999-05-25 18:15:34 +02:00
appendStringInfo(str,
" :hashjoinop %u ",
node->hashjoinop);
1999-05-25 18:15:34 +02:00
appendStringInfo(str,
" :hashdone %d ",
node->hashdone);
}
static void
_outSubPlan(StringInfo str, SubPlan *node)
{
appendStringInfo(str, " SUBPLAN :plan ");
_outNode(str, node->plan);
appendStringInfo(str, " :planid %u :rtable ", node->plan_id);
_outNode(str, node->rtable);
appendStringInfo(str, " :setprm ");
_outIntList(str, node->setParam);
appendStringInfo(str, " :parprm ");
_outIntList(str, node->parParam);
appendStringInfo(str, " :slink ");
_outNode(str, node->sublink);
}
/*
* Scan is a subclass of Node
*/
static void
_outScan(StringInfo str, Scan *node)
{
appendStringInfo(str, " SCAN ");
_outPlanInfo(str, (Plan *) node);
appendStringInfo(str, " :scanrelid %u ", node->scanrelid);
}
/*
* SeqScan is a subclass of Scan
*/
static void
_outSeqScan(StringInfo str, SeqScan *node)
{
appendStringInfo(str, " SEQSCAN ");
_outPlanInfo(str, (Plan *) node);
appendStringInfo(str, " :scanrelid %u ", node->scanrelid);
}
/*
* IndexScan is a subclass of Scan
*/
static void
_outIndexScan(StringInfo str, IndexScan *node)
{
appendStringInfo(str, " INDEXSCAN ");
_outPlanInfo(str, (Plan *) node);
appendStringInfo(str, " :scanrelid %u :indxid ", node->scan.scanrelid);
_outIntList(str, node->indxid);
appendStringInfo(str, " :indxqual ");
_outNode(str, node->indxqual);
appendStringInfo(str, " :indxqualorig ");
_outNode(str, node->indxqualorig);
appendStringInfo(str, " :indxorderdir %d ", node->indxorderdir);
}
/*
* TidScan is a subclass of Scan
*/
static void
_outTidScan(StringInfo str, TidScan *node)
{
appendStringInfo(str, " TIDSCAN ");
_outPlanInfo(str, (Plan *) node);
appendStringInfo(str, " :scanrelid %u ", node->scan.scanrelid);
appendStringInfo(str, " :needrescan %d ", node->needRescan);
appendStringInfo(str, " :tideval ");
_outNode(str, node->tideval);
}
/*
* Noname is a subclass of Plan
*/
static void
1999-05-26 00:43:53 +02:00
_outNoname(StringInfo str, Noname *node)
{
appendStringInfo(str, " NONAME ");
_outPlanInfo(str, (Plan *) node);
1999-05-25 18:15:34 +02:00
appendStringInfo(str, " :nonameid %u :keycount %d ",
node->nonameid,
node->keycount);
}
/*
* Material is a subclass of Noname
*/
static void
_outMaterial(StringInfo str, Material *node)
{
appendStringInfo(str, " MATERIAL ");
_outPlanInfo(str, (Plan *) node);
appendStringInfo(str, " :nonameid %u :keycount %d ",
node->nonameid,
node->keycount);
}
/*
* Sort is a subclass of Noname
*/
static void
_outSort(StringInfo str, Sort *node)
{
appendStringInfo(str, " SORT ");
_outPlanInfo(str, (Plan *) node);
appendStringInfo(str, " :nonameid %u :keycount %d ",
1999-05-25 18:15:34 +02:00
node->nonameid,
node->keycount);
}
static void
1997-09-08 22:59:27 +02:00
_outAgg(StringInfo str, Agg *node)
{
appendStringInfo(str, " AGG ");
_outPlanInfo(str, (Plan *) node);
}
static void
_outGroup(StringInfo str, Group *node)
{
appendStringInfo(str, " GRP ");
_outPlanInfo(str, (Plan *) node);
/* the actual Group fields */
1998-12-15 03:32:57 +01:00
appendStringInfo(str, " :numCols %d :tuplePerGroup %s ",
1999-05-25 18:15:34 +02:00
node->numCols,
node->tuplePerGroup ? "true" : "false");
}
/*
* For some reason, unique is a subclass of Noname.
*/
static void
_outUnique(StringInfo str, Unique *node)
{
appendStringInfo(str, " UNIQUE ");
_outPlanInfo(str, (Plan *) node);
appendStringInfo(str, " :nonameid %u :keycount %d :numCols %d ",
1999-05-25 18:15:34 +02:00
node->nonameid,
node->keycount,
node->numCols);
}
/*
* Hash is a subclass of Noname
*/
static void
_outHash(StringInfo str, Hash *node)
{
appendStringInfo(str, " HASH ");
_outPlanInfo(str, (Plan *) node);
appendStringInfo(str, " :hashkey ");
_outNode(str, node->hashkey);
}
/*****************************************************************************
*
* Stuff from primnodes.h.
*
*****************************************************************************/
/*
* Resdom is a subclass of Node
*/
static void
_outResdom(StringInfo str, Resdom *node)
{
appendStringInfo(str,
" RESDOM :resno %d :restype %u :restypmod %d :resname ",
1999-05-25 18:15:34 +02:00
node->resno,
node->restype,
node->restypmod);
_outToken(str, node->resname);
appendStringInfo(str, " :reskey %d :reskeyop %u :ressortgroupref %d :resjunk %s ",
1999-05-25 18:15:34 +02:00
node->reskey,
node->reskeyop,
node->ressortgroupref,
1999-05-25 18:15:34 +02:00
node->resjunk ? "true" : "false");
}
static void
_outFjoin(StringInfo str, Fjoin *node)
{
int i;
appendStringInfo(str, " FJOIN :initialized %s :nNodes %d ",
1999-05-25 18:15:34 +02:00
node->fj_initialized ? "true" : "false",
node->fj_nNodes);
appendStringInfo(str, " :innerNode ");
_outNode(str, node->fj_innerNode);
1999-05-25 18:15:34 +02:00
appendStringInfo(str, " :results @ 0x%x :alwaysdone",
(int) node->fj_results);
for (i = 0; i < node->fj_nNodes; i++)
appendStringInfo(str, (node->fj_alwaysDone[i]) ? "true" : "false");
}
/*
* Expr is a subclass of Node
*/
static void
_outExpr(StringInfo str, Expr *node)
{
char *opstr = NULL;
appendStringInfo(str, " EXPR :typeOid %u ",
1999-05-25 18:15:34 +02:00
node->typeOid);
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;
case SUBPLAN_EXPR:
opstr = "subp";
break;
}
appendStringInfo(str, " :opType ");
_outToken(str, opstr);
appendStringInfo(str, " :oper ");
_outNode(str, node->oper);
appendStringInfo(str, " :args ");
_outNode(str, node->args);
}
/*
* Var is a subclass of Expr
*/
static void
_outVar(StringInfo str, Var *node)
{
1999-05-25 18:15:34 +02:00
appendStringInfo(str,
" VAR :varno %d :varattno %d :vartype %u :vartypmod %d ",
node->varno,
node->varattno,
node->vartype,
node->vartypmod);
1999-05-25 18:15:34 +02:00
appendStringInfo(str, " :varlevelsup %u :varnoold %d :varoattno %d",
node->varlevelsup,
node->varnoold,
node->varoattno);
}
/*
* Const is a subclass of Expr
*/
static void
_outConst(StringInfo str, Const *node)
{
1999-05-25 18:15:34 +02:00
appendStringInfo(str,
" CONST :consttype %u :constlen %d :constisnull %s :constvalue ",
node->consttype,
node->constlen,
node->constisnull ? "true" : "false");
if (node->constisnull)
1998-01-07 16:32:47 +01:00
appendStringInfo(str, "<>");
else
_outDatum(str, node->constvalue, node->consttype);
1999-05-25 18:15:34 +02:00
appendStringInfo(str, " :constbyval %s ",
node->constbyval ? "true" : "false");
}
/*
1999-01-24 01:28:37 +01:00
* Aggref
*/
static void
1999-05-26 00:43:53 +02:00
_outAggref(StringInfo str, Aggref *node)
{
appendStringInfo(str, " AGGREG :aggname ");
_outToken(str, node->aggname);
appendStringInfo(str, " :basetype %u :aggtype %u :target ",
1999-05-25 18:15:34 +02:00
node->basetype,
node->aggtype);
_outNode(str, node->target);
appendStringInfo(str, " :usenulls %s :aggstar %s :aggdistinct %s ",
node->usenulls ? "true" : "false",
node->aggstar ? "true" : "false",
node->aggdistinct ? "true" : "false");
/* aggno is not dumped */
}
/*
* SubLink
*/
static void
_outSubLink(StringInfo str, SubLink *node)
{
1999-05-25 18:15:34 +02:00
appendStringInfo(str,
" SUBLINK :subLinkType %d :useor %s :lefthand ",
node->subLinkType,
node->useor ? "true" : "false");
_outNode(str, node->lefthand);
appendStringInfo(str, " :oper ");
1998-01-20 06:05:08 +01:00
_outNode(str, node->oper);
appendStringInfo(str, " :subselect ");
_outNode(str, node->subselect);
}
/*
* RelabelType
*/
static void
_outRelabelType(StringInfo str, RelabelType *node)
{
appendStringInfo(str, " RELABELTYPE :arg ");
_outNode(str, node->arg);
appendStringInfo(str, " :resulttype %u :resulttypmod %d ",
node->resulttype, node->resulttypmod);
}
/*
* Array is a subclass of Expr
*/
static void
1997-09-08 22:59:27 +02:00
_outArray(StringInfo str, Array *node)
{
int i;
1999-05-25 18:15:34 +02:00
appendStringInfo(str,
" ARRAY :arrayelemtype %u :arrayelemlength %d :arrayelembyval %c ",
node->arrayelemtype,
node->arrayelemlength,
node->arrayelembyval ? 't' : 'f');
1998-12-20 08:13:36 +01:00
appendStringInfo(str, " :arrayndim %d :arraylow ", node->arrayndim);
for (i = 0; i < node->arrayndim; i++)
appendStringInfo(str, " %d ", node->arraylow.indx[i]);
appendStringInfo(str, " :arrayhigh ");
for (i = 0; i < node->arrayndim; i++)
appendStringInfo(str, " %d ", node->arrayhigh.indx[i]);
appendStringInfo(str, " :arraylen %d ", node->arraylen);
}
/*
* ArrayRef is a subclass of Expr
*/
static void
1997-09-08 22:59:27 +02:00
_outArrayRef(StringInfo str, ArrayRef *node)
{
1999-05-25 18:15:34 +02:00
appendStringInfo(str,
1999-07-18 21:02:49 +02:00
" ARRAYREF :refelemtype %u :refattrlength %d :refelemlength %d ",
1999-05-25 18:15:34 +02:00
node->refelemtype,
node->refattrlength,
node->refelemlength);
1999-05-25 18:15:34 +02:00
appendStringInfo(str, " :refelembyval %c :refupperindex ",
node->refelembyval ? 't' : 'f');
_outNode(str, node->refupperindexpr);
appendStringInfo(str, " :reflowerindex ");
_outNode(str, node->reflowerindexpr);
appendStringInfo(str, " :refexpr ");
_outNode(str, node->refexpr);
appendStringInfo(str, " :refassgnexpr ");
_outNode(str, node->refassgnexpr);
}
/*
* Func is a subclass of Expr
*/
static void
_outFunc(StringInfo str, Func *node)
{
1999-05-25 18:15:34 +02:00
appendStringInfo(str,
" FUNC :funcid %u :functype %u :funcisindex %s :funcsize %d ",
node->funcid,
node->functype,
node->funcisindex ? "true" : "false",
node->funcsize);
appendStringInfo(str, " :func_fcache @ 0x%x :func_tlist ",
1999-05-25 18:15:34 +02:00
(int) node->func_fcache);
_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)
{
1999-05-25 18:15:34 +02:00
appendStringInfo(str,
" OPER :opno %u :opid %u :opresulttype %u ",
node->opno,
node->opid,
node->opresulttype);
}
/*
* Param is a subclass of Expr
*/
static void
_outParam(StringInfo str, Param *node)
{
appendStringInfo(str, " PARAM :paramkind %d :paramid %d :paramname ",
1999-05-25 18:15:34 +02:00
node->paramkind,
node->paramid);
_outToken(str, node->paramname);
appendStringInfo(str, " :paramtype %u :param_tlist ",
1999-05-25 18:15:34 +02:00
node->paramtype);
_outNode(str, node->param_tlist);
}
/*
* Stuff from execnodes.h
*/
/*
* EState is a subclass of Node.
*/
static void
_outEState(StringInfo str, EState *node)
{
1999-05-25 18:15:34 +02:00
appendStringInfo(str,
" ESTATE :direction %d :range_table ",
node->es_direction);
_outNode(str, node->es_range_table);
appendStringInfo(str, " :result_relation_info @ 0x%x ",
1999-05-25 18:15:34 +02:00
(int) (node->es_result_relation_info));
}
/*
* Stuff from relation.h
*/
static void
1999-05-26 00:43:53 +02:00
_outRelOptInfo(StringInfo str, RelOptInfo *node)
{
appendStringInfo(str, " RELOPTINFO :relids ");
_outIntList(str, node->relids);
1999-05-25 18:15:34 +02:00
appendStringInfo(str,
" :rows %.0f :width %d :indexed %s :pages %ld :tuples %.0f :targetlist ",
node->rows,
node->width,
1999-05-25 18:15:34 +02:00
node->indexed ? "true" : "false",
node->pages,
node->tuples);
_outNode(str, node->targetlist);
appendStringInfo(str, " :pathlist ");
_outNode(str, node->pathlist);
appendStringInfo(str, " :cheapest_startup_path ");
_outNode(str, node->cheapest_startup_path);
appendStringInfo(str, " :cheapest_total_path ");
_outNode(str, node->cheapest_total_path);
1999-05-25 18:15:34 +02:00
appendStringInfo(str,
" :pruneable %s :baserestrictinfo ",
1999-05-25 18:15:34 +02:00
node->pruneable ? "true" : "false");
_outNode(str, node->baserestrictinfo);
appendStringInfo(str, " :joininfo ");
_outNode(str, node->joininfo);
appendStringInfo(str, " :innerjoin ");
_outNode(str, node->innerjoin);
}
static void
_outIndexOptInfo(StringInfo str, IndexOptInfo *node)
{
appendStringInfo(str, " INDEXOPTINFO :indexoid %u :pages %ld :tuples %g ",
node->indexoid,
node->pages,
node->tuples);
}
/*
* TargetEntry is a subclass of Node.
*/
static void
_outTargetEntry(StringInfo str, TargetEntry *node)
{
appendStringInfo(str, " TARGETENTRY :resdom ");
_outNode(str, node->resdom);
appendStringInfo(str, " :expr ");
_outNode(str, node->expr);
}
static void
_outRangeTblEntry(StringInfo str, RangeTblEntry *node)
{
appendStringInfo(str, " RTE :relname ");
_outToken(str, node->relname);
appendStringInfo(str, " :ref ");
_outNode(str, node->ref);
1999-05-25 18:15:34 +02:00
appendStringInfo(str,
" :relid %u :inh %s :inFromCl %s :inJoinSet %s :skipAcl %s",
1999-05-25 18:15:34 +02:00
node->relid,
node->inh ? "true" : "false",
node->inFromCl ? "true" : "false",
node->inJoinSet ? "true" : "false",
1999-05-25 18:15:34 +02:00
node->skipAcl ? "true" : "false");
}
1999-01-21 17:08:55 +01:00
static void
1999-05-26 00:43:53 +02:00
_outRowMark(StringInfo str, RowMark *node)
1999-01-21 17:08:55 +01:00
{
appendStringInfo(str, " ROWMARK :rti %u :info %u", node->rti, node->info);
}
/*
* Path is a subclass of Node.
*/
static void
_outPath(StringInfo str, Path *node)
{
appendStringInfo(str,
" PATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
1999-05-25 18:15:34 +02:00
node->pathtype,
node->startup_cost,
node->total_cost);
_outNode(str, node->pathkeys);
}
/*
* IndexPath is a subclass of Path.
*/
static void
_outIndexPath(StringInfo str, IndexPath *node)
{
1999-05-25 18:15:34 +02:00
appendStringInfo(str,
" INDEXPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
1999-05-25 18:15:34 +02:00
node->path.pathtype,
node->path.startup_cost,
node->path.total_cost);
_outNode(str, node->path.pathkeys);
appendStringInfo(str, " :indexid ");
_outIntList(str, node->indexid);
appendStringInfo(str, " :indexqual ");
_outNode(str, node->indexqual);
appendStringInfo(str, " :indexscandir %d :joinrelids ",
(int) node->indexscandir);
_outIntList(str, node->joinrelids);
appendStringInfo(str, " :rows %.2f ",
node->rows);
}
/*
* TidPath is a subclass of Path.
*/
static void
_outTidPath(StringInfo str, TidPath *node)
{
appendStringInfo(str,
" TIDPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
node->path.pathtype,
node->path.startup_cost,
node->path.total_cost);
_outNode(str, node->path.pathkeys);
appendStringInfo(str, " :tideval ");
_outNode(str, node->tideval);
appendStringInfo(str, " :un joined_relids ");
_outIntList(str, node->unjoined_relids);
}
/*
1999-02-12 07:43:53 +01:00
* NestPath is a subclass of Path
*/
static void
1999-05-26 00:43:53 +02:00
_outNestPath(StringInfo str, NestPath *node)
{
1999-05-25 18:15:34 +02:00
appendStringInfo(str,
" NESTPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
1999-05-25 18:15:34 +02:00
node->path.pathtype,
node->path.startup_cost,
node->path.total_cost);
_outNode(str, node->path.pathkeys);
appendStringInfo(str, " :outerjoinpath ");
_outNode(str, node->outerjoinpath);
appendStringInfo(str, " :innerjoinpath ");
_outNode(str, node->innerjoinpath);
appendStringInfo(str, " :joinrestrictinfo ");
_outNode(str, node->joinrestrictinfo);
}
/*
1999-02-12 07:43:53 +01:00
* MergePath is a subclass of NestPath.
*/
static void
_outMergePath(StringInfo str, MergePath *node)
{
1999-05-25 18:15:34 +02:00
appendStringInfo(str,
" MERGEPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
1999-05-25 18:15:34 +02:00
node->jpath.path.pathtype,
node->jpath.path.startup_cost,
node->jpath.path.total_cost);
_outNode(str, node->jpath.path.pathkeys);
appendStringInfo(str, " :outerjoinpath ");
_outNode(str, node->jpath.outerjoinpath);
appendStringInfo(str, " :innerjoinpath ");
_outNode(str, node->jpath.innerjoinpath);
appendStringInfo(str, " :joinrestrictinfo ");
_outNode(str, node->jpath.joinrestrictinfo);
appendStringInfo(str, " :path_mergeclauses ");
_outNode(str, node->path_mergeclauses);
appendStringInfo(str, " :outersortkeys ");
_outNode(str, node->outersortkeys);
appendStringInfo(str, " :innersortkeys ");
_outNode(str, node->innersortkeys);
}
/*
1999-02-12 07:43:53 +01:00
* HashPath is a subclass of NestPath.
*/
static void
_outHashPath(StringInfo str, HashPath *node)
{
1999-05-25 18:15:34 +02:00
appendStringInfo(str,
" HASHPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
1999-05-25 18:15:34 +02:00
node->jpath.path.pathtype,
node->jpath.path.startup_cost,
node->jpath.path.total_cost);
_outNode(str, node->jpath.path.pathkeys);
appendStringInfo(str, " :outerjoinpath ");
_outNode(str, node->jpath.outerjoinpath);
appendStringInfo(str, " :innerjoinpath ");
_outNode(str, node->jpath.innerjoinpath);
appendStringInfo(str, " :joinrestrictinfo ");
_outNode(str, node->jpath.joinrestrictinfo);
appendStringInfo(str, " :path_hashclauses ");
_outNode(str, node->path_hashclauses);
}
/*
* PathKeyItem is a subclass of Node.
*/
static void
_outPathKeyItem(StringInfo str, PathKeyItem *node)
{
appendStringInfo(str, " PATHKEYITEM :sortop %u :key ",
node->sortop);
_outNode(str, node->key);
}
/*
* RestrictInfo is a subclass of Node.
*/
static void
1999-05-26 00:43:53 +02:00
_outRestrictInfo(StringInfo str, RestrictInfo *node)
{
1999-02-05 20:59:31 +01:00
appendStringInfo(str, " RESTRICTINFO :clause ");
_outNode(str, node->clause);
appendStringInfo(str, " :subclauseindices ");
_outNode(str, node->subclauseindices);
appendStringInfo(str, " :mergejoinoperator %u ", node->mergejoinoperator);
appendStringInfo(str, " :left_sortop %u ", node->left_sortop);
appendStringInfo(str, " :right_sortop %u ", node->right_sortop);
1998-12-20 08:13:36 +01:00
appendStringInfo(str, " :hashjoinoperator %u ", node->hashjoinoperator);
}
/*
1998-09-01 05:29:17 +02:00
* JoinInfo is a subclass of Node.
*/
static void
1999-05-26 00:43:53 +02:00
_outJoinInfo(StringInfo str, JoinInfo *node)
{
1999-02-18 01:49:48 +01:00
appendStringInfo(str, " JINFO :unjoined_relids ");
_outIntList(str, node->unjoined_relids);
appendStringInfo(str, " :jinfo_restrictinfo ");
_outNode(str, node->jinfo_restrictinfo);
}
/*
* Print the value of a Datum given its type.
*/
static void
_outDatum(StringInfo str, Datum value, Oid type)
{
1999-05-25 18:15:34 +02:00
char *s;
Size length,
1999-05-25 18:15:34 +02:00
typeLength;
bool byValue;
int i;
/*
* 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);
1998-12-20 08:13:36 +01:00
appendStringInfo(str, " %d [ ", length);
for (i = 0; i < (int) sizeof(Datum); i++)
appendStringInfo(str, "%d ", (int) (s[i]));
1998-12-20 08:13:36 +01:00
appendStringInfo(str, "] ");
}
else
{ /* !byValue */
s = (char *) DatumGetPointer(value);
if (!PointerIsValid(s))
1998-12-20 08:13:36 +01:00
appendStringInfo(str, " 0 [ ] ");
else
{
1999-05-25 18:15:34 +02:00
/*
* 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);
1998-12-20 08:13:36 +01:00
appendStringInfo(str, " %d [ ", length);
for (i = 0; i < (int) length; i++)
appendStringInfo(str, "%d ", (int) (s[i]));
1998-12-20 08:13:36 +01:00
appendStringInfo(str, "] ");
}
}
}
static void
_outIter(StringInfo str, Iter *node)
{
1998-12-20 08:13:36 +01:00
appendStringInfo(str, " ITER :iterexpr ");
_outNode(str, node->iterexpr);
}
static void
_outStream(StringInfo str, Stream *node)
{
1999-05-25 18:15:34 +02:00
appendStringInfo(str,
" STREAM :pathptr @ 0x%x :cinfo @ 0x%x :clausetype %d :upstream @ 0x%x ",
(int) node->pathptr,
(int) node->cinfo,
(int) node->clausetype,
(int) node->upstream);
1999-05-25 18:15:34 +02:00
appendStringInfo(str,
" :downstream @ 0x%x :groupup %d :groupcost %f :groupsel %f ",
(int) node->downstream,
node->groupup,
node->groupcost,
node->groupsel);
}
static void
_outAExpr(StringInfo str, A_Expr *node)
{
appendStringInfo(str, "EXPR ");
switch (node->oper)
{
case AND:
appendStringInfo(str, "AND ");
break;
case OR:
appendStringInfo(str, "OR ");
break;
case NOT:
appendStringInfo(str, "NOT ");
break;
case ISNULL:
appendStringInfo(str, "ISNULL ");
break;
case NOTNULL:
appendStringInfo(str, "NOTNULL ");
break;
default:
_outToken(str, node->opname);
appendStringInfo(str, " ");
break;
}
_outNode(str, node->lexpr);
_outNode(str, node->rexpr);
}
static void
_outValue(StringInfo str, Value *value)
{
switch (value->type)
{
case T_Integer:
appendStringInfo(str, " %ld ", value->val.ival);
break;
case T_Float:
/* We assume the value is a valid numeric literal
* and so does not need quoting.
*/
appendStringInfo(str, " %s ", value->val.str);
break;
case T_String:
appendStringInfo(str, " \"");
_outToken(str, value->val.str);
appendStringInfo(str, "\" ");
break;
default:
elog(NOTICE, "_outValue: don't know how to print type %d ",
value->type);
break;
}
}
static void
_outIdent(StringInfo str, Ident *node)
{
appendStringInfo(str, " IDENT ");
_outToken(str, node->name);
}
static void
_outAttr(StringInfo str, Attr *node)
{
appendStringInfo(str, " ATTR :relname ");
_outToken(str, node->relname);
appendStringInfo(str, " :attrs ");
_outNode(str, node->attrs);
}
static void
_outAConst(StringInfo str, A_Const *node)
{
appendStringInfo(str, "CONST ");
_outValue(str, &(node->val));
appendStringInfo(str, " :typename ");
_outNode(str, node->typename);
}
1998-12-04 16:34:49 +01:00
static void
_outConstraint(StringInfo str, Constraint *node)
{
appendStringInfo(str, " ");
_outToken(str, node->name);
appendStringInfo(str, " :type ");
1998-12-04 16:34:49 +01:00
switch (node->contype)
{
case CONSTR_PRIMARY:
appendStringInfo(str, "PRIMARY KEY ");
1998-12-04 16:34:49 +01:00
_outNode(str, node->keys);
break;
case CONSTR_CHECK:
appendStringInfo(str, "CHECK :raw ");
_outNode(str, node->raw_expr);
appendStringInfo(str, " :cooked ");
_outToken(str, node->cooked_expr);
1998-12-04 16:34:49 +01:00
break;
case CONSTR_DEFAULT:
appendStringInfo(str, "DEFAULT :raw ");
_outNode(str, node->raw_expr);
appendStringInfo(str, " :cooked ");
_outToken(str, node->cooked_expr);
1998-12-04 16:34:49 +01:00
break;
case CONSTR_NOTNULL:
appendStringInfo(str, "NOT NULL");
1998-12-04 16:34:49 +01:00
break;
case CONSTR_UNIQUE:
appendStringInfo(str, "UNIQUE ");
1998-12-04 16:34:49 +01:00
_outNode(str, node->keys);
break;
default:
appendStringInfo(str, "<unrecognized_constraint>");
1998-12-04 16:34:49 +01:00
break;
}
}
static void
1999-05-26 00:43:53 +02:00
_outCaseExpr(StringInfo str, CaseExpr *node)
1998-12-04 16:34:49 +01:00
{
appendStringInfo(str, "CASE ");
1998-12-04 16:34:49 +01:00
_outNode(str, node->args);
1998-12-20 08:13:36 +01:00
appendStringInfo(str, " :default ");
1998-12-04 16:34:49 +01:00
_outNode(str, node->defresult);
}
static void
1999-05-26 00:43:53 +02:00
_outCaseWhen(StringInfo str, CaseWhen *node)
1998-12-04 16:34:49 +01:00
{
appendStringInfo(str, " WHEN ");
1998-12-04 16:34:49 +01:00
_outNode(str, node->expr);
1998-12-20 08:13:36 +01:00
appendStringInfo(str, " :then ");
1998-12-04 16:34:49 +01:00
_outNode(str, node->result);
}
/*
* _outNode -
* converts a Node into ascii string and append it to 'str'
*/
static void
_outNode(StringInfo str, void *obj)
{
if (obj == NULL)
{
1998-01-07 16:32:47 +01:00
appendStringInfo(str, "<>");
return;
}
if (IsA(obj, List))
{
List *l;
appendStringInfoChar(str, '(');
foreach(l, (List *) obj)
{
_outNode(str, lfirst(l));
if (lnext(l))
appendStringInfoChar(str, ' ');
}
appendStringInfoChar(str, ')');
}
else if (IsA_Value(obj))
{
/* nodeRead does not want to see { } around these! */
_outValue(str, obj);
}
else
{
appendStringInfoChar(str, '{');
switch (nodeTag(obj))
{
case T_CreateStmt:
_outCreateStmt(str, obj);
break;
case T_IndexStmt:
_outIndexStmt(str, obj);
break;
case T_ColumnDef:
_outColumnDef(str, obj);
break;
case T_TypeName:
_outTypeName(str, obj);
break;
case T_TypeCast:
_outTypeCast(str, obj);
break;
case T_IndexElem:
_outIndexElem(str, obj);
break;
case T_Query:
_outQuery(str, obj);
break;
case T_SortClause:
_outSortClause(str, obj);
break;
case T_GroupClause:
_outGroupClause(str, obj);
break;
case T_Plan:
_outPlan(str, obj);
break;
case T_Result:
_outResult(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_TidScan:
_outTidScan(str, obj);
break;
case T_Noname:
_outNoname(str, obj);
break;
case T_Material:
_outMaterial(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_SubPlan:
_outSubPlan(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;
1999-01-24 01:28:37 +01:00
case T_Aggref:
_outAggref(str, obj);
break;
case T_SubLink:
_outSubLink(str, obj);
break;
case T_RelabelType:
_outRelabelType(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;
1998-07-18 06:22:52 +02:00
case T_RelOptInfo:
1998-08-02 00:12:13 +02:00
_outRelOptInfo(str, obj);
break;
case T_IndexOptInfo:
_outIndexOptInfo(str, obj);
break;
case T_TargetEntry:
_outTargetEntry(str, obj);
break;
case T_RangeTblEntry:
_outRangeTblEntry(str, obj);
break;
1999-01-21 17:08:55 +01:00
case T_RowMark:
_outRowMark(str, obj);
break;
case T_Path:
_outPath(str, obj);
break;
case T_IndexPath:
_outIndexPath(str, obj);
break;
case T_TidPath:
_outTidPath(str, obj);
break;
1999-02-12 07:43:53 +01:00
case T_NestPath:
_outNestPath(str, obj);
break;
case T_MergePath:
_outMergePath(str, obj);
break;
case T_HashPath:
_outHashPath(str, obj);
break;
case T_PathKeyItem:
_outPathKeyItem(str, obj);
break;
case T_RestrictInfo:
_outRestrictInfo(str, obj);
break;
1998-09-01 05:29:17 +02:00
case T_JoinInfo:
_outJoinInfo(str, obj);
break;
case T_Iter:
_outIter(str, obj);
break;
case T_Stream:
_outStream(str, obj);
break;
case T_A_Expr:
_outAExpr(str, obj);
break;
case T_Ident:
_outIdent(str, obj);
break;
case T_A_Const:
_outAConst(str, obj);
break;
1998-12-04 16:34:49 +01:00
case T_Constraint:
_outConstraint(str, obj);
break;
case T_CaseExpr:
_outCaseExpr(str, obj);
break;
case T_CaseWhen:
_outCaseWhen(str, obj);
break;
case T_VariableSetStmt:
break;
case T_SelectStmt:
_outSelectStmt(str, obj);
break;
case T_FuncCall:
_outFuncCall(str, obj);
break;
case T_Attr:
_outAttr(str, obj);
break;
default:
1998-01-07 06:42:47 +01:00
elog(NOTICE, "_outNode: don't know how to print type %d ",
nodeTag(obj));
break;
}
appendStringInfoChar(str, '}');
}
}
/*
* nodeToString -
* returns the ascii representation of the Node as a palloc'd string
*/
char *
nodeToString(void *obj)
{
1999-05-25 18:15:34 +02:00
StringInfoData str;
/* see stringinfo.h for an explanation of this maneuver */
initStringInfo(&str);
_outNode(&str, obj);
return str.data;
}