]> granicus.if.org Git - postgresql/blob - src/backend/nodes/outfuncs.c
Re-implement LIMIT/OFFSET as a plan node type, instead of a hack in
[postgresql] / src / backend / nodes / outfuncs.c
1 /*
2  *
3  * outfuncs.c
4  *        routines to convert a node to ascii representation
5  *
6  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *      $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.129 2000/10/26 21:35:48 tgl Exp $
10  *
11  * NOTES
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
16  *        Mariposa.
17  *
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.)
21  *
22  */
23 #include <ctype.h>
24
25 #include "postgres.h"
26
27 #include "access/heapam.h"
28 #include "access/htup.h"
29 #include "catalog/pg_type.h"
30 #include "fmgr.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"
43
44
45 static void _outDatum(StringInfo str, Datum value, Oid type);
46 static void _outNode(StringInfo str, void *obj);
47
48 /*
49  * _outToken
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.
52  *
53  *        If a null or empty string is given, it is encoded as "<>".
54  */
55 static void
56 _outToken(StringInfo str, char *s)
57 {
58         if (s == NULL || *s == '\0')
59         {
60                 appendStringInfo(str, "<>");
61                 return;
62         }
63
64         /*
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.
68          */
69         /* These characters only need to be quoted at the start of the string */
70         if (*s == '<' ||
71                 *s == '\"' ||
72                 *s == '@' ||
73                 isdigit((int) *s) ||
74                 (*s == '-' && isdigit((int) s[1])))
75                 appendStringInfoChar(str, '\\');
76         while (*s)
77         {
78                 /* These chars must be backslashed anywhere in the string */
79                 if (*s == ' ' || *s == '\n' || *s == '\t' ||
80                         *s == '(' || *s == ')' || *s == '{' || *s == '}' ||
81                         *s == '\\')
82                         appendStringInfoChar(str, '\\');
83                 appendStringInfoChar(str, *s++);
84         }
85 }
86
87 /*
88  * _outIntList -
89  *         converts a List of integers
90  */
91 static void
92 _outIntList(StringInfo str, List *list)
93 {
94         List       *l;
95
96         appendStringInfoChar(str, '(');
97         foreach(l, list)
98                 appendStringInfo(str, " %d", lfirsti(l));
99         appendStringInfoChar(str, ')');
100 }
101
102 static void
103 _outCreateStmt(StringInfo str, CreateStmt *node)
104 {
105         appendStringInfo(str, " CREATE :relname ");
106         _outToken(str, node->relname);
107
108         appendStringInfo(str, " :istemp %s ",
109                                          node->istemp ? "true" : "false");
110
111         appendStringInfo(str, " :columns ");
112         _outNode(str, node->tableElts);
113
114         appendStringInfo(str, " :inhRelnames ");
115         _outNode(str, node->inhRelnames);
116
117         appendStringInfo(str, " :constraints ");
118         _outNode(str, node->constraints);
119 }
120
121 static void
122 _outIndexStmt(StringInfo str, IndexStmt *node)
123 {
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);
132
133         appendStringInfo(str, " :withClause ");
134         _outNode(str, node->withClause);
135
136         appendStringInfo(str, " :whereClause ");
137         _outNode(str, node->whereClause);
138
139         appendStringInfo(str, " :rangetable ");
140         _outNode(str, node->rangetable);
141
142         appendStringInfo(str, " :unique %s :primary %s ",
143                                          node->unique ? "true" : "false",
144                                          node->primary ? "true" : "false");
145 }
146
147 static void
148 _outSelectStmt(StringInfo str, SelectStmt *node)
149 {
150         /* XXX this is pretty durn incomplete */
151         appendStringInfo(str, "SELECT :where ");
152         _outNode(str, node->whereClause);
153 }
154
155 static void
156 _outFuncCall(StringInfo str, FuncCall *node)
157 {
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");
165 }
166
167 static void
168 _outColumnDef(StringInfo str, ColumnDef *node)
169 {
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);
182 }
183
184 static void
185 _outTypeName(StringInfo str, TypeName *node)
186 {
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",
192                                          node->typmod);
193         _outNode(str, node->arrayBounds);
194 }
195
196 static void
197 _outTypeCast(StringInfo str, TypeCast *node)
198 {
199         appendStringInfo(str, " TYPECAST :arg ");
200         _outNode(str, node->arg);
201         appendStringInfo(str, " :typename ");
202         _outNode(str, node->typename);
203 }
204
205 static void
206 _outIndexElem(StringInfo str, IndexElem *node)
207 {
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);
214 }
215
216 static void
217 _outQuery(StringInfo str, Query *node)
218 {
219
220         appendStringInfo(str, " QUERY :command %d ", node->commandType);
221
222         if (node->utilityStmt)
223         {
224                 /*
225                  * Hack to make up for lack of outfuncs for utility-stmt nodes
226                  */
227                 switch (nodeTag(node->utilityStmt))
228                 {
229                         case T_CreateStmt:
230                                 appendStringInfo(str, " :create ");
231                                 _outToken(str, ((CreateStmt *) (node->utilityStmt))->relname);
232                                 appendStringInfo(str, " ");
233                                 _outNode(str, node->utilityStmt);
234                                 break;
235
236                         case T_IndexStmt:
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);
243                                 break;
244
245                         case T_NotifyStmt:
246                                 appendStringInfo(str, " :notify ");
247                                 _outToken(str, ((NotifyStmt *) (node->utilityStmt))->relname);
248                                 break;
249
250                         default:
251                                 appendStringInfo(str, " :utility ? ");
252                 }
253         }
254         else
255                 appendStringInfo(str, " :utility <>");
256
257         appendStringInfo(str, " :resultRelation %d :into ",
258                                          node->resultRelation);
259         _outToken(str, node->into);
260
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);
269
270         appendStringInfo(str, " :jointree ");
271         _outNode(str, node->jointree);
272
273         appendStringInfo(str, " :rowMarks ");
274         _outIntList(str, node->rowMarks);
275
276         appendStringInfo(str, " :targetList ");
277         _outNode(str, node->targetList);
278
279         appendStringInfo(str, " :groupClause ");
280         _outNode(str, node->groupClause);
281
282         appendStringInfo(str, " :havingQual ");
283         _outNode(str, node->havingQual);
284
285         appendStringInfo(str, " :distinctClause ");
286         _outNode(str, node->distinctClause);
287
288         appendStringInfo(str, " :sortClause ");
289         _outNode(str, node->sortClause);
290
291         appendStringInfo(str, " :limitOffset ");
292         _outNode(str, node->limitOffset);
293
294         appendStringInfo(str, " :limitCount ");
295         _outNode(str, node->limitCount);
296
297         appendStringInfo(str, " :setOperations ");
298         _outNode(str, node->setOperations);
299 }
300
301 static void
302 _outSortClause(StringInfo str, SortClause *node)
303 {
304         appendStringInfo(str, " SORTCLAUSE :tleSortGroupRef %d :sortop %u ",
305                                          node->tleSortGroupRef, node->sortop);
306 }
307
308 static void
309 _outGroupClause(StringInfo str, GroupClause *node)
310 {
311         appendStringInfo(str, " GROUPCLAUSE :tleSortGroupRef %d :sortop %u ",
312                                          node->tleSortGroupRef, node->sortop);
313 }
314
315 static void
316 _outSetOperationStmt(StringInfo str, SetOperationStmt *node)
317 {
318         appendStringInfo(str, " SETOPERATIONSTMT :op %d :all %s :larg ",
319                                          (int) node->op,
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);
326 }
327
328 /*
329  * print the basic stuff of all nodes that inherit from Plan
330  */
331 static void
332 _outPlanInfo(StringInfo str, Plan *node)
333 {
334         appendStringInfo(str,
335                                          ":startup_cost %.2f :total_cost %.2f :rows %.0f :width %d :state %s :qptargetlist ",
336                                          node->startup_cost,
337                                          node->total_cost,
338                                          node->plan_rows,
339                                          node->plan_width,
340                                          node->state ? "not-NULL" : "<>");
341         _outNode(str, node->targetlist);
342
343         appendStringInfo(str, " :qpqual ");
344         _outNode(str, node->qual);
345
346         appendStringInfo(str, " :lefttree ");
347         _outNode(str, node->lefttree);
348
349         appendStringInfo(str, " :righttree ");
350         _outNode(str, node->righttree);
351
352         appendStringInfo(str, " :extprm ");
353         _outIntList(str, node->extParam);
354
355         appendStringInfo(str, " :locprm ");
356         _outIntList(str, node->locParam);
357
358         appendStringInfo(str, " :initplan ");
359         _outNode(str, node->initPlan);
360
361         appendStringInfo(str, " :nprm %d ", node->nParamExec);
362 }
363
364 /*
365  *      Stuff from plannodes.h
366  */
367 static void
368 _outPlan(StringInfo str, Plan *node)
369 {
370         appendStringInfo(str, " PLAN ");
371         _outPlanInfo(str, (Plan *) node);
372 }
373
374 static void
375 _outResult(StringInfo str, Result *node)
376 {
377         appendStringInfo(str, " RESULT ");
378         _outPlanInfo(str, (Plan *) node);
379
380         appendStringInfo(str, " :resconstantqual ");
381         _outNode(str, node->resconstantqual);
382
383 }
384
385 /*
386  *      Append is a subclass of Plan.
387  */
388 static void
389 _outAppend(StringInfo str, Append *node)
390 {
391         appendStringInfo(str, " APPEND ");
392         _outPlanInfo(str, (Plan *) node);
393
394         appendStringInfo(str, " :appendplans ");
395         _outNode(str, node->appendplans);
396
397         appendStringInfo(str, " :inheritrelid %u :inheritrtable ",
398                                          node->inheritrelid);
399         _outNode(str, node->inheritrtable);
400 }
401
402 /*
403  *      Join is a subclass of Plan
404  */
405 static void
406 _outJoin(StringInfo str, Join *node)
407 {
408         appendStringInfo(str, " JOIN ");
409         _outPlanInfo(str, (Plan *) node);
410         appendStringInfo(str, " :jointype %d :joinqual ",
411                                          (int) node->jointype);
412         _outNode(str, node->joinqual);
413 }
414
415 /*
416  *      NestLoop is a subclass of Join
417  */
418 static void
419 _outNestLoop(StringInfo str, NestLoop *node)
420 {
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);
426 }
427
428 /*
429  *      MergeJoin is a subclass of Join
430  */
431 static void
432 _outMergeJoin(StringInfo str, MergeJoin *node)
433 {
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);
439
440         appendStringInfo(str, " :mergeclauses ");
441         _outNode(str, node->mergeclauses);
442 }
443
444 /*
445  *      HashJoin is a subclass of Join.
446  */
447 static void
448 _outHashJoin(StringInfo str, HashJoin *node)
449 {
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);
455
456         appendStringInfo(str, " :hashclauses ");
457         _outNode(str, node->hashclauses);
458         appendStringInfo(str, " :hashjoinop %u ",
459                                          node->hashjoinop);
460 }
461
462 static void
463 _outSubPlan(StringInfo str, SubPlan *node)
464 {
465         appendStringInfo(str, " SUBPLAN :plan ");
466         _outNode(str, node->plan);
467
468         appendStringInfo(str, " :planid %u :rtable ", node->plan_id);
469         _outNode(str, node->rtable);
470
471         appendStringInfo(str, " :setprm ");
472         _outIntList(str, node->setParam);
473
474         appendStringInfo(str, " :parprm ");
475         _outIntList(str, node->parParam);
476
477         appendStringInfo(str, " :slink ");
478         _outNode(str, node->sublink);
479 }
480
481 /*
482  *      Scan is a subclass of Node
483  */
484 static void
485 _outScan(StringInfo str, Scan *node)
486 {
487         appendStringInfo(str, " SCAN ");
488         _outPlanInfo(str, (Plan *) node);
489
490         appendStringInfo(str, " :scanrelid %u ", node->scanrelid);
491 }
492
493 /*
494  *      SeqScan is a subclass of Scan
495  */
496 static void
497 _outSeqScan(StringInfo str, SeqScan *node)
498 {
499         appendStringInfo(str, " SEQSCAN ");
500         _outPlanInfo(str, (Plan *) node);
501
502         appendStringInfo(str, " :scanrelid %u ", node->scanrelid);
503 }
504
505 /*
506  *      IndexScan is a subclass of Scan
507  */
508 static void
509 _outIndexScan(StringInfo str, IndexScan *node)
510 {
511         appendStringInfo(str, " INDEXSCAN ");
512         _outPlanInfo(str, (Plan *) node);
513
514         appendStringInfo(str, " :scanrelid %u :indxid ", node->scan.scanrelid);
515         _outIntList(str, node->indxid);
516
517         appendStringInfo(str, " :indxqual ");
518         _outNode(str, node->indxqual);
519
520         appendStringInfo(str, " :indxqualorig ");
521         _outNode(str, node->indxqualorig);
522
523         appendStringInfo(str, " :indxorderdir %d ", node->indxorderdir);
524 }
525
526 /*
527  *      TidScan is a subclass of Scan
528  */
529 static void
530 _outTidScan(StringInfo str, TidScan *node)
531 {
532         appendStringInfo(str, " TIDSCAN ");
533         _outPlanInfo(str, (Plan *) node);
534
535         appendStringInfo(str, " :scanrelid %u ", node->scan.scanrelid);
536         appendStringInfo(str, " :needrescan %d ", node->needRescan);
537
538         appendStringInfo(str, " :tideval ");
539         _outNode(str, node->tideval);
540
541 }
542
543 /*
544  *      SubqueryScan is a subclass of Scan
545  */
546 static void
547 _outSubqueryScan(StringInfo str, SubqueryScan *node)
548 {
549         appendStringInfo(str, " SUBQUERYSCAN ");
550         _outPlanInfo(str, (Plan *) node);
551
552         appendStringInfo(str, " :scanrelid %u :subplan ", node->scan.scanrelid);
553         _outNode(str, node->subplan);
554 }
555
556 /*
557  *      Material is a subclass of Plan
558  */
559 static void
560 _outMaterial(StringInfo str, Material *node)
561 {
562         appendStringInfo(str, " MATERIAL ");
563         _outPlanInfo(str, (Plan *) node);
564 }
565
566 /*
567  *      Sort is a subclass of Plan
568  */
569 static void
570 _outSort(StringInfo str, Sort *node)
571 {
572         appendStringInfo(str, " SORT ");
573         _outPlanInfo(str, (Plan *) node);
574         appendStringInfo(str, " :keycount %d ", node->keycount);
575 }
576
577 static void
578 _outAgg(StringInfo str, Agg *node)
579 {
580         appendStringInfo(str, " AGG ");
581         _outPlanInfo(str, (Plan *) node);
582 }
583
584 static void
585 _outGroup(StringInfo str, Group *node)
586 {
587         appendStringInfo(str, " GRP ");
588         _outPlanInfo(str, (Plan *) node);
589
590         /* the actual Group fields */
591         appendStringInfo(str, " :numCols %d :tuplePerGroup %s ",
592                                          node->numCols,
593                                          node->tuplePerGroup ? "true" : "false");
594 }
595
596 static void
597 _outUnique(StringInfo str, Unique *node)
598 {
599         int             i;
600
601         appendStringInfo(str, " UNIQUE ");
602         _outPlanInfo(str, (Plan *) node);
603
604         appendStringInfo(str, " :numCols %d :uniqColIdx ",
605                                          node->numCols);
606         for (i = 0; i < node->numCols; i++)
607                 appendStringInfo(str, "%d ", (int) node->uniqColIdx[i]);
608 }
609
610 static void
611 _outSetOp(StringInfo str, SetOp *node)
612 {
613         int             i;
614
615         appendStringInfo(str, " SETOP ");
616         _outPlanInfo(str, (Plan *) node);
617
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);
624 }
625
626 static void
627 _outLimit(StringInfo str, Limit *node)
628 {
629         appendStringInfo(str, " LIMIT ");
630         _outPlanInfo(str, (Plan *) node);
631
632         appendStringInfo(str, " :limitOffset ");
633         _outNode(str, node->limitOffset);
634         appendStringInfo(str, " :limitCount ");
635         _outNode(str, node->limitCount);
636 }
637
638 /*
639  *      Hash is a subclass of Plan
640  */
641 static void
642 _outHash(StringInfo str, Hash *node)
643 {
644         appendStringInfo(str, " HASH ");
645         _outPlanInfo(str, (Plan *) node);
646
647         appendStringInfo(str, " :hashkey ");
648         _outNode(str, node->hashkey);
649 }
650
651 /*****************************************************************************
652  *
653  *      Stuff from primnodes.h.
654  *
655  *****************************************************************************/
656
657 /*
658  *      Resdom is a subclass of Node
659  */
660 static void
661 _outResdom(StringInfo str, Resdom *node)
662 {
663         appendStringInfo(str,
664                                  " RESDOM :resno %d :restype %u :restypmod %d :resname ",
665                                          node->resno,
666                                          node->restype,
667                                          node->restypmod);
668         _outToken(str, node->resname);
669         appendStringInfo(str, " :reskey %d :reskeyop %u :ressortgroupref %d :resjunk %s ",
670                                          node->reskey,
671                                          node->reskeyop,
672                                          node->ressortgroupref,
673                                          node->resjunk ? "true" : "false");
674 }
675
676 static void
677 _outFjoin(StringInfo str, Fjoin *node)
678 {
679         int                     i;
680
681         appendStringInfo(str, " FJOIN :initialized %s :nNodes %d ",
682                                          node->fj_initialized ? "true" : "false",
683                                          node->fj_nNodes);
684
685         appendStringInfo(str, " :innerNode ");
686         _outNode(str, node->fj_innerNode);
687
688         appendStringInfo(str, " :results @ 0x%x :alwaysdone",
689                                          (int) node->fj_results);
690
691         for (i = 0; i < node->fj_nNodes; i++)
692                 appendStringInfo(str, (node->fj_alwaysDone[i]) ? "true" : "false");
693 }
694
695 /*
696  *      Expr is a subclass of Node
697  */
698 static void
699 _outExpr(StringInfo str, Expr *node)
700 {
701         char       *opstr = NULL;
702
703         appendStringInfo(str, " EXPR :typeOid %u ",
704                                          node->typeOid);
705
706         switch (node->opType)
707         {
708                 case OP_EXPR:
709                         opstr = "op";
710                         break;
711                 case FUNC_EXPR:
712                         opstr = "func";
713                         break;
714                 case OR_EXPR:
715                         opstr = "or";
716                         break;
717                 case AND_EXPR:
718                         opstr = "and";
719                         break;
720                 case NOT_EXPR:
721                         opstr = "not";
722                         break;
723                 case SUBPLAN_EXPR:
724                         opstr = "subp";
725                         break;
726         }
727         appendStringInfo(str, " :opType ");
728         _outToken(str, opstr);
729         appendStringInfo(str, " :oper ");
730         _outNode(str, node->oper);
731
732         appendStringInfo(str, " :args ");
733         _outNode(str, node->args);
734 }
735
736 /*
737  *      Var is a subclass of Expr
738  */
739 static void
740 _outVar(StringInfo str, Var *node)
741 {
742         appendStringInfo(str,
743                                 " VAR :varno %d :varattno %d :vartype %u :vartypmod %d ",
744                                          node->varno,
745                                          node->varattno,
746                                          node->vartype,
747                                          node->vartypmod);
748
749         appendStringInfo(str, " :varlevelsup %u :varnoold %d :varoattno %d",
750                                          node->varlevelsup,
751                                          node->varnoold,
752                                          node->varoattno);
753 }
754
755 /*
756  *      Const is a subclass of Expr
757  */
758 static void
759 _outConst(StringInfo str, Const *node)
760 {
761         appendStringInfo(str,
762                 " CONST :consttype %u :constlen %d :constisnull %s :constvalue ",
763                                          node->consttype,
764                                          node->constlen,
765                                          node->constisnull ? "true" : "false");
766
767         if (node->constisnull)
768                 appendStringInfo(str, "<>");
769         else
770                 _outDatum(str, node->constvalue, node->consttype);
771
772         appendStringInfo(str, " :constbyval %s ",
773                                          node->constbyval ? "true" : "false");
774 }
775
776 /*
777  *      Aggref
778  */
779 static void
780 _outAggref(StringInfo str, Aggref *node)
781 {
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);
787
788         appendStringInfo(str, " :aggstar %s :aggdistinct %s ",
789                                          node->aggstar ? "true" : "false",
790                                          node->aggdistinct ? "true" : "false");
791         /* aggno is not dumped */
792 }
793
794 /*
795  *      SubLink
796  */
797 static void
798 _outSubLink(StringInfo str, SubLink *node)
799 {
800         appendStringInfo(str,
801                                          " SUBLINK :subLinkType %d :useor %s :lefthand ",
802                                          node->subLinkType,
803                                          node->useor ? "true" : "false");
804         _outNode(str, node->lefthand);
805
806         appendStringInfo(str, " :oper ");
807         _outNode(str, node->oper);
808
809         appendStringInfo(str, " :subselect ");
810         _outNode(str, node->subselect);
811 }
812
813 /*
814  *      ArrayRef is a subclass of Expr
815  */
816 static void
817 _outArrayRef(StringInfo str, ArrayRef *node)
818 {
819         appendStringInfo(str,
820                 " ARRAYREF :refelemtype %u :refattrlength %d :refelemlength %d ",
821                                          node->refelemtype,
822                                          node->refattrlength,
823                                          node->refelemlength);
824
825         appendStringInfo(str, " :refelembyval %c :refupperindex ",
826                                          node->refelembyval ? 't' : 'f');
827         _outNode(str, node->refupperindexpr);
828
829         appendStringInfo(str, " :reflowerindex ");
830         _outNode(str, node->reflowerindexpr);
831
832         appendStringInfo(str, " :refexpr ");
833         _outNode(str, node->refexpr);
834
835         appendStringInfo(str, " :refassgnexpr ");
836         _outNode(str, node->refassgnexpr);
837 }
838
839 /*
840  *      Func is a subclass of Expr
841  */
842 static void
843 _outFunc(StringInfo str, Func *node)
844 {
845         appendStringInfo(str, " FUNC :funcid %u :functype %u ",
846                                          node->funcid,
847                                          node->functype);
848 }
849
850 /*
851  *      Oper is a subclass of Expr
852  */
853 static void
854 _outOper(StringInfo str, Oper *node)
855 {
856         appendStringInfo(str,
857                                          " OPER :opno %u :opid %u :opresulttype %u ",
858                                          node->opno,
859                                          node->opid,
860                                          node->opresulttype);
861 }
862
863 /*
864  *      Param is a subclass of Expr
865  */
866 static void
867 _outParam(StringInfo str, Param *node)
868 {
869         appendStringInfo(str, " PARAM :paramkind %d :paramid %d :paramname ",
870                                          node->paramkind,
871                                          node->paramid);
872         _outToken(str, node->paramname);
873         appendStringInfo(str, " :paramtype %u ", node->paramtype);
874 }
875
876 /*
877  *      FieldSelect
878  */
879 static void
880 _outFieldSelect(StringInfo str, FieldSelect *node)
881 {
882         appendStringInfo(str, " FIELDSELECT :arg ");
883         _outNode(str, node->arg);
884
885         appendStringInfo(str, " :fieldnum %d :resulttype %u :resulttypmod %d ",
886                                          node->fieldnum, node->resulttype, node->resulttypmod);
887 }
888
889 /*
890  *      RelabelType
891  */
892 static void
893 _outRelabelType(StringInfo str, RelabelType *node)
894 {
895         appendStringInfo(str, " RELABELTYPE :arg ");
896         _outNode(str, node->arg);
897
898         appendStringInfo(str, " :resulttype %u :resulttypmod %d ",
899                                          node->resulttype, node->resulttypmod);
900 }
901
902 /*
903  *      RangeTblRef
904  */
905 static void
906 _outRangeTblRef(StringInfo str, RangeTblRef *node)
907 {
908         appendStringInfo(str, " RANGETBLREF %d ",
909                                          node->rtindex);
910 }
911
912 /*
913  *      FromExpr
914  */
915 static void
916 _outFromExpr(StringInfo str, FromExpr *node)
917 {
918         appendStringInfo(str, " FROMEXPR :fromlist ");
919         _outNode(str, node->fromlist);
920         appendStringInfo(str, " :quals ");
921         _outNode(str, node->quals);
922 }
923
924 /*
925  *      JoinExpr
926  */
927 static void
928 _outJoinExpr(StringInfo str, JoinExpr *node)
929 {
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);
946 }
947
948 /*
949  *      Stuff from execnodes.h
950  */
951
952 /*
953  *      EState is a subclass of Node.
954  */
955 static void
956 _outEState(StringInfo str, EState *node)
957 {
958         appendStringInfo(str,
959                                          " ESTATE :direction %d :range_table ",
960                                          node->es_direction);
961         _outNode(str, node->es_range_table);
962
963         appendStringInfo(str, " :result_relation_info @ 0x%x ",
964                                          (int) (node->es_result_relation_info));
965 }
966
967 /*
968  *      Stuff from relation.h
969  */
970
971 static void
972 _outRelOptInfo(StringInfo str, RelOptInfo *node)
973 {
974         appendStringInfo(str, " RELOPTINFO :relids ");
975         _outIntList(str, node->relids);
976
977         appendStringInfo(str, " :rows %.0f :width %d :targetlist ",
978                                          node->rows,
979                                          node->width);
980         _outNode(str, node->targetlist);
981
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);
988
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",
993                                          node->pages,
994                                          node->tuples);
995         _outNode(str, node->subplan);
996
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);
1006 }
1007
1008 static void
1009 _outIndexOptInfo(StringInfo str, IndexOptInfo *node)
1010 {
1011         appendStringInfo(str, " INDEXOPTINFO :indexoid %u :pages %ld :tuples %g ",
1012                                          node->indexoid,
1013                                          node->pages,
1014                                          node->tuples);
1015 }
1016
1017 /*
1018  *      TargetEntry is a subclass of Node.
1019  */
1020 static void
1021 _outTargetEntry(StringInfo str, TargetEntry *node)
1022 {
1023         appendStringInfo(str, " TARGETENTRY :resdom ");
1024         _outNode(str, node->resdom);
1025
1026         appendStringInfo(str, " :expr ");
1027         _outNode(str, node->expr);
1028 }
1029
1030 static void
1031 _outRangeTblEntry(StringInfo str, RangeTblEntry *node)
1032 {
1033         appendStringInfo(str, " RTE :relname ");
1034         _outToken(str, node->relname);
1035         appendStringInfo(str, " :relid %u ",
1036                                          node->relid);
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",
1049                                          node->checkAsUser);
1050 }
1051
1052 /*
1053  *      Path is a subclass of Node.
1054  */
1055 static void
1056 _outPath(StringInfo str, Path *node)
1057 {
1058         appendStringInfo(str,
1059          " PATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
1060                                          node->pathtype,
1061                                          node->startup_cost,
1062                                          node->total_cost);
1063         _outNode(str, node->pathkeys);
1064 }
1065
1066 /*
1067  *      IndexPath is a subclass of Path.
1068  */
1069 static void
1070 _outIndexPath(StringInfo str, IndexPath *node)
1071 {
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);
1078
1079         appendStringInfo(str, " :indexid ");
1080         _outIntList(str, node->indexid);
1081
1082         appendStringInfo(str, " :indexqual ");
1083         _outNode(str, node->indexqual);
1084
1085         appendStringInfo(str, " :indexscandir %d :joinrelids ",
1086                                          (int) node->indexscandir);
1087         _outIntList(str, node->joinrelids);
1088
1089         appendStringInfo(str, " :alljoinquals %s :rows %.2f ",
1090                                          node->alljoinquals ? "true" : "false",
1091                                          node->rows);
1092 }
1093
1094 /*
1095  *      TidPath is a subclass of Path.
1096  */
1097 static void
1098 _outTidPath(StringInfo str, TidPath *node)
1099 {
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);
1106
1107         appendStringInfo(str, " :tideval ");
1108         _outNode(str, node->tideval);
1109
1110         appendStringInfo(str, " :un joined_relids ");
1111         _outIntList(str, node->unjoined_relids);
1112 }
1113
1114 /*
1115  *      NestPath is a subclass of Path
1116  */
1117 static void
1118 _outNestPath(StringInfo str, NestPath *node)
1119 {
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);
1133 }
1134
1135 /*
1136  *      MergePath is a subclass of NestPath.
1137  */
1138 static void
1139 _outMergePath(StringInfo str, MergePath *node)
1140 {
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);
1154
1155         appendStringInfo(str, " :path_mergeclauses ");
1156         _outNode(str, node->path_mergeclauses);
1157
1158         appendStringInfo(str, " :outersortkeys ");
1159         _outNode(str, node->outersortkeys);
1160
1161         appendStringInfo(str, " :innersortkeys ");
1162         _outNode(str, node->innersortkeys);
1163 }
1164
1165 /*
1166  *      HashPath is a subclass of NestPath.
1167  */
1168 static void
1169 _outHashPath(StringInfo str, HashPath *node)
1170 {
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);
1184
1185         appendStringInfo(str, " :path_hashclauses ");
1186         _outNode(str, node->path_hashclauses);
1187 }
1188
1189 /*
1190  *      PathKeyItem is a subclass of Node.
1191  */
1192 static void
1193 _outPathKeyItem(StringInfo str, PathKeyItem *node)
1194 {
1195         appendStringInfo(str, " PATHKEYITEM :sortop %u :key ",
1196                                          node->sortop);
1197         _outNode(str, node->key);
1198 }
1199
1200 /*
1201  *      RestrictInfo is a subclass of Node.
1202  */
1203 static void
1204 _outRestrictInfo(StringInfo str, RestrictInfo *node)
1205 {
1206         appendStringInfo(str, " RESTRICTINFO :clause ");
1207         _outNode(str, node->clause);
1208
1209         appendStringInfo(str, " :ispusheddown %s :subclauseindices ",
1210                                          node->ispusheddown ? "true" : "false");
1211         _outNode(str, node->subclauseindices);
1212
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);
1217 }
1218
1219 /*
1220  *      JoinInfo is a subclass of Node.
1221  */
1222 static void
1223 _outJoinInfo(StringInfo str, JoinInfo *node)
1224 {
1225         appendStringInfo(str, " JINFO :unjoined_relids ");
1226         _outIntList(str, node->unjoined_relids);
1227
1228         appendStringInfo(str, " :jinfo_restrictinfo ");
1229         _outNode(str, node->jinfo_restrictinfo);
1230 }
1231
1232 /*
1233  * Print the value of a Datum given its type.
1234  */
1235 static void
1236 _outDatum(StringInfo str, Datum value, Oid type)
1237 {
1238         bool            byValue;
1239         int                     typeLength;
1240         Size            length;
1241         char       *s;
1242         int                     i;
1243
1244         /*
1245          * find some information about the type and the "real" length of the
1246          * datum.
1247          */
1248         byValue = get_typbyval(type);
1249         typeLength = get_typlen(type);
1250         length = datumGetSize(value, byValue, typeLength);
1251
1252         if (byValue)
1253         {
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, "] ");
1259         }
1260         else
1261         {                                                       /* !byValue */
1262                 s = (char *) DatumGetPointer(value);
1263                 if (!PointerIsValid(s))
1264                         appendStringInfo(str, " 0 [ ] ");
1265                 else
1266                 {
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, "] ");
1271                 }
1272         }
1273 }
1274
1275 static void
1276 _outIter(StringInfo str, Iter *node)
1277 {
1278         appendStringInfo(str, " ITER :iterexpr ");
1279         _outNode(str, node->iterexpr);
1280 }
1281
1282 static void
1283 _outStream(StringInfo str, Stream *node)
1284 {
1285         appendStringInfo(str,
1286                                          " STREAM :pathptr @ 0x%x :cinfo @ 0x%x :clausetype %d :upstream @ 0x%x ",
1287                                          (int) node->pathptr,
1288                                          (int) node->cinfo,
1289                                          (int) node->clausetype,
1290                                          (int) node->upstream);
1291
1292         appendStringInfo(str,
1293                    " :downstream @ 0x%x :groupup %d :groupcost %f :groupsel %f ",
1294                                          (int) node->downstream,
1295                                          node->groupup,
1296                                          node->groupcost,
1297                                          node->groupsel);
1298 }
1299
1300 static void
1301 _outAExpr(StringInfo str, A_Expr *node)
1302 {
1303         appendStringInfo(str, " AEXPR ");
1304         switch (node->oper)
1305         {
1306                 case AND:
1307                         appendStringInfo(str, "AND ");
1308                         break;
1309                 case OR:
1310                         appendStringInfo(str, "OR ");
1311                         break;
1312                 case NOT:
1313                         appendStringInfo(str, "NOT ");
1314                         break;
1315                 case ISNULL:
1316                         appendStringInfo(str, "ISNULL ");
1317                         break;
1318                 case NOTNULL:
1319                         appendStringInfo(str, "NOTNULL ");
1320                         break;
1321                 case OP:
1322                         _outToken(str, node->opname);
1323                         appendStringInfo(str, " ");
1324                         break;
1325                 default:
1326                         appendStringInfo(str, "?? ");
1327                         break;
1328         }
1329         _outNode(str, node->lexpr);
1330         appendStringInfo(str, " ");
1331         _outNode(str, node->rexpr);
1332 }
1333
1334 static void
1335 _outValue(StringInfo str, Value *value)
1336 {
1337         switch (value->type)
1338         {
1339                         case T_Integer:
1340                         appendStringInfo(str, " %ld ", value->val.ival);
1341                         break;
1342                 case T_Float:
1343
1344                         /*
1345                          * We assume the value is a valid numeric literal and so does
1346                          * not need quoting.
1347                          */
1348                         appendStringInfo(str, " %s ", value->val.str);
1349                         break;
1350                 case T_String:
1351                         appendStringInfo(str, " \"");
1352                         _outToken(str, value->val.str);
1353                         appendStringInfo(str, "\" ");
1354                         break;
1355                 default:
1356                         elog(NOTICE, "_outValue: don't know how to print type %d ",
1357                                  value->type);
1358                         break;
1359         }
1360 }
1361
1362 static void
1363 _outIdent(StringInfo str, Ident *node)
1364 {
1365         appendStringInfo(str, " IDENT ");
1366         _outToken(str, node->name);
1367 }
1368
1369 static void
1370 _outAttr(StringInfo str, Attr *node)
1371 {
1372         appendStringInfo(str, " ATTR :relname ");
1373         _outToken(str, node->relname);
1374         appendStringInfo(str, " :attrs ");
1375         _outNode(str, node->attrs);
1376 }
1377
1378 static void
1379 _outAConst(StringInfo str, A_Const *node)
1380 {
1381         appendStringInfo(str, "CONST ");
1382         _outValue(str, &(node->val));
1383         appendStringInfo(str, " :typename ");
1384         _outNode(str, node->typename);
1385 }
1386
1387 static void
1388 _outConstraint(StringInfo str, Constraint *node)
1389 {
1390         appendStringInfo(str, " ");
1391         _outToken(str, node->name);
1392         appendStringInfo(str, " :type ");
1393
1394         switch (node->contype)
1395         {
1396                 case CONSTR_PRIMARY:
1397                         appendStringInfo(str, "PRIMARY KEY ");
1398                         _outNode(str, node->keys);
1399                         break;
1400
1401                 case CONSTR_CHECK:
1402                         appendStringInfo(str, "CHECK :raw ");
1403                         _outNode(str, node->raw_expr);
1404                         appendStringInfo(str, " :cooked ");
1405                         _outToken(str, node->cooked_expr);
1406                         break;
1407
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);
1413                         break;
1414
1415                 case CONSTR_NOTNULL:
1416                         appendStringInfo(str, "NOT NULL");
1417                         break;
1418
1419                 case CONSTR_UNIQUE:
1420                         appendStringInfo(str, "UNIQUE ");
1421                         _outNode(str, node->keys);
1422                         break;
1423
1424                 default:
1425                         appendStringInfo(str, "<unrecognized_constraint>");
1426                         break;
1427         }
1428 }
1429
1430 static void
1431 _outCaseExpr(StringInfo str, CaseExpr *node)
1432 {
1433         appendStringInfo(str, " CASE :casetype %u :arg ",
1434                                          node->casetype);
1435         _outNode(str, node->arg);
1436
1437         appendStringInfo(str, " :args ");
1438         _outNode(str, node->args);
1439
1440         appendStringInfo(str, " :defresult ");
1441         _outNode(str, node->defresult);
1442 }
1443
1444 static void
1445 _outCaseWhen(StringInfo str, CaseWhen *node)
1446 {
1447         appendStringInfo(str, " WHEN ");
1448         _outNode(str, node->expr);
1449
1450         appendStringInfo(str, " :then ");
1451         _outNode(str, node->result);
1452 }
1453
1454 /*
1455  * _outNode -
1456  *        converts a Node into ascii string and append it to 'str'
1457  */
1458 static void
1459 _outNode(StringInfo str, void *obj)
1460 {
1461         if (obj == NULL)
1462         {
1463                 appendStringInfo(str, "<>");
1464                 return;
1465         }
1466
1467         if (IsA(obj, List))
1468         {
1469                 List       *l;
1470
1471                 appendStringInfoChar(str, '(');
1472                 foreach(l, (List *) obj)
1473                 {
1474                         _outNode(str, lfirst(l));
1475                         if (lnext(l))
1476                                 appendStringInfoChar(str, ' ');
1477                 }
1478                 appendStringInfoChar(str, ')');
1479         }
1480         else if (IsA_Value(obj))
1481         {
1482                 /* nodeRead does not want to see { } around these! */
1483                 _outValue(str, obj);
1484         }
1485         else
1486         {
1487                 appendStringInfoChar(str, '{');
1488                 switch (nodeTag(obj))
1489                 {
1490                         case T_CreateStmt:
1491                                 _outCreateStmt(str, obj);
1492                                 break;
1493                         case T_IndexStmt:
1494                                 _outIndexStmt(str, obj);
1495                                 break;
1496                         case T_ColumnDef:
1497                                 _outColumnDef(str, obj);
1498                                 break;
1499                         case T_TypeName:
1500                                 _outTypeName(str, obj);
1501                                 break;
1502                         case T_TypeCast:
1503                                 _outTypeCast(str, obj);
1504                                 break;
1505                         case T_IndexElem:
1506                                 _outIndexElem(str, obj);
1507                                 break;
1508                         case T_Query:
1509                                 _outQuery(str, obj);
1510                                 break;
1511                         case T_SortClause:
1512                                 _outSortClause(str, obj);
1513                                 break;
1514                         case T_GroupClause:
1515                                 _outGroupClause(str, obj);
1516                                 break;
1517                         case T_SetOperationStmt:
1518                                 _outSetOperationStmt(str, obj);
1519                                 break;
1520                         case T_Plan:
1521                                 _outPlan(str, obj);
1522                                 break;
1523                         case T_Result:
1524                                 _outResult(str, obj);
1525                                 break;
1526                         case T_Append:
1527                                 _outAppend(str, obj);
1528                                 break;
1529                         case T_Join:
1530                                 _outJoin(str, obj);
1531                                 break;
1532                         case T_NestLoop:
1533                                 _outNestLoop(str, obj);
1534                                 break;
1535                         case T_MergeJoin:
1536                                 _outMergeJoin(str, obj);
1537                                 break;
1538                         case T_HashJoin:
1539                                 _outHashJoin(str, obj);
1540                                 break;
1541                         case T_Scan:
1542                                 _outScan(str, obj);
1543                                 break;
1544                         case T_SeqScan:
1545                                 _outSeqScan(str, obj);
1546                                 break;
1547                         case T_IndexScan:
1548                                 _outIndexScan(str, obj);
1549                                 break;
1550                         case T_TidScan:
1551                                 _outTidScan(str, obj);
1552                                 break;
1553                         case T_SubqueryScan:
1554                                 _outSubqueryScan(str, obj);
1555                                 break;
1556                         case T_Material:
1557                                 _outMaterial(str, obj);
1558                                 break;
1559                         case T_Sort:
1560                                 _outSort(str, obj);
1561                                 break;
1562                         case T_Agg:
1563                                 _outAgg(str, obj);
1564                                 break;
1565                         case T_Group:
1566                                 _outGroup(str, obj);
1567                                 break;
1568                         case T_Unique:
1569                                 _outUnique(str, obj);
1570                                 break;
1571                         case T_SetOp:
1572                                 _outSetOp(str, obj);
1573                                 break;
1574                         case T_Limit:
1575                                 _outLimit(str, obj);
1576                                 break;
1577                         case T_Hash:
1578                                 _outHash(str, obj);
1579                                 break;
1580                         case T_SubPlan:
1581                                 _outSubPlan(str, obj);
1582                                 break;
1583                         case T_Resdom:
1584                                 _outResdom(str, obj);
1585                                 break;
1586                         case T_Fjoin:
1587                                 _outFjoin(str, obj);
1588                                 break;
1589                         case T_Expr:
1590                                 _outExpr(str, obj);
1591                                 break;
1592                         case T_Var:
1593                                 _outVar(str, obj);
1594                                 break;
1595                         case T_Const:
1596                                 _outConst(str, obj);
1597                                 break;
1598                         case T_Aggref:
1599                                 _outAggref(str, obj);
1600                                 break;
1601                         case T_SubLink:
1602                                 _outSubLink(str, obj);
1603                                 break;
1604                         case T_ArrayRef:
1605                                 _outArrayRef(str, obj);
1606                                 break;
1607                         case T_Func:
1608                                 _outFunc(str, obj);
1609                                 break;
1610                         case T_Oper:
1611                                 _outOper(str, obj);
1612                                 break;
1613                         case T_Param:
1614                                 _outParam(str, obj);
1615                                 break;
1616                         case T_FieldSelect:
1617                                 _outFieldSelect(str, obj);
1618                                 break;
1619                         case T_RelabelType:
1620                                 _outRelabelType(str, obj);
1621                                 break;
1622                         case T_RangeTblRef:
1623                                 _outRangeTblRef(str, obj);
1624                                 break;
1625                         case T_FromExpr:
1626                                 _outFromExpr(str, obj);
1627                                 break;
1628                         case T_JoinExpr:
1629                                 _outJoinExpr(str, obj);
1630                                 break;
1631                         case T_EState:
1632                                 _outEState(str, obj);
1633                                 break;
1634                         case T_RelOptInfo:
1635                                 _outRelOptInfo(str, obj);
1636                                 break;
1637                         case T_IndexOptInfo:
1638                                 _outIndexOptInfo(str, obj);
1639                                 break;
1640                         case T_TargetEntry:
1641                                 _outTargetEntry(str, obj);
1642                                 break;
1643                         case T_RangeTblEntry:
1644                                 _outRangeTblEntry(str, obj);
1645                                 break;
1646                         case T_Path:
1647                                 _outPath(str, obj);
1648                                 break;
1649                         case T_IndexPath:
1650                                 _outIndexPath(str, obj);
1651                                 break;
1652                         case T_TidPath:
1653                                 _outTidPath(str, obj);
1654                                 break;
1655                         case T_NestPath:
1656                                 _outNestPath(str, obj);
1657                                 break;
1658                         case T_MergePath:
1659                                 _outMergePath(str, obj);
1660                                 break;
1661                         case T_HashPath:
1662                                 _outHashPath(str, obj);
1663                                 break;
1664                         case T_PathKeyItem:
1665                                 _outPathKeyItem(str, obj);
1666                                 break;
1667                         case T_RestrictInfo:
1668                                 _outRestrictInfo(str, obj);
1669                                 break;
1670                         case T_JoinInfo:
1671                                 _outJoinInfo(str, obj);
1672                                 break;
1673                         case T_Iter:
1674                                 _outIter(str, obj);
1675                                 break;
1676                         case T_Stream:
1677                                 _outStream(str, obj);
1678                                 break;
1679                         case T_A_Expr:
1680                                 _outAExpr(str, obj);
1681                                 break;
1682                         case T_Ident:
1683                                 _outIdent(str, obj);
1684                                 break;
1685                         case T_A_Const:
1686                                 _outAConst(str, obj);
1687                                 break;
1688                         case T_Constraint:
1689                                 _outConstraint(str, obj);
1690                                 break;
1691                         case T_CaseExpr:
1692                                 _outCaseExpr(str, obj);
1693                                 break;
1694                         case T_CaseWhen:
1695                                 _outCaseWhen(str, obj);
1696                                 break;
1697
1698                         case T_VariableSetStmt:
1699                                 break;
1700                         case T_SelectStmt:
1701                                 _outSelectStmt(str, obj);
1702                                 break;
1703                         case T_FuncCall:
1704                                 _outFuncCall(str, obj);
1705                                 break;
1706                         case T_Attr:
1707                                 _outAttr(str, obj);
1708                                 break;
1709
1710                         default:
1711                                 elog(NOTICE, "_outNode: don't know how to print type %d ",
1712                                          nodeTag(obj));
1713                                 break;
1714                 }
1715                 appendStringInfoChar(str, '}');
1716         }
1717 }
1718
1719 /*
1720  * nodeToString -
1721  *         returns the ascii representation of the Node as a palloc'd string
1722  */
1723 char *
1724 nodeToString(void *obj)
1725 {
1726         StringInfoData str;
1727
1728         /* see stringinfo.h for an explanation of this maneuver */
1729         initStringInfo(&str);
1730         _outNode(&str, obj);
1731         return str.data;
1732 }