4 * routines to convert a node to ascii representation
6 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
7 * Portions Copyright (c) 1994, Regents of the University of California
9 * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.129 2000/10/26 21:35:48 tgl Exp $
12 * Every (plan) node in POSTGRES has an associated "out" routine which
13 * knows how to create its ascii representation. These functions are
14 * useful for debugging as well as for storing plans in the system
15 * catalogs (eg. indexes). This is also the plan string sent out in
18 * These functions update the in/out argument of type StringInfo
19 * passed to them. This argument contains the string holding the ASCII
20 * representation plus some other information (string length, etc.)
27 #include "access/heapam.h"
28 #include "access/htup.h"
29 #include "catalog/pg_type.h"
31 #include "lib/stringinfo.h"
32 #include "nodes/execnodes.h"
33 #include "nodes/nodes.h"
34 #include "nodes/parsenodes.h"
35 #include "nodes/pg_list.h"
36 #include "nodes/plannodes.h"
37 #include "nodes/primnodes.h"
38 #include "nodes/relation.h"
39 #include "parser/parse.h"
40 #include "utils/datum.h"
41 #include "utils/lsyscache.h"
42 #include "utils/syscache.h"
45 static void _outDatum(StringInfo str, Datum value, Oid type);
46 static void _outNode(StringInfo str, void *obj);
50 * Convert an ordinary string (eg, an identifier) into a form that
51 * will be decoded back to a plain token by read.c's functions.
53 * If a null or empty string is given, it is encoded as "<>".
56 _outToken(StringInfo str, char *s)
58 if (s == NULL || *s == '\0')
60 appendStringInfo(str, "<>");
65 * Look for characters or patterns that are treated specially by
66 * read.c (either in lsptok() or in nodeRead()), and therefore need a
67 * protective backslash.
69 /* These characters only need to be quoted at the start of the string */
74 (*s == '-' && isdigit((int) s[1])))
75 appendStringInfoChar(str, '\\');
78 /* These chars must be backslashed anywhere in the string */
79 if (*s == ' ' || *s == '\n' || *s == '\t' ||
80 *s == '(' || *s == ')' || *s == '{' || *s == '}' ||
82 appendStringInfoChar(str, '\\');
83 appendStringInfoChar(str, *s++);
89 * converts a List of integers
92 _outIntList(StringInfo str, List *list)
96 appendStringInfoChar(str, '(');
98 appendStringInfo(str, " %d", lfirsti(l));
99 appendStringInfoChar(str, ')');
103 _outCreateStmt(StringInfo str, CreateStmt *node)
105 appendStringInfo(str, " CREATE :relname ");
106 _outToken(str, node->relname);
108 appendStringInfo(str, " :istemp %s ",
109 node->istemp ? "true" : "false");
111 appendStringInfo(str, " :columns ");
112 _outNode(str, node->tableElts);
114 appendStringInfo(str, " :inhRelnames ");
115 _outNode(str, node->inhRelnames);
117 appendStringInfo(str, " :constraints ");
118 _outNode(str, node->constraints);
122 _outIndexStmt(StringInfo str, IndexStmt *node)
124 appendStringInfo(str, " INDEX :idxname ");
125 _outToken(str, node->idxname);
126 appendStringInfo(str, " :relname ");
127 _outToken(str, node->relname);
128 appendStringInfo(str, " :accessMethod ");
129 _outToken(str, node->accessMethod);
130 appendStringInfo(str, " :indexParams ");
131 _outNode(str, node->indexParams);
133 appendStringInfo(str, " :withClause ");
134 _outNode(str, node->withClause);
136 appendStringInfo(str, " :whereClause ");
137 _outNode(str, node->whereClause);
139 appendStringInfo(str, " :rangetable ");
140 _outNode(str, node->rangetable);
142 appendStringInfo(str, " :unique %s :primary %s ",
143 node->unique ? "true" : "false",
144 node->primary ? "true" : "false");
148 _outSelectStmt(StringInfo str, SelectStmt *node)
150 /* XXX this is pretty durn incomplete */
151 appendStringInfo(str, "SELECT :where ");
152 _outNode(str, node->whereClause);
156 _outFuncCall(StringInfo str, FuncCall *node)
158 appendStringInfo(str, "FUNCTION ");
159 _outToken(str, node->funcname);
160 appendStringInfo(str, " :args ");
161 _outNode(str, node->args);
162 appendStringInfo(str, " :agg_star %s :agg_distinct %s ",
163 node->agg_star ? "true" : "false",
164 node->agg_distinct ? "true" : "false");
168 _outColumnDef(StringInfo str, ColumnDef *node)
170 appendStringInfo(str, " COLUMNDEF :colname ");
171 _outToken(str, node->colname);
172 appendStringInfo(str, " :typename ");
173 _outNode(str, node->typename);
174 appendStringInfo(str, " :is_not_null %s :is_sequence %s :raw_default ",
175 node->is_not_null ? "true" : "false",
176 node->is_sequence ? "true" : "false");
177 _outNode(str, node->raw_default);
178 appendStringInfo(str, " :cooked_default ");
179 _outToken(str, node->cooked_default);
180 appendStringInfo(str, " :constraints ");
181 _outNode(str, node->constraints);
185 _outTypeName(StringInfo str, TypeName *node)
187 appendStringInfo(str, " TYPENAME :name ");
188 _outToken(str, node->name);
189 appendStringInfo(str, " :timezone %s :setof %s typmod %d :arrayBounds ",
190 node->timezone ? "true" : "false",
191 node->setof ? "true" : "false",
193 _outNode(str, node->arrayBounds);
197 _outTypeCast(StringInfo str, TypeCast *node)
199 appendStringInfo(str, " TYPECAST :arg ");
200 _outNode(str, node->arg);
201 appendStringInfo(str, " :typename ");
202 _outNode(str, node->typename);
206 _outIndexElem(StringInfo str, IndexElem *node)
208 appendStringInfo(str, " INDEXELEM :name ");
209 _outToken(str, node->name);
210 appendStringInfo(str, " :args ");
211 _outNode(str, node->args);
212 appendStringInfo(str, " :class ");
213 _outToken(str, node->class);
217 _outQuery(StringInfo str, Query *node)
220 appendStringInfo(str, " QUERY :command %d ", node->commandType);
222 if (node->utilityStmt)
225 * Hack to make up for lack of outfuncs for utility-stmt nodes
227 switch (nodeTag(node->utilityStmt))
230 appendStringInfo(str, " :create ");
231 _outToken(str, ((CreateStmt *) (node->utilityStmt))->relname);
232 appendStringInfo(str, " ");
233 _outNode(str, node->utilityStmt);
237 appendStringInfo(str, " :index ");
238 _outToken(str, ((IndexStmt *) (node->utilityStmt))->idxname);
239 appendStringInfo(str, " on ");
240 _outToken(str, ((IndexStmt *) (node->utilityStmt))->relname);
241 appendStringInfo(str, " ");
242 _outNode(str, node->utilityStmt);
246 appendStringInfo(str, " :notify ");
247 _outToken(str, ((NotifyStmt *) (node->utilityStmt))->relname);
251 appendStringInfo(str, " :utility ? ");
255 appendStringInfo(str, " :utility <>");
257 appendStringInfo(str, " :resultRelation %d :into ",
258 node->resultRelation);
259 _outToken(str, node->into);
261 appendStringInfo(str, " :isPortal %s :isBinary %s :isTemp %s"
262 " :hasAggs %s :hasSubLinks %s :rtable ",
263 node->isPortal ? "true" : "false",
264 node->isBinary ? "true" : "false",
265 node->isTemp ? "true" : "false",
266 node->hasAggs ? "true" : "false",
267 node->hasSubLinks ? "true" : "false");
268 _outNode(str, node->rtable);
270 appendStringInfo(str, " :jointree ");
271 _outNode(str, node->jointree);
273 appendStringInfo(str, " :rowMarks ");
274 _outIntList(str, node->rowMarks);
276 appendStringInfo(str, " :targetList ");
277 _outNode(str, node->targetList);
279 appendStringInfo(str, " :groupClause ");
280 _outNode(str, node->groupClause);
282 appendStringInfo(str, " :havingQual ");
283 _outNode(str, node->havingQual);
285 appendStringInfo(str, " :distinctClause ");
286 _outNode(str, node->distinctClause);
288 appendStringInfo(str, " :sortClause ");
289 _outNode(str, node->sortClause);
291 appendStringInfo(str, " :limitOffset ");
292 _outNode(str, node->limitOffset);
294 appendStringInfo(str, " :limitCount ");
295 _outNode(str, node->limitCount);
297 appendStringInfo(str, " :setOperations ");
298 _outNode(str, node->setOperations);
302 _outSortClause(StringInfo str, SortClause *node)
304 appendStringInfo(str, " SORTCLAUSE :tleSortGroupRef %d :sortop %u ",
305 node->tleSortGroupRef, node->sortop);
309 _outGroupClause(StringInfo str, GroupClause *node)
311 appendStringInfo(str, " GROUPCLAUSE :tleSortGroupRef %d :sortop %u ",
312 node->tleSortGroupRef, node->sortop);
316 _outSetOperationStmt(StringInfo str, SetOperationStmt *node)
318 appendStringInfo(str, " SETOPERATIONSTMT :op %d :all %s :larg ",
320 node->all ? "true" : "false");
321 _outNode(str, node->larg);
322 appendStringInfo(str, " :rarg ");
323 _outNode(str, node->rarg);
324 appendStringInfo(str, " :colTypes ");
325 _outIntList(str, node->colTypes);
329 * print the basic stuff of all nodes that inherit from Plan
332 _outPlanInfo(StringInfo str, Plan *node)
334 appendStringInfo(str,
335 ":startup_cost %.2f :total_cost %.2f :rows %.0f :width %d :state %s :qptargetlist ",
340 node->state ? "not-NULL" : "<>");
341 _outNode(str, node->targetlist);
343 appendStringInfo(str, " :qpqual ");
344 _outNode(str, node->qual);
346 appendStringInfo(str, " :lefttree ");
347 _outNode(str, node->lefttree);
349 appendStringInfo(str, " :righttree ");
350 _outNode(str, node->righttree);
352 appendStringInfo(str, " :extprm ");
353 _outIntList(str, node->extParam);
355 appendStringInfo(str, " :locprm ");
356 _outIntList(str, node->locParam);
358 appendStringInfo(str, " :initplan ");
359 _outNode(str, node->initPlan);
361 appendStringInfo(str, " :nprm %d ", node->nParamExec);
365 * Stuff from plannodes.h
368 _outPlan(StringInfo str, Plan *node)
370 appendStringInfo(str, " PLAN ");
371 _outPlanInfo(str, (Plan *) node);
375 _outResult(StringInfo str, Result *node)
377 appendStringInfo(str, " RESULT ");
378 _outPlanInfo(str, (Plan *) node);
380 appendStringInfo(str, " :resconstantqual ");
381 _outNode(str, node->resconstantqual);
386 * Append is a subclass of Plan.
389 _outAppend(StringInfo str, Append *node)
391 appendStringInfo(str, " APPEND ");
392 _outPlanInfo(str, (Plan *) node);
394 appendStringInfo(str, " :appendplans ");
395 _outNode(str, node->appendplans);
397 appendStringInfo(str, " :inheritrelid %u :inheritrtable ",
399 _outNode(str, node->inheritrtable);
403 * Join is a subclass of Plan
406 _outJoin(StringInfo str, Join *node)
408 appendStringInfo(str, " JOIN ");
409 _outPlanInfo(str, (Plan *) node);
410 appendStringInfo(str, " :jointype %d :joinqual ",
411 (int) node->jointype);
412 _outNode(str, node->joinqual);
416 * NestLoop is a subclass of Join
419 _outNestLoop(StringInfo str, NestLoop *node)
421 appendStringInfo(str, " NESTLOOP ");
422 _outPlanInfo(str, (Plan *) node);
423 appendStringInfo(str, " :jointype %d :joinqual ",
424 (int) node->join.jointype);
425 _outNode(str, node->join.joinqual);
429 * MergeJoin is a subclass of Join
432 _outMergeJoin(StringInfo str, MergeJoin *node)
434 appendStringInfo(str, " MERGEJOIN ");
435 _outPlanInfo(str, (Plan *) node);
436 appendStringInfo(str, " :jointype %d :joinqual ",
437 (int) node->join.jointype);
438 _outNode(str, node->join.joinqual);
440 appendStringInfo(str, " :mergeclauses ");
441 _outNode(str, node->mergeclauses);
445 * HashJoin is a subclass of Join.
448 _outHashJoin(StringInfo str, HashJoin *node)
450 appendStringInfo(str, " HASHJOIN ");
451 _outPlanInfo(str, (Plan *) node);
452 appendStringInfo(str, " :jointype %d :joinqual ",
453 (int) node->join.jointype);
454 _outNode(str, node->join.joinqual);
456 appendStringInfo(str, " :hashclauses ");
457 _outNode(str, node->hashclauses);
458 appendStringInfo(str, " :hashjoinop %u ",
463 _outSubPlan(StringInfo str, SubPlan *node)
465 appendStringInfo(str, " SUBPLAN :plan ");
466 _outNode(str, node->plan);
468 appendStringInfo(str, " :planid %u :rtable ", node->plan_id);
469 _outNode(str, node->rtable);
471 appendStringInfo(str, " :setprm ");
472 _outIntList(str, node->setParam);
474 appendStringInfo(str, " :parprm ");
475 _outIntList(str, node->parParam);
477 appendStringInfo(str, " :slink ");
478 _outNode(str, node->sublink);
482 * Scan is a subclass of Node
485 _outScan(StringInfo str, Scan *node)
487 appendStringInfo(str, " SCAN ");
488 _outPlanInfo(str, (Plan *) node);
490 appendStringInfo(str, " :scanrelid %u ", node->scanrelid);
494 * SeqScan is a subclass of Scan
497 _outSeqScan(StringInfo str, SeqScan *node)
499 appendStringInfo(str, " SEQSCAN ");
500 _outPlanInfo(str, (Plan *) node);
502 appendStringInfo(str, " :scanrelid %u ", node->scanrelid);
506 * IndexScan is a subclass of Scan
509 _outIndexScan(StringInfo str, IndexScan *node)
511 appendStringInfo(str, " INDEXSCAN ");
512 _outPlanInfo(str, (Plan *) node);
514 appendStringInfo(str, " :scanrelid %u :indxid ", node->scan.scanrelid);
515 _outIntList(str, node->indxid);
517 appendStringInfo(str, " :indxqual ");
518 _outNode(str, node->indxqual);
520 appendStringInfo(str, " :indxqualorig ");
521 _outNode(str, node->indxqualorig);
523 appendStringInfo(str, " :indxorderdir %d ", node->indxorderdir);
527 * TidScan is a subclass of Scan
530 _outTidScan(StringInfo str, TidScan *node)
532 appendStringInfo(str, " TIDSCAN ");
533 _outPlanInfo(str, (Plan *) node);
535 appendStringInfo(str, " :scanrelid %u ", node->scan.scanrelid);
536 appendStringInfo(str, " :needrescan %d ", node->needRescan);
538 appendStringInfo(str, " :tideval ");
539 _outNode(str, node->tideval);
544 * SubqueryScan is a subclass of Scan
547 _outSubqueryScan(StringInfo str, SubqueryScan *node)
549 appendStringInfo(str, " SUBQUERYSCAN ");
550 _outPlanInfo(str, (Plan *) node);
552 appendStringInfo(str, " :scanrelid %u :subplan ", node->scan.scanrelid);
553 _outNode(str, node->subplan);
557 * Material is a subclass of Plan
560 _outMaterial(StringInfo str, Material *node)
562 appendStringInfo(str, " MATERIAL ");
563 _outPlanInfo(str, (Plan *) node);
567 * Sort is a subclass of Plan
570 _outSort(StringInfo str, Sort *node)
572 appendStringInfo(str, " SORT ");
573 _outPlanInfo(str, (Plan *) node);
574 appendStringInfo(str, " :keycount %d ", node->keycount);
578 _outAgg(StringInfo str, Agg *node)
580 appendStringInfo(str, " AGG ");
581 _outPlanInfo(str, (Plan *) node);
585 _outGroup(StringInfo str, Group *node)
587 appendStringInfo(str, " GRP ");
588 _outPlanInfo(str, (Plan *) node);
590 /* the actual Group fields */
591 appendStringInfo(str, " :numCols %d :tuplePerGroup %s ",
593 node->tuplePerGroup ? "true" : "false");
597 _outUnique(StringInfo str, Unique *node)
601 appendStringInfo(str, " UNIQUE ");
602 _outPlanInfo(str, (Plan *) node);
604 appendStringInfo(str, " :numCols %d :uniqColIdx ",
606 for (i = 0; i < node->numCols; i++)
607 appendStringInfo(str, "%d ", (int) node->uniqColIdx[i]);
611 _outSetOp(StringInfo str, SetOp *node)
615 appendStringInfo(str, " SETOP ");
616 _outPlanInfo(str, (Plan *) node);
618 appendStringInfo(str, " :cmd %d :numCols %d :dupColIdx ",
619 (int) node->cmd, node->numCols);
620 for (i = 0; i < node->numCols; i++)
621 appendStringInfo(str, "%d ", (int) node->dupColIdx[i]);
622 appendStringInfo(str, " :flagColIdx %d ",
623 (int) node->flagColIdx);
627 _outLimit(StringInfo str, Limit *node)
629 appendStringInfo(str, " LIMIT ");
630 _outPlanInfo(str, (Plan *) node);
632 appendStringInfo(str, " :limitOffset ");
633 _outNode(str, node->limitOffset);
634 appendStringInfo(str, " :limitCount ");
635 _outNode(str, node->limitCount);
639 * Hash is a subclass of Plan
642 _outHash(StringInfo str, Hash *node)
644 appendStringInfo(str, " HASH ");
645 _outPlanInfo(str, (Plan *) node);
647 appendStringInfo(str, " :hashkey ");
648 _outNode(str, node->hashkey);
651 /*****************************************************************************
653 * Stuff from primnodes.h.
655 *****************************************************************************/
658 * Resdom is a subclass of Node
661 _outResdom(StringInfo str, Resdom *node)
663 appendStringInfo(str,
664 " RESDOM :resno %d :restype %u :restypmod %d :resname ",
668 _outToken(str, node->resname);
669 appendStringInfo(str, " :reskey %d :reskeyop %u :ressortgroupref %d :resjunk %s ",
672 node->ressortgroupref,
673 node->resjunk ? "true" : "false");
677 _outFjoin(StringInfo str, Fjoin *node)
681 appendStringInfo(str, " FJOIN :initialized %s :nNodes %d ",
682 node->fj_initialized ? "true" : "false",
685 appendStringInfo(str, " :innerNode ");
686 _outNode(str, node->fj_innerNode);
688 appendStringInfo(str, " :results @ 0x%x :alwaysdone",
689 (int) node->fj_results);
691 for (i = 0; i < node->fj_nNodes; i++)
692 appendStringInfo(str, (node->fj_alwaysDone[i]) ? "true" : "false");
696 * Expr is a subclass of Node
699 _outExpr(StringInfo str, Expr *node)
703 appendStringInfo(str, " EXPR :typeOid %u ",
706 switch (node->opType)
727 appendStringInfo(str, " :opType ");
728 _outToken(str, opstr);
729 appendStringInfo(str, " :oper ");
730 _outNode(str, node->oper);
732 appendStringInfo(str, " :args ");
733 _outNode(str, node->args);
737 * Var is a subclass of Expr
740 _outVar(StringInfo str, Var *node)
742 appendStringInfo(str,
743 " VAR :varno %d :varattno %d :vartype %u :vartypmod %d ",
749 appendStringInfo(str, " :varlevelsup %u :varnoold %d :varoattno %d",
756 * Const is a subclass of Expr
759 _outConst(StringInfo str, Const *node)
761 appendStringInfo(str,
762 " CONST :consttype %u :constlen %d :constisnull %s :constvalue ",
765 node->constisnull ? "true" : "false");
767 if (node->constisnull)
768 appendStringInfo(str, "<>");
770 _outDatum(str, node->constvalue, node->consttype);
772 appendStringInfo(str, " :constbyval %s ",
773 node->constbyval ? "true" : "false");
780 _outAggref(StringInfo str, Aggref *node)
782 appendStringInfo(str, " AGGREG :aggname ");
783 _outToken(str, node->aggname);
784 appendStringInfo(str, " :basetype %u :aggtype %u :target ",
785 node->basetype, node->aggtype);
786 _outNode(str, node->target);
788 appendStringInfo(str, " :aggstar %s :aggdistinct %s ",
789 node->aggstar ? "true" : "false",
790 node->aggdistinct ? "true" : "false");
791 /* aggno is not dumped */
798 _outSubLink(StringInfo str, SubLink *node)
800 appendStringInfo(str,
801 " SUBLINK :subLinkType %d :useor %s :lefthand ",
803 node->useor ? "true" : "false");
804 _outNode(str, node->lefthand);
806 appendStringInfo(str, " :oper ");
807 _outNode(str, node->oper);
809 appendStringInfo(str, " :subselect ");
810 _outNode(str, node->subselect);
814 * ArrayRef is a subclass of Expr
817 _outArrayRef(StringInfo str, ArrayRef *node)
819 appendStringInfo(str,
820 " ARRAYREF :refelemtype %u :refattrlength %d :refelemlength %d ",
823 node->refelemlength);
825 appendStringInfo(str, " :refelembyval %c :refupperindex ",
826 node->refelembyval ? 't' : 'f');
827 _outNode(str, node->refupperindexpr);
829 appendStringInfo(str, " :reflowerindex ");
830 _outNode(str, node->reflowerindexpr);
832 appendStringInfo(str, " :refexpr ");
833 _outNode(str, node->refexpr);
835 appendStringInfo(str, " :refassgnexpr ");
836 _outNode(str, node->refassgnexpr);
840 * Func is a subclass of Expr
843 _outFunc(StringInfo str, Func *node)
845 appendStringInfo(str, " FUNC :funcid %u :functype %u ",
851 * Oper is a subclass of Expr
854 _outOper(StringInfo str, Oper *node)
856 appendStringInfo(str,
857 " OPER :opno %u :opid %u :opresulttype %u ",
864 * Param is a subclass of Expr
867 _outParam(StringInfo str, Param *node)
869 appendStringInfo(str, " PARAM :paramkind %d :paramid %d :paramname ",
872 _outToken(str, node->paramname);
873 appendStringInfo(str, " :paramtype %u ", node->paramtype);
880 _outFieldSelect(StringInfo str, FieldSelect *node)
882 appendStringInfo(str, " FIELDSELECT :arg ");
883 _outNode(str, node->arg);
885 appendStringInfo(str, " :fieldnum %d :resulttype %u :resulttypmod %d ",
886 node->fieldnum, node->resulttype, node->resulttypmod);
893 _outRelabelType(StringInfo str, RelabelType *node)
895 appendStringInfo(str, " RELABELTYPE :arg ");
896 _outNode(str, node->arg);
898 appendStringInfo(str, " :resulttype %u :resulttypmod %d ",
899 node->resulttype, node->resulttypmod);
906 _outRangeTblRef(StringInfo str, RangeTblRef *node)
908 appendStringInfo(str, " RANGETBLREF %d ",
916 _outFromExpr(StringInfo str, FromExpr *node)
918 appendStringInfo(str, " FROMEXPR :fromlist ");
919 _outNode(str, node->fromlist);
920 appendStringInfo(str, " :quals ");
921 _outNode(str, node->quals);
928 _outJoinExpr(StringInfo str, JoinExpr *node)
930 appendStringInfo(str, " JOINEXPR :jointype %d :isNatural %s :larg ",
931 (int) node->jointype,
932 node->isNatural ? "true" : "false");
933 _outNode(str, node->larg);
934 appendStringInfo(str, " :rarg ");
935 _outNode(str, node->rarg);
936 appendStringInfo(str, " :using ");
937 _outNode(str, node->using);
938 appendStringInfo(str, " :quals ");
939 _outNode(str, node->quals);
940 appendStringInfo(str, " :alias ");
941 _outNode(str, node->alias);
942 appendStringInfo(str, " :colnames ");
943 _outNode(str, node->colnames);
944 appendStringInfo(str, " :colvars ");
945 _outNode(str, node->colvars);
949 * Stuff from execnodes.h
953 * EState is a subclass of Node.
956 _outEState(StringInfo str, EState *node)
958 appendStringInfo(str,
959 " ESTATE :direction %d :range_table ",
961 _outNode(str, node->es_range_table);
963 appendStringInfo(str, " :result_relation_info @ 0x%x ",
964 (int) (node->es_result_relation_info));
968 * Stuff from relation.h
972 _outRelOptInfo(StringInfo str, RelOptInfo *node)
974 appendStringInfo(str, " RELOPTINFO :relids ");
975 _outIntList(str, node->relids);
977 appendStringInfo(str, " :rows %.0f :width %d :targetlist ",
980 _outNode(str, node->targetlist);
982 appendStringInfo(str, " :pathlist ");
983 _outNode(str, node->pathlist);
984 appendStringInfo(str, " :cheapest_startup_path ");
985 _outNode(str, node->cheapest_startup_path);
986 appendStringInfo(str, " :cheapest_total_path ");
987 _outNode(str, node->cheapest_total_path);
989 appendStringInfo(str, " :pruneable %s :issubquery %s :indexed %s :pages %ld :tuples %.0f :subplan ",
990 node->pruneable ? "true" : "false",
991 node->issubquery ? "true" : "false",
992 node->indexed ? "true" : "false",
995 _outNode(str, node->subplan);
997 appendStringInfo(str, " :baserestrictinfo ");
998 _outNode(str, node->baserestrictinfo);
999 appendStringInfo(str, " :baserestrictcost %.2f :outerjoinset ",
1000 node->baserestrictcost);
1001 _outIntList(str, node->outerjoinset);
1002 appendStringInfo(str, " :joininfo ");
1003 _outNode(str, node->joininfo);
1004 appendStringInfo(str, " :innerjoin ");
1005 _outNode(str, node->innerjoin);
1009 _outIndexOptInfo(StringInfo str, IndexOptInfo *node)
1011 appendStringInfo(str, " INDEXOPTINFO :indexoid %u :pages %ld :tuples %g ",
1018 * TargetEntry is a subclass of Node.
1021 _outTargetEntry(StringInfo str, TargetEntry *node)
1023 appendStringInfo(str, " TARGETENTRY :resdom ");
1024 _outNode(str, node->resdom);
1026 appendStringInfo(str, " :expr ");
1027 _outNode(str, node->expr);
1031 _outRangeTblEntry(StringInfo str, RangeTblEntry *node)
1033 appendStringInfo(str, " RTE :relname ");
1034 _outToken(str, node->relname);
1035 appendStringInfo(str, " :relid %u ",
1037 appendStringInfo(str, " :subquery ");
1038 _outNode(str, node->subquery);
1039 appendStringInfo(str, " :alias ");
1040 _outNode(str, node->alias);
1041 appendStringInfo(str, " :eref ");
1042 _outNode(str, node->eref);
1043 appendStringInfo(str, " :inh %s :inFromCl %s :checkForRead %s"
1044 " :checkForWrite %s :checkAsUser %u",
1045 node->inh ? "true" : "false",
1046 node->inFromCl ? "true" : "false",
1047 node->checkForRead ? "true" : "false",
1048 node->checkForWrite ? "true" : "false",
1053 * Path is a subclass of Node.
1056 _outPath(StringInfo str, Path *node)
1058 appendStringInfo(str,
1059 " PATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
1063 _outNode(str, node->pathkeys);
1067 * IndexPath is a subclass of Path.
1070 _outIndexPath(StringInfo str, IndexPath *node)
1072 appendStringInfo(str,
1073 " INDEXPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
1074 node->path.pathtype,
1075 node->path.startup_cost,
1076 node->path.total_cost);
1077 _outNode(str, node->path.pathkeys);
1079 appendStringInfo(str, " :indexid ");
1080 _outIntList(str, node->indexid);
1082 appendStringInfo(str, " :indexqual ");
1083 _outNode(str, node->indexqual);
1085 appendStringInfo(str, " :indexscandir %d :joinrelids ",
1086 (int) node->indexscandir);
1087 _outIntList(str, node->joinrelids);
1089 appendStringInfo(str, " :alljoinquals %s :rows %.2f ",
1090 node->alljoinquals ? "true" : "false",
1095 * TidPath is a subclass of Path.
1098 _outTidPath(StringInfo str, TidPath *node)
1100 appendStringInfo(str,
1101 " TIDPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
1102 node->path.pathtype,
1103 node->path.startup_cost,
1104 node->path.total_cost);
1105 _outNode(str, node->path.pathkeys);
1107 appendStringInfo(str, " :tideval ");
1108 _outNode(str, node->tideval);
1110 appendStringInfo(str, " :un joined_relids ");
1111 _outIntList(str, node->unjoined_relids);
1115 * NestPath is a subclass of Path
1118 _outNestPath(StringInfo str, NestPath *node)
1120 appendStringInfo(str,
1121 " NESTPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
1122 node->path.pathtype,
1123 node->path.startup_cost,
1124 node->path.total_cost);
1125 _outNode(str, node->path.pathkeys);
1126 appendStringInfo(str, " :jointype %d :outerjoinpath ",
1127 (int) node->jointype);
1128 _outNode(str, node->outerjoinpath);
1129 appendStringInfo(str, " :innerjoinpath ");
1130 _outNode(str, node->innerjoinpath);
1131 appendStringInfo(str, " :joinrestrictinfo ");
1132 _outNode(str, node->joinrestrictinfo);
1136 * MergePath is a subclass of NestPath.
1139 _outMergePath(StringInfo str, MergePath *node)
1141 appendStringInfo(str,
1142 " MERGEPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
1143 node->jpath.path.pathtype,
1144 node->jpath.path.startup_cost,
1145 node->jpath.path.total_cost);
1146 _outNode(str, node->jpath.path.pathkeys);
1147 appendStringInfo(str, " :jointype %d :outerjoinpath ",
1148 (int) node->jpath.jointype);
1149 _outNode(str, node->jpath.outerjoinpath);
1150 appendStringInfo(str, " :innerjoinpath ");
1151 _outNode(str, node->jpath.innerjoinpath);
1152 appendStringInfo(str, " :joinrestrictinfo ");
1153 _outNode(str, node->jpath.joinrestrictinfo);
1155 appendStringInfo(str, " :path_mergeclauses ");
1156 _outNode(str, node->path_mergeclauses);
1158 appendStringInfo(str, " :outersortkeys ");
1159 _outNode(str, node->outersortkeys);
1161 appendStringInfo(str, " :innersortkeys ");
1162 _outNode(str, node->innersortkeys);
1166 * HashPath is a subclass of NestPath.
1169 _outHashPath(StringInfo str, HashPath *node)
1171 appendStringInfo(str,
1172 " HASHPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
1173 node->jpath.path.pathtype,
1174 node->jpath.path.startup_cost,
1175 node->jpath.path.total_cost);
1176 _outNode(str, node->jpath.path.pathkeys);
1177 appendStringInfo(str, " :jointype %d :outerjoinpath ",
1178 (int) node->jpath.jointype);
1179 _outNode(str, node->jpath.outerjoinpath);
1180 appendStringInfo(str, " :innerjoinpath ");
1181 _outNode(str, node->jpath.innerjoinpath);
1182 appendStringInfo(str, " :joinrestrictinfo ");
1183 _outNode(str, node->jpath.joinrestrictinfo);
1185 appendStringInfo(str, " :path_hashclauses ");
1186 _outNode(str, node->path_hashclauses);
1190 * PathKeyItem is a subclass of Node.
1193 _outPathKeyItem(StringInfo str, PathKeyItem *node)
1195 appendStringInfo(str, " PATHKEYITEM :sortop %u :key ",
1197 _outNode(str, node->key);
1201 * RestrictInfo is a subclass of Node.
1204 _outRestrictInfo(StringInfo str, RestrictInfo *node)
1206 appendStringInfo(str, " RESTRICTINFO :clause ");
1207 _outNode(str, node->clause);
1209 appendStringInfo(str, " :ispusheddown %s :subclauseindices ",
1210 node->ispusheddown ? "true" : "false");
1211 _outNode(str, node->subclauseindices);
1213 appendStringInfo(str, " :mergejoinoperator %u ", node->mergejoinoperator);
1214 appendStringInfo(str, " :left_sortop %u ", node->left_sortop);
1215 appendStringInfo(str, " :right_sortop %u ", node->right_sortop);
1216 appendStringInfo(str, " :hashjoinoperator %u ", node->hashjoinoperator);
1220 * JoinInfo is a subclass of Node.
1223 _outJoinInfo(StringInfo str, JoinInfo *node)
1225 appendStringInfo(str, " JINFO :unjoined_relids ");
1226 _outIntList(str, node->unjoined_relids);
1228 appendStringInfo(str, " :jinfo_restrictinfo ");
1229 _outNode(str, node->jinfo_restrictinfo);
1233 * Print the value of a Datum given its type.
1236 _outDatum(StringInfo str, Datum value, Oid type)
1245 * find some information about the type and the "real" length of the
1248 byValue = get_typbyval(type);
1249 typeLength = get_typlen(type);
1250 length = datumGetSize(value, byValue, typeLength);
1254 s = (char *) (&value);
1255 appendStringInfo(str, " %u [ ", (unsigned int) length);
1256 for (i = 0; i < (int) sizeof(Datum); i++)
1257 appendStringInfo(str, "%d ", (int) (s[i]));
1258 appendStringInfo(str, "] ");
1262 s = (char *) DatumGetPointer(value);
1263 if (!PointerIsValid(s))
1264 appendStringInfo(str, " 0 [ ] ");
1267 appendStringInfo(str, " %u [ ", (unsigned int) length);
1268 for (i = 0; i < (int) length; i++)
1269 appendStringInfo(str, "%d ", (int) (s[i]));
1270 appendStringInfo(str, "] ");
1276 _outIter(StringInfo str, Iter *node)
1278 appendStringInfo(str, " ITER :iterexpr ");
1279 _outNode(str, node->iterexpr);
1283 _outStream(StringInfo str, Stream *node)
1285 appendStringInfo(str,
1286 " STREAM :pathptr @ 0x%x :cinfo @ 0x%x :clausetype %d :upstream @ 0x%x ",
1287 (int) node->pathptr,
1289 (int) node->clausetype,
1290 (int) node->upstream);
1292 appendStringInfo(str,
1293 " :downstream @ 0x%x :groupup %d :groupcost %f :groupsel %f ",
1294 (int) node->downstream,
1301 _outAExpr(StringInfo str, A_Expr *node)
1303 appendStringInfo(str, " AEXPR ");
1307 appendStringInfo(str, "AND ");
1310 appendStringInfo(str, "OR ");
1313 appendStringInfo(str, "NOT ");
1316 appendStringInfo(str, "ISNULL ");
1319 appendStringInfo(str, "NOTNULL ");
1322 _outToken(str, node->opname);
1323 appendStringInfo(str, " ");
1326 appendStringInfo(str, "?? ");
1329 _outNode(str, node->lexpr);
1330 appendStringInfo(str, " ");
1331 _outNode(str, node->rexpr);
1335 _outValue(StringInfo str, Value *value)
1337 switch (value->type)
1340 appendStringInfo(str, " %ld ", value->val.ival);
1345 * We assume the value is a valid numeric literal and so does
1348 appendStringInfo(str, " %s ", value->val.str);
1351 appendStringInfo(str, " \"");
1352 _outToken(str, value->val.str);
1353 appendStringInfo(str, "\" ");
1356 elog(NOTICE, "_outValue: don't know how to print type %d ",
1363 _outIdent(StringInfo str, Ident *node)
1365 appendStringInfo(str, " IDENT ");
1366 _outToken(str, node->name);
1370 _outAttr(StringInfo str, Attr *node)
1372 appendStringInfo(str, " ATTR :relname ");
1373 _outToken(str, node->relname);
1374 appendStringInfo(str, " :attrs ");
1375 _outNode(str, node->attrs);
1379 _outAConst(StringInfo str, A_Const *node)
1381 appendStringInfo(str, "CONST ");
1382 _outValue(str, &(node->val));
1383 appendStringInfo(str, " :typename ");
1384 _outNode(str, node->typename);
1388 _outConstraint(StringInfo str, Constraint *node)
1390 appendStringInfo(str, " ");
1391 _outToken(str, node->name);
1392 appendStringInfo(str, " :type ");
1394 switch (node->contype)
1396 case CONSTR_PRIMARY:
1397 appendStringInfo(str, "PRIMARY KEY ");
1398 _outNode(str, node->keys);
1402 appendStringInfo(str, "CHECK :raw ");
1403 _outNode(str, node->raw_expr);
1404 appendStringInfo(str, " :cooked ");
1405 _outToken(str, node->cooked_expr);
1408 case CONSTR_DEFAULT:
1409 appendStringInfo(str, "DEFAULT :raw ");
1410 _outNode(str, node->raw_expr);
1411 appendStringInfo(str, " :cooked ");
1412 _outToken(str, node->cooked_expr);
1415 case CONSTR_NOTNULL:
1416 appendStringInfo(str, "NOT NULL");
1420 appendStringInfo(str, "UNIQUE ");
1421 _outNode(str, node->keys);
1425 appendStringInfo(str, "<unrecognized_constraint>");
1431 _outCaseExpr(StringInfo str, CaseExpr *node)
1433 appendStringInfo(str, " CASE :casetype %u :arg ",
1435 _outNode(str, node->arg);
1437 appendStringInfo(str, " :args ");
1438 _outNode(str, node->args);
1440 appendStringInfo(str, " :defresult ");
1441 _outNode(str, node->defresult);
1445 _outCaseWhen(StringInfo str, CaseWhen *node)
1447 appendStringInfo(str, " WHEN ");
1448 _outNode(str, node->expr);
1450 appendStringInfo(str, " :then ");
1451 _outNode(str, node->result);
1456 * converts a Node into ascii string and append it to 'str'
1459 _outNode(StringInfo str, void *obj)
1463 appendStringInfo(str, "<>");
1471 appendStringInfoChar(str, '(');
1472 foreach(l, (List *) obj)
1474 _outNode(str, lfirst(l));
1476 appendStringInfoChar(str, ' ');
1478 appendStringInfoChar(str, ')');
1480 else if (IsA_Value(obj))
1482 /* nodeRead does not want to see { } around these! */
1483 _outValue(str, obj);
1487 appendStringInfoChar(str, '{');
1488 switch (nodeTag(obj))
1491 _outCreateStmt(str, obj);
1494 _outIndexStmt(str, obj);
1497 _outColumnDef(str, obj);
1500 _outTypeName(str, obj);
1503 _outTypeCast(str, obj);
1506 _outIndexElem(str, obj);
1509 _outQuery(str, obj);
1512 _outSortClause(str, obj);
1515 _outGroupClause(str, obj);
1517 case T_SetOperationStmt:
1518 _outSetOperationStmt(str, obj);
1524 _outResult(str, obj);
1527 _outAppend(str, obj);
1533 _outNestLoop(str, obj);
1536 _outMergeJoin(str, obj);
1539 _outHashJoin(str, obj);
1545 _outSeqScan(str, obj);
1548 _outIndexScan(str, obj);
1551 _outTidScan(str, obj);
1553 case T_SubqueryScan:
1554 _outSubqueryScan(str, obj);
1557 _outMaterial(str, obj);
1566 _outGroup(str, obj);
1569 _outUnique(str, obj);
1572 _outSetOp(str, obj);
1575 _outLimit(str, obj);
1581 _outSubPlan(str, obj);
1584 _outResdom(str, obj);
1587 _outFjoin(str, obj);
1596 _outConst(str, obj);
1599 _outAggref(str, obj);
1602 _outSubLink(str, obj);
1605 _outArrayRef(str, obj);
1614 _outParam(str, obj);
1617 _outFieldSelect(str, obj);
1620 _outRelabelType(str, obj);
1623 _outRangeTblRef(str, obj);
1626 _outFromExpr(str, obj);
1629 _outJoinExpr(str, obj);
1632 _outEState(str, obj);
1635 _outRelOptInfo(str, obj);
1637 case T_IndexOptInfo:
1638 _outIndexOptInfo(str, obj);
1641 _outTargetEntry(str, obj);
1643 case T_RangeTblEntry:
1644 _outRangeTblEntry(str, obj);
1650 _outIndexPath(str, obj);
1653 _outTidPath(str, obj);
1656 _outNestPath(str, obj);
1659 _outMergePath(str, obj);
1662 _outHashPath(str, obj);
1665 _outPathKeyItem(str, obj);
1667 case T_RestrictInfo:
1668 _outRestrictInfo(str, obj);
1671 _outJoinInfo(str, obj);
1677 _outStream(str, obj);
1680 _outAExpr(str, obj);
1683 _outIdent(str, obj);
1686 _outAConst(str, obj);
1689 _outConstraint(str, obj);
1692 _outCaseExpr(str, obj);
1695 _outCaseWhen(str, obj);
1698 case T_VariableSetStmt:
1701 _outSelectStmt(str, obj);
1704 _outFuncCall(str, obj);
1711 elog(NOTICE, "_outNode: don't know how to print type %d ",
1715 appendStringInfoChar(str, '}');
1721 * returns the ascii representation of the Node as a palloc'd string
1724 nodeToString(void *obj)
1728 /* see stringinfo.h for an explanation of this maneuver */
1729 initStringInfo(&str);
1730 _outNode(&str, obj);