outfuncs.c 40.4 KB
Newer Older
M
 
Marc G. Fournier 已提交
1
/*
2
 * outfuncs.c
3
 *	  routines to convert a node to ascii representation
4
 *
B
Bruce Momjian 已提交
5
 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
B
Add:  
Bruce Momjian 已提交
6
 * Portions Copyright (c) 1994, Regents of the University of California
7
 *
8
 *	$Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.161 2002/07/04 15:23:53 thomas Exp $
9 10
 *
 * NOTES
11 12 13
 *	  Every (plan) node in POSTGRES has an associated "out" routine which
 *	  knows how to create its ascii representation. These functions are
 *	  useful for debugging as well as for storing plans in the system
14
 *	  catalogs (eg. views).
15
 */
16
#include "postgres.h"
17

18 19
#include <ctype.h>

B
Bruce Momjian 已提交
20 21 22
#include "lib/stringinfo.h"
#include "nodes/nodes.h"
#include "nodes/parsenodes.h"
23 24 25
#include "nodes/plannodes.h"
#include "nodes/primnodes.h"
#include "nodes/relation.h"
26
#include "parser/parse.h"
B
Bruce Momjian 已提交
27
#include "utils/datum.h"
28

29

30 31
#define booltostr(x)  ((x) ? "true" : "false")

32
static void _outDatum(StringInfo str, Datum value, int typlen, bool typbyval);
33
static void _outNode(StringInfo str, void *obj);
34

35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
/*
 * _outToken
 *	  Convert an ordinary string (eg, an identifier) into a form that
 *	  will be decoded back to a plain token by read.c's functions.
 *
 *	  If a null or empty string is given, it is encoded as "<>".
 */
static void
_outToken(StringInfo str, char *s)
{
	if (s == NULL || *s == '\0')
	{
		appendStringInfo(str, "<>");
		return;
	}
50

51 52
	/*
	 * Look for characters or patterns that are treated specially by
53 54
	 * read.c (either in pg_strtok() or in nodeRead()), and therefore need
	 * a protective backslash.
55 56 57 58 59
	 */
	/* These characters only need to be quoted at the start of the string */
	if (*s == '<' ||
		*s == '\"' ||
		*s == '@' ||
60
		isdigit((unsigned char) *s) ||
61 62
		((*s == '+' || *s == '-') &&
		 (isdigit((unsigned char) s[1]) || s[1] == '.')))
63 64 65 66 67 68 69 70 71 72 73
		appendStringInfoChar(str, '\\');
	while (*s)
	{
		/* These chars must be backslashed anywhere in the string */
		if (*s == ' ' || *s == '\n' || *s == '\t' ||
			*s == '(' || *s == ')' || *s == '{' || *s == '}' ||
			*s == '\\')
			appendStringInfoChar(str, '\\');
		appendStringInfoChar(str, *s++);
	}
}
74

75 76
/*
 * _outIntList -
77
 *	   converts a List of integers
78
 */
79
static void
80
_outIntList(StringInfo str, List *list)
81
{
B
Bruce Momjian 已提交
82
	List	   *l;
83

84
	appendStringInfoChar(str, '(');
85
	foreach(l, list)
86 87
		appendStringInfo(str, " %d", lfirsti(l));
	appendStringInfoChar(str, ')');
88 89
}

90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
/*
 * _outOidList -
 *	   converts a List of OIDs
 */
static void
_outOidList(StringInfo str, List *list)
{
	List	   *l;

	appendStringInfoChar(str, '(');
	foreach(l, list)
		appendStringInfo(str, " %u", (Oid) lfirsti(l));
	appendStringInfoChar(str, ')');
}

105 106 107
static void
_outCreateStmt(StringInfo str, CreateStmt *node)
{
108 109
	appendStringInfo(str, " CREATE :relation ");
	_outNode(str, node->relation);
110

111
	appendStringInfo(str, "	:tableElts ");
112
	_outNode(str, node->tableElts);
M
 
Marc G. Fournier 已提交
113

114 115
	appendStringInfo(str, " :inhRelations ");
	_outNode(str, node->inhRelations);
M
 
Marc G. Fournier 已提交
116

117
	appendStringInfo(str, " :constraints ");
118
	_outNode(str, node->constraints);
119

120
	appendStringInfo(str, " :hasoids %s ",
121
					 booltostr(node->hasoids));
122
}
123 124 125 126

static void
_outIndexStmt(StringInfo str, IndexStmt *node)
{
127 128
	appendStringInfo(str, " INDEX :idxname ");
	_outToken(str, node->idxname);
129 130
	appendStringInfo(str, " :relation ");
	_outNode(str, node->relation);
131 132 133
	appendStringInfo(str, " :accessMethod ");
	_outToken(str, node->accessMethod);
	appendStringInfo(str, " :indexParams ");
134
	_outNode(str, node->indexParams);
135 136 137 138
	appendStringInfo(str, " :whereClause ");
	_outNode(str, node->whereClause);
	appendStringInfo(str, " :rangetable ");
	_outNode(str, node->rangetable);
139
	appendStringInfo(str, " :unique %s :primary %s ",
140 141
					 booltostr(node->unique),
					 booltostr(node->primary));
142
}
143

144 145 146 147 148 149 150
static void
_outNotifyStmt(StringInfo str, NotifyStmt *node)
{
	appendStringInfo(str, "NOTIFY :relation ");
	_outNode(str, node->relation);
}

151 152 153
static void
_outSelectStmt(StringInfo str, SelectStmt *node)
{
154
	/* XXX this is pretty durn incomplete */
M
 
Marc G. Fournier 已提交
155
	appendStringInfo(str, "SELECT :where ");
156 157 158 159 160 161
	_outNode(str, node->whereClause);
}

static void
_outFuncCall(StringInfo str, FuncCall *node)
{
162
	appendStringInfo(str, "FUNCTION ");
163
	_outNode(str, node->funcname);
164
	appendStringInfo(str, " :args ");
165
	_outNode(str, node->args);
166
	appendStringInfo(str, " :agg_star %s :agg_distinct %s ",
167 168
					 booltostr(node->agg_star),
					 booltostr(node->agg_distinct));
169
}
170

171 172 173
static void
_outColumnDef(StringInfo str, ColumnDef *node)
{
174 175 176
	appendStringInfo(str, " COLUMNDEF :colname ");
	_outToken(str, node->colname);
	appendStringInfo(str, " :typename ");
177
	_outNode(str, node->typename);
178 179
	appendStringInfo(str, " :is_not_null %s :raw_default ",
					 booltostr(node->is_not_null));
180
	_outNode(str, node->raw_default);
181 182 183
	appendStringInfo(str, " :cooked_default ");
	_outToken(str, node->cooked_default);
	appendStringInfo(str, " :constraints ");
184
	_outNode(str, node->constraints);
185 186 187 188 189
}

static void
_outTypeName(StringInfo str, TypeName *node)
{
190 191 192 193 194
	appendStringInfo(str, " TYPENAME :names ");
	_outNode(str, node->names);
	appendStringInfo(str, " :typeid %u :timezone %s :setof %s"
					 " :pct_type %s typmod %d :arrayBounds ",
					 node->typeid,
195 196
					 booltostr(node->timezone),
					 booltostr(node->setof),
197
					 booltostr(node->pct_type),
B
Bruce Momjian 已提交
198
					 node->typmod);
199 200
	_outNode(str, node->arrayBounds);
}
201

202 203 204 205 206 207 208 209 210
static void
_outTypeCast(StringInfo str, TypeCast *node)
{
	appendStringInfo(str, " TYPECAST :arg ");
	_outNode(str, node->arg);
	appendStringInfo(str, " :typename ");
	_outNode(str, node->typename);
}

211 212 213
static void
_outIndexElem(StringInfo str, IndexElem *node)
{
214 215
	appendStringInfo(str, " INDEXELEM :name ");
	_outToken(str, node->name);
216 217
	appendStringInfo(str, " :funcname ");
	_outNode(str, node->funcname);
218
	appendStringInfo(str, " :args ");
219
	_outNode(str, node->args);
220 221
	appendStringInfo(str, " :opclass ");
	_outNode(str, node->opclass);
222
}
223

224
static void
225
_outQuery(StringInfo str, Query *node)
226
{
227
	appendStringInfo(str, " QUERY :command %d :utility ", node->commandType);
228

229 230 231 232 233 234 235
	/*
	 * Hack to work around missing outfuncs routines for a lot of the
	 * utility-statement node types.  (The only one we actually *need*
	 * for rules support is NotifyStmt.)  Someday we ought to support
	 * 'em all, but for the meantime do this to avoid getting lots of
	 * warnings when running with debug_print_parse on.
	 */
236 237 238 239 240 241 242
	if (node->utilityStmt)
	{
		switch (nodeTag(node->utilityStmt))
		{
			case T_CreateStmt:
			case T_IndexStmt:
			case T_NotifyStmt:
243
				_outNode(str, node->utilityStmt);
244 245
				break;
			default:
246 247
				appendStringInfo(str, "?");
				break;
248 249
		}
	}
250
	else
251
		appendStringInfo(str, "<>");
252

253
	appendStringInfo(str, " :resultRelation %d :into ",
254
					 node->resultRelation);
255
	_outNode(str, node->into);
256

257
	appendStringInfo(str, " :isPortal %s :isBinary %s"
258
					 " :hasAggs %s :hasSubLinks %s :rtable ",
259 260 261 262
					 booltostr(node->isPortal),
					 booltostr(node->isBinary),
					 booltostr(node->hasAggs),
					 booltostr(node->hasSubLinks));
263
	_outNode(str, node->rtable);
M
 
Marc G. Fournier 已提交
264

265 266 267
	appendStringInfo(str, " :jointree ");
	_outNode(str, node->jointree);

268 269 270
	appendStringInfo(str, " :rowMarks ");
	_outIntList(str, node->rowMarks);

271 272
	appendStringInfo(str, " :targetList ");
	_outNode(str, node->targetList);
M
 
Marc G. Fournier 已提交
273

274 275
	appendStringInfo(str, " :groupClause ");
	_outNode(str, node->groupClause);
M
 
Marc G. Fournier 已提交
276

277
	appendStringInfo(str, " :havingQual ");
278
	_outNode(str, node->havingQual);
M
 
Marc G. Fournier 已提交
279

280 281
	appendStringInfo(str, " :distinctClause ");
	_outNode(str, node->distinctClause);
B
Hi!  
Bruce Momjian 已提交
282

283 284
	appendStringInfo(str, " :sortClause ");
	_outNode(str, node->sortClause);
285

B
Bruce Momjian 已提交
286 287
	appendStringInfo(str, " :limitOffset ");
	_outNode(str, node->limitOffset);
M
 
Marc G. Fournier 已提交
288

B
Bruce Momjian 已提交
289 290
	appendStringInfo(str, " :limitCount ");
	_outNode(str, node->limitCount);
291 292 293

	appendStringInfo(str, " :setOperations ");
	_outNode(str, node->setOperations);
294 295 296

	appendStringInfo(str, " :resultRelations ");
	_outIntList(str, node->resultRelations);
297 298 299
}

static void
300
_outSortClause(StringInfo str, SortClause *node)
301
{
302
	appendStringInfo(str, " SORTCLAUSE :tleSortGroupRef %u :sortop %u ",
303
					 node->tleSortGroupRef, node->sortop);
304 305 306 307 308
}

static void
_outGroupClause(StringInfo str, GroupClause *node)
{
309
	appendStringInfo(str, " GROUPCLAUSE :tleSortGroupRef %u :sortop %u ",
310
					 node->tleSortGroupRef, node->sortop);
311 312
}

313 314 315 316 317
static void
_outSetOperationStmt(StringInfo str, SetOperationStmt *node)
{
	appendStringInfo(str, " SETOPERATIONSTMT :op %d :all %s :larg ",
					 (int) node->op,
318
					 booltostr(node->all));
319 320 321 322
	_outNode(str, node->larg);
	appendStringInfo(str, " :rarg ");
	_outNode(str, node->rarg);
	appendStringInfo(str, " :colTypes ");
323
	_outOidList(str, node->colTypes);
324 325
}

326 327
/*
 * print the basic stuff of all nodes that inherit from Plan
328 329
 *
 * NOTE: we deliberately omit the execution state (EState)
330 331
 */
static void
332
_outPlanInfo(StringInfo str, Plan *node)
333
{
B
Bruce Momjian 已提交
334
	appendStringInfo(str,
335
					 ":startup_cost %.2f :total_cost %.2f :rows %.0f :width %d :qptargetlist ",
336 337
					 node->startup_cost,
					 node->total_cost,
338
					 node->plan_rows,
339
					 node->plan_width);
340
	_outNode(str, node->targetlist);
M
 
Marc G. Fournier 已提交
341

342
	appendStringInfo(str, " :qpqual ");
343
	_outNode(str, node->qual);
M
 
Marc G. Fournier 已提交
344

345
	appendStringInfo(str, " :lefttree ");
346
	_outNode(str, node->lefttree);
M
 
Marc G. Fournier 已提交
347

348
	appendStringInfo(str, " :righttree ");
349
	_outNode(str, node->righttree);
M
 
Marc G. Fournier 已提交
350

V
Vadim B. Mikheev 已提交
351 352
	appendStringInfo(str, " :extprm ");
	_outIntList(str, node->extParam);
M
 
Marc G. Fournier 已提交
353

V
Vadim B. Mikheev 已提交
354 355
	appendStringInfo(str, " :locprm ");
	_outIntList(str, node->locParam);
M
 
Marc G. Fournier 已提交
356

V
Vadim B. Mikheev 已提交
357 358
	appendStringInfo(str, " :initplan ");
	_outNode(str, node->initPlan);
M
 
Marc G. Fournier 已提交
359

M
 
Marc G. Fournier 已提交
360
	appendStringInfo(str, " :nprm %d ", node->nParamExec);
361 362 363
}

/*
364
 *	Stuff from plannodes.h
365 366
 */
static void
367
_outPlan(StringInfo str, Plan *node)
368
{
369
	appendStringInfo(str, " PLAN ");
370
	_outPlanInfo(str, (Plan *) node);
371 372 373
}

static void
374
_outResult(StringInfo str, Result *node)
375
{
376
	appendStringInfo(str, " RESULT ");
377 378
	_outPlanInfo(str, (Plan *) node);

379
	appendStringInfo(str, " :resconstantqual ");
380 381
	_outNode(str, node->resconstantqual);

382 383 384
}

/*
385
 *	Append is a subclass of Plan.
386 387
 */
static void
B
Bruce Momjian 已提交
388
_outAppend(StringInfo str, Append *node)
389
{
390
	appendStringInfo(str, " APPEND ");
391 392
	_outPlanInfo(str, (Plan *) node);

393 394
	appendStringInfo(str, " :appendplans ");
	_outNode(str, node->appendplans);
395

396
	appendStringInfo(str, " :isTarget %s ",
397
					 booltostr(node->isTarget));
398 399 400
}

/*
401
 *	Join is a subclass of Plan
402 403
 */
static void
404
_outJoin(StringInfo str, Join *node)
405
{
406
	appendStringInfo(str, " JOIN ");
407
	_outPlanInfo(str, (Plan *) node);
408 409 410
	appendStringInfo(str, " :jointype %d :joinqual ",
					 (int) node->jointype);
	_outNode(str, node->joinqual);
411 412 413
}

/*
414
 *	NestLoop is a subclass of Join
415 416
 */
static void
417
_outNestLoop(StringInfo str, NestLoop *node)
418
{
419
	appendStringInfo(str, " NESTLOOP ");
420
	_outPlanInfo(str, (Plan *) node);
421 422 423
	appendStringInfo(str, " :jointype %d :joinqual ",
					 (int) node->join.jointype);
	_outNode(str, node->join.joinqual);
424 425 426
}

/*
427
 *	MergeJoin is a subclass of Join
428 429
 */
static void
430
_outMergeJoin(StringInfo str, MergeJoin *node)
431
{
432
	appendStringInfo(str, " MERGEJOIN ");
433
	_outPlanInfo(str, (Plan *) node);
434 435 436
	appendStringInfo(str, " :jointype %d :joinqual ",
					 (int) node->join.jointype);
	_outNode(str, node->join.joinqual);
437

438
	appendStringInfo(str, " :mergeclauses ");
439
	_outNode(str, node->mergeclauses);
440 441 442
}

/*
443
 *	HashJoin is a subclass of Join.
444 445
 */
static void
446
_outHashJoin(StringInfo str, HashJoin *node)
447
{
448
	appendStringInfo(str, " HASHJOIN ");
449
	_outPlanInfo(str, (Plan *) node);
450 451 452
	appendStringInfo(str, " :jointype %d :joinqual ",
					 (int) node->join.jointype);
	_outNode(str, node->join.joinqual);
453

454
	appendStringInfo(str, " :hashclauses ");
455
	_outNode(str, node->hashclauses);
456
	appendStringInfo(str, " :hashjoinop %u ",
B
Bruce Momjian 已提交
457
					 node->hashjoinop);
458 459
}

V
Vadim B. Mikheev 已提交
460 461 462
static void
_outSubPlan(StringInfo str, SubPlan *node)
{
M
 
Marc G. Fournier 已提交
463
	appendStringInfo(str, " SUBPLAN :plan ");
V
Vadim B. Mikheev 已提交
464
	_outNode(str, node->plan);
M
 
Marc G. Fournier 已提交
465

466
	appendStringInfo(str, " :planid %d :rtable ", node->plan_id);
V
Vadim B. Mikheev 已提交
467
	_outNode(str, node->rtable);
M
 
Marc G. Fournier 已提交
468

V
Vadim B. Mikheev 已提交
469
	appendStringInfo(str, " :setprm ");
470
	_outIntList(str, node->setParam);
M
 
Marc G. Fournier 已提交
471

V
Vadim B. Mikheev 已提交
472
	appendStringInfo(str, " :parprm ");
473
	_outIntList(str, node->parParam);
M
 
Marc G. Fournier 已提交
474

V
Vadim B. Mikheev 已提交
475 476 477 478
	appendStringInfo(str, " :slink ");
	_outNode(str, node->sublink);
}

479
/*
480
 *	Scan is a subclass of Node
481 482
 */
static void
483
_outScan(StringInfo str, Scan *node)
484
{
485
	appendStringInfo(str, " SCAN ");
486 487
	_outPlanInfo(str, (Plan *) node);

488
	appendStringInfo(str, " :scanrelid %u ", node->scanrelid);
489 490 491
}

/*
492
 *	SeqScan is a subclass of Scan
493 494
 */
static void
495
_outSeqScan(StringInfo str, SeqScan *node)
496
{
497
	appendStringInfo(str, " SEQSCAN ");
498 499
	_outPlanInfo(str, (Plan *) node);

500
	appendStringInfo(str, " :scanrelid %u ", node->scanrelid);
501 502 503
}

/*
504
 *	IndexScan is a subclass of Scan
505 506
 */
static void
507
_outIndexScan(StringInfo str, IndexScan *node)
508
{
509
	appendStringInfo(str, " INDEXSCAN ");
510 511
	_outPlanInfo(str, (Plan *) node);

512
	appendStringInfo(str, " :scanrelid %u :indxid ", node->scan.scanrelid);
513
	_outOidList(str, node->indxid);
514

515
	appendStringInfo(str, " :indxqual ");
516 517
	_outNode(str, node->indxqual);

V
Vadim B. Mikheev 已提交
518 519 520
	appendStringInfo(str, " :indxqualorig ");
	_outNode(str, node->indxqualorig);

521
	appendStringInfo(str, " :indxorderdir %d ", node->indxorderdir);
522 523
}

524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540
/*
 *	TidScan is a subclass of Scan
 */
static void
_outTidScan(StringInfo str, TidScan *node)
{
	appendStringInfo(str, " TIDSCAN ");
	_outPlanInfo(str, (Plan *) node);

	appendStringInfo(str, " :scanrelid %u ", node->scan.scanrelid);
	appendStringInfo(str, " :needrescan %d ", node->needRescan);

	appendStringInfo(str, " :tideval ");
	_outNode(str, node->tideval);

}

541 542 543 544 545 546 547 548 549 550 551 552 553
/*
 *	SubqueryScan is a subclass of Scan
 */
static void
_outSubqueryScan(StringInfo str, SubqueryScan *node)
{
	appendStringInfo(str, " SUBQUERYSCAN ");
	_outPlanInfo(str, (Plan *) node);

	appendStringInfo(str, " :scanrelid %u :subplan ", node->scan.scanrelid);
	_outNode(str, node->subplan);
}

554 555 556 557 558 559 560 561 562 563 564 565
/*
 *	FunctionScan is a subclass of Scan
 */
static void
_outFunctionScan(StringInfo str, FunctionScan *node)
{
	appendStringInfo(str, " FUNCTIONSCAN ");
	_outPlanInfo(str, (Plan *) node);

	appendStringInfo(str, " :scanrelid %u ", node->scan.scanrelid);
}

566
/*
567
 *	Material is a subclass of Plan
568 569 570 571 572 573 574 575
 */
static void
_outMaterial(StringInfo str, Material *node)
{
	appendStringInfo(str, " MATERIAL ");
	_outPlanInfo(str, (Plan *) node);
}

576
/*
577
 *	Sort is a subclass of Plan
578 579
 */
static void
580
_outSort(StringInfo str, Sort *node)
581
{
582
	appendStringInfo(str, " SORT ");
583
	_outPlanInfo(str, (Plan *) node);
584
	appendStringInfo(str, " :keycount %d ", node->keycount);
585 586 587
}

static void
B
Bruce Momjian 已提交
588
_outAgg(StringInfo str, Agg *node)
589
{
590
	appendStringInfo(str, " AGG ");
591
	_outPlanInfo(str, (Plan *) node);
592 593 594
}

static void
595
_outGroup(StringInfo str, Group *node)
596
{
597
	appendStringInfo(str, " GRP ");
598 599 600
	_outPlanInfo(str, (Plan *) node);

	/* the actual Group fields */
M
 
Marc G. Fournier 已提交
601
	appendStringInfo(str, " :numCols %d :tuplePerGroup %s ",
B
Bruce Momjian 已提交
602
					 node->numCols,
603
					 booltostr(node->tuplePerGroup));
604
}
605

606
static void
607
_outUnique(StringInfo str, Unique *node)
608
{
B
Bruce Momjian 已提交
609
	int			i;
610

611
	appendStringInfo(str, " UNIQUE ");
612 613
	_outPlanInfo(str, (Plan *) node);

614
	appendStringInfo(str, " :numCols %d :uniqColIdx ",
615
					 node->numCols);
616 617 618
	for (i = 0; i < node->numCols; i++)
		appendStringInfo(str, "%d ", (int) node->uniqColIdx[i]);
}
619

620 621 622
static void
_outSetOp(StringInfo str, SetOp *node)
{
B
Bruce Momjian 已提交
623
	int			i;
624 625 626 627 628 629 630 631 632 633 634 635

	appendStringInfo(str, " SETOP ");
	_outPlanInfo(str, (Plan *) node);

	appendStringInfo(str, " :cmd %d :numCols %d :dupColIdx ",
					 (int) node->cmd, node->numCols);
	for (i = 0; i < node->numCols; i++)
		appendStringInfo(str, "%d ", (int) node->dupColIdx[i]);
	appendStringInfo(str, " :flagColIdx %d ",
					 (int) node->flagColIdx);
}

636 637 638 639 640 641 642 643 644 645 646 647
static void
_outLimit(StringInfo str, Limit *node)
{
	appendStringInfo(str, " LIMIT ");
	_outPlanInfo(str, (Plan *) node);

	appendStringInfo(str, " :limitOffset ");
	_outNode(str, node->limitOffset);
	appendStringInfo(str, " :limitCount ");
	_outNode(str, node->limitCount);
}

648
/*
649
 *	Hash is a subclass of Plan
650 651
 */
static void
652
_outHash(StringInfo str, Hash *node)
653
{
654
	appendStringInfo(str, " HASH ");
655 656
	_outPlanInfo(str, (Plan *) node);

657
	appendStringInfo(str, " :hashkey ");
658
	_outNode(str, node->hashkey);
659 660 661 662
}

/*****************************************************************************
 *
663
 *	Stuff from primnodes.h.
664 665 666 667
 *
 *****************************************************************************/

/*
668
 *	Resdom is a subclass of Node
669 670
 */
static void
671
_outResdom(StringInfo str, Resdom *node)
672
{
673
	appendStringInfo(str,
674
				 " RESDOM :resno %d :restype %u :restypmod %d :resname ",
B
Bruce Momjian 已提交
675 676 677
					 node->resno,
					 node->restype,
					 node->restypmod);
678
	_outToken(str, node->resname);
679
	appendStringInfo(str, " :reskey %u :reskeyop %u :ressortgroupref %u :resjunk %s ",
B
Bruce Momjian 已提交
680
					 node->reskey,
681
					 node->reskeyop,
682
					 node->ressortgroupref,
683
					 booltostr(node->resjunk));
684 685 686
}

static void
687
_outFjoin(StringInfo str, Fjoin *node)
688
{
689
	int			i;
690

M
 
Marc G. Fournier 已提交
691
	appendStringInfo(str, " FJOIN :initialized %s :nNodes %d ",
692
					 booltostr(node->fj_initialized),
B
Bruce Momjian 已提交
693
					 node->fj_nNodes);
694 695 696 697

	appendStringInfo(str, " :innerNode ");
	_outNode(str, node->fj_innerNode);

698 699
	appendStringInfo(str, " :results @ 0x%p :alwaysdone",
					 node->fj_results);
700 701

	for (i = 0; i < node->fj_nNodes; i++)
702 703
		appendStringInfo(str,
						 booltostr(node->fj_alwaysDone[i]));
704 705 706
}

/*
707
 *	Expr is a subclass of Node
708 709
 */
static void
710
_outExpr(StringInfo str, Expr *node)
711
{
712
	char	   *opstr = NULL;
713

M
 
Marc G. Fournier 已提交
714
	appendStringInfo(str, " EXPR :typeOid %u ",
B
Bruce Momjian 已提交
715
					 node->typeOid);
716 717 718

	switch (node->opType)
	{
719 720 721
		case OP_EXPR:
			opstr = "op";
			break;
722 723 724
		case DISTINCT_EXPR:
			opstr = "distinct";
			break;
725 726 727 728 729 730 731 732 733 734 735 736
		case FUNC_EXPR:
			opstr = "func";
			break;
		case OR_EXPR:
			opstr = "or";
			break;
		case AND_EXPR:
			opstr = "and";
			break;
		case NOT_EXPR:
			opstr = "not";
			break;
V
Vadim B. Mikheev 已提交
737 738 739
		case SUBPLAN_EXPR:
			opstr = "subp";
			break;
740
	}
741 742 743
	appendStringInfo(str, " :opType ");
	_outToken(str, opstr);
	appendStringInfo(str, " :oper ");
744
	_outNode(str, node->oper);
M
 
Marc G. Fournier 已提交
745

746
	appendStringInfo(str, " :args ");
747
	_outNode(str, node->args);
748 749 750
}

/*
751
 *	Var is a subclass of Expr
752 753
 */
static void
754
_outVar(StringInfo str, Var *node)
755
{
B
Bruce Momjian 已提交
756
	appendStringInfo(str,
757
				" VAR :varno %u :varattno %d :vartype %u :vartypmod %d ",
B
Bruce Momjian 已提交
758 759 760 761
					 node->varno,
					 node->varattno,
					 node->vartype,
					 node->vartypmod);
M
 
Marc G. Fournier 已提交
762

763
	appendStringInfo(str, " :varlevelsup %u :varnoold %u :varoattno %d",
B
Bruce Momjian 已提交
764 765 766
					 node->varlevelsup,
					 node->varnoold,
					 node->varoattno);
767 768 769
}

/*
770
 *	Const is a subclass of Expr
771 772
 */
static void
773
_outConst(StringInfo str, Const *node)
774
{
B
Bruce Momjian 已提交
775
	appendStringInfo(str,
776 777
					 " CONST :consttype %u :constlen %d :constbyval %s"
					 " :constisnull %s :constvalue ",
B
Bruce Momjian 已提交
778 779
					 node->consttype,
					 node->constlen,
780 781
					 booltostr(node->constbyval),
					 booltostr(node->constisnull));
M
 
Marc G. Fournier 已提交
782

783
	if (node->constisnull)
B
Bruce Momjian 已提交
784
		appendStringInfo(str, "<>");
785
	else
786
		_outDatum(str, node->constvalue, node->constlen, node->constbyval);
787 788 789
}

/*
B
Bruce Momjian 已提交
790
 *	Aggref
791 792
 */
static void
793
_outAggref(StringInfo str, Aggref *node)
794
{
795 796
	appendStringInfo(str, " AGGREG :aggfnoid %u :aggtype %u :target ",
					 node->aggfnoid, node->aggtype);
797
	_outNode(str, node->target);
M
 
Marc G. Fournier 已提交
798

799
	appendStringInfo(str, " :aggstar %s :aggdistinct %s ",
800 801
					 booltostr(node->aggstar),
					 booltostr(node->aggdistinct));
802
	/* aggno is not dumped */
803 804
}

805 806 807 808 809 810
/*
 *	SubLink
 */
static void
_outSubLink(StringInfo str, SubLink *node)
{
B
Bruce Momjian 已提交
811 812 813
	appendStringInfo(str,
					 " SUBLINK :subLinkType %d :useor %s :lefthand ",
					 node->subLinkType,
814
					 booltostr(node->useor));
815
	_outNode(str, node->lefthand);
M
 
Marc G. Fournier 已提交
816

817
	appendStringInfo(str, " :oper ");
B
Bruce Momjian 已提交
818
	_outNode(str, node->oper);
M
 
Marc G. Fournier 已提交
819

820 821 822 823
	appendStringInfo(str, " :subselect ");
	_outNode(str, node->subselect);
}

824
/*
825
 *	ArrayRef is a subclass of Expr
826 827
 */
static void
B
Bruce Momjian 已提交
828
_outArrayRef(StringInfo str, ArrayRef *node)
829
{
B
Bruce Momjian 已提交
830
	appendStringInfo(str,
T
Tom Lane 已提交
831
		" ARRAYREF :refelemtype %u :refattrlength %d :refelemlength %d ",
B
Bruce Momjian 已提交
832 833 834
					 node->refelemtype,
					 node->refattrlength,
					 node->refelemlength);
M
 
Marc G. Fournier 已提交
835

B
Bruce Momjian 已提交
836 837
	appendStringInfo(str, " :refelembyval %c :refupperindex ",
					 node->refelembyval ? 't' : 'f');
838 839
	_outNode(str, node->refupperindexpr);

840
	appendStringInfo(str, " :reflowerindex ");
841 842
	_outNode(str, node->reflowerindexpr);

843
	appendStringInfo(str, " :refexpr ");
844 845
	_outNode(str, node->refexpr);

846
	appendStringInfo(str, " :refassgnexpr ");
847
	_outNode(str, node->refassgnexpr);
848 849 850
}

/*
851
 *	Func is a subclass of Expr
852 853
 */
static void
854
_outFunc(StringInfo str, Func *node)
855
{
856 857
	appendStringInfo(str,
					 " FUNC :funcid %u :funcresulttype %u :funcretset %s ",
B
Bruce Momjian 已提交
858
					 node->funcid,
859 860
					 node->funcresulttype,
					 booltostr(node->funcretset));
861 862 863
}

/*
864
 *	Oper is a subclass of Expr
865 866
 */
static void
867
_outOper(StringInfo str, Oper *node)
868
{
B
Bruce Momjian 已提交
869
	appendStringInfo(str,
870
					 " OPER :opno %u :opid %u :opresulttype %u :opretset %s ",
B
Bruce Momjian 已提交
871 872
					 node->opno,
					 node->opid,
873 874
					 node->opresulttype,
					 booltostr(node->opretset));
875 876 877
}

/*
878
 *	Param is a subclass of Expr
879 880
 */
static void
881
_outParam(StringInfo str, Param *node)
882
{
883
	appendStringInfo(str, " PARAM :paramkind %d :paramid %d :paramname ",
B
Bruce Momjian 已提交
884
					 node->paramkind,
885 886
					 node->paramid);
	_outToken(str, node->paramname);
887
	appendStringInfo(str, " :paramtype %u ", node->paramtype);
888 889
}

890 891 892 893 894 895 896 897 898 899
/*
 *	FieldSelect
 */
static void
_outFieldSelect(StringInfo str, FieldSelect *node)
{
	appendStringInfo(str, " FIELDSELECT :arg ");
	_outNode(str, node->arg);

	appendStringInfo(str, " :fieldnum %d :resulttype %u :resulttypmod %d ",
B
Bruce Momjian 已提交
900
				   node->fieldnum, node->resulttype, node->resulttypmod);
901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925
}

/*
 *	RelabelType
 */
static void
_outRelabelType(StringInfo str, RelabelType *node)
{
	appendStringInfo(str, " RELABELTYPE :arg ");
	_outNode(str, node->arg);

	appendStringInfo(str, " :resulttype %u :resulttypmod %d ",
					 node->resulttype, node->resulttypmod);
}

/*
 *	RangeTblRef
 */
static void
_outRangeTblRef(StringInfo str, RangeTblRef *node)
{
	appendStringInfo(str, " RANGETBLREF %d ",
					 node->rtindex);
}

926 927 928 929 930 931 932 933 934 935 936 937
/*
 *	FromExpr
 */
static void
_outFromExpr(StringInfo str, FromExpr *node)
{
	appendStringInfo(str, " FROMEXPR :fromlist ");
	_outNode(str, node->fromlist);
	appendStringInfo(str, " :quals ");
	_outNode(str, node->quals);
}

938 939 940 941 942 943 944 945
/*
 *	JoinExpr
 */
static void
_outJoinExpr(StringInfo str, JoinExpr *node)
{
	appendStringInfo(str, " JOINEXPR :jointype %d :isNatural %s :larg ",
					 (int) node->jointype,
946
					 booltostr(node->isNatural));
947 948 949 950 951 952 953 954 955
	_outNode(str, node->larg);
	appendStringInfo(str, " :rarg ");
	_outNode(str, node->rarg);
	appendStringInfo(str, " :using ");
	_outNode(str, node->using);
	appendStringInfo(str, " :quals ");
	_outNode(str, node->quals);
	appendStringInfo(str, " :alias ");
	_outNode(str, node->alias);
956
	appendStringInfo(str, " :rtindex %d ", node->rtindex);
957 958
}

959
/*
960
 *	TargetEntry is a subclass of Node.
961 962
 */
static void
963
_outTargetEntry(StringInfo str, TargetEntry *node)
964
{
M
 
Marc G. Fournier 已提交
965
	appendStringInfo(str, " TARGETENTRY :resdom ");
966 967
	_outNode(str, node->resdom);

968 969
	appendStringInfo(str, " :expr ");
	_outNode(str, node->expr);
970
}
971

972 973 974 975 976 977 978 979 980
static void
_outAlias(StringInfo str, Alias *node)
{
	appendStringInfo(str, " ALIAS :aliasname ");
	_outToken(str, node->aliasname);
	appendStringInfo(str, " :colnames ");
	_outNode(str, node->colnames);
}

981
static void
982
_outRangeTblEntry(StringInfo str, RangeTblEntry *node)
983
{
984 985
	/* put alias + eref first to make dump more legible */
	appendStringInfo(str, " RTE :alias ");
986 987 988
	_outNode(str, node->alias);
	appendStringInfo(str, " :eref ");
	_outNode(str, node->eref);
989 990 991 992 993 994
	appendStringInfo(str, " :rtekind %d ",
					 (int) node->rtekind);
	switch (node->rtekind)
	{
		case RTE_RELATION:
		case RTE_SPECIAL:
995
			appendStringInfo(str, ":relid %u", node->relid);
996 997 998 999 1000
			break;
		case RTE_SUBQUERY:
			appendStringInfo(str, ":subquery ");
			_outNode(str, node->subquery);
			break;
1001 1002 1003 1004
		case RTE_FUNCTION:
			appendStringInfo(str, ":funcexpr ");
			_outNode(str, node->funcexpr);
			break;
1005
		case RTE_JOIN:
1006
			appendStringInfo(str, ":jointype %d :joinaliasvars ",
1007
							 (int) node->jointype);
1008
			_outNode(str, node->joinaliasvars);
1009 1010 1011 1012 1013
			break;
		default:
			elog(ERROR, "bogus rte kind %d", (int) node->rtekind);
			break;
	}
1014 1015
	appendStringInfo(str, " :inh %s :inFromCl %s :checkForRead %s"
					 " :checkForWrite %s :checkAsUser %u",
1016 1017 1018 1019
					 booltostr(node->inh),
					 booltostr(node->inFromCl),
					 booltostr(node->checkForRead),
					 booltostr(node->checkForWrite),
1020
					 node->checkAsUser);
1021 1022
}

1023
/*
1024
 *	Path is a subclass of Node.
1025 1026
 */
static void
1027
_outPath(StringInfo str, Path *node)
1028
{
1029
	appendStringInfo(str,
1030
	 " PATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
B
Bruce Momjian 已提交
1031
					 node->pathtype,
1032 1033
					 node->startup_cost,
					 node->total_cost);
1034
	_outNode(str, node->pathkeys);
1035 1036 1037
}

/*
1038
 *	IndexPath is a subclass of Path.
1039 1040
 */
static void
1041
_outIndexPath(StringInfo str, IndexPath *node)
1042
{
B
Bruce Momjian 已提交
1043
	appendStringInfo(str,
1044
					 " INDEXPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
B
Bruce Momjian 已提交
1045
					 node->path.pathtype,
1046 1047
					 node->path.startup_cost,
					 node->path.total_cost);
1048
	_outNode(str, node->path.pathkeys);
1049

1050 1051
	appendStringInfo(str, " :indexinfo ");
	_outNode(str, node->indexinfo);
1052

1053
	appendStringInfo(str, " :indexqual ");
1054
	_outNode(str, node->indexqual);
1055

1056 1057
	appendStringInfo(str, " :indexscandir %d :joinrelids ",
					 (int) node->indexscandir);
1058
	_outIntList(str, node->joinrelids);
1059

1060
	appendStringInfo(str, " :alljoinquals %s :rows %.2f ",
1061
					 booltostr(node->alljoinquals),
1062
					 node->rows);
1063 1064
}

1065 1066 1067 1068 1069 1070 1071
/*
 *	TidPath is a subclass of Path.
 */
static void
_outTidPath(StringInfo str, TidPath *node)
{
	appendStringInfo(str,
1072
					 " TIDPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
1073
					 node->path.pathtype,
1074 1075
					 node->path.startup_cost,
					 node->path.total_cost);
1076 1077 1078 1079 1080
	_outNode(str, node->path.pathkeys);

	appendStringInfo(str, " :tideval ");
	_outNode(str, node->tideval);

1081
	appendStringInfo(str, " :unjoined_relids ");
1082 1083 1084
	_outIntList(str, node->unjoined_relids);
}

1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101
/*
 *	AppendPath is a subclass of Path.
 */
static void
_outAppendPath(StringInfo str, AppendPath *node)
{
	appendStringInfo(str,
					 " APPENDPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
					 node->path.pathtype,
					 node->path.startup_cost,
					 node->path.total_cost);
	_outNode(str, node->path.pathkeys);

	appendStringInfo(str, " :subpaths ");
	_outNode(str, node->subpaths);
}

1102
/*
1103
 *	NestPath is a subclass of Path
1104 1105
 */
static void
1106
_outNestPath(StringInfo str, NestPath *node)
1107
{
B
Bruce Momjian 已提交
1108
	appendStringInfo(str,
1109
					 " NESTPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
B
Bruce Momjian 已提交
1110
					 node->path.pathtype,
1111 1112
					 node->path.startup_cost,
					 node->path.total_cost);
1113
	_outNode(str, node->path.pathkeys);
1114 1115
	appendStringInfo(str, " :jointype %d :outerjoinpath ",
					 (int) node->jointype);
1116 1117 1118 1119 1120
	_outNode(str, node->outerjoinpath);
	appendStringInfo(str, " :innerjoinpath ");
	_outNode(str, node->innerjoinpath);
	appendStringInfo(str, " :joinrestrictinfo ");
	_outNode(str, node->joinrestrictinfo);
1121 1122 1123
}

/*
1124
 *	MergePath is a subclass of NestPath.
1125 1126
 */
static void
1127
_outMergePath(StringInfo str, MergePath *node)
1128
{
B
Bruce Momjian 已提交
1129
	appendStringInfo(str,
1130
					 " MERGEPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
B
Bruce Momjian 已提交
1131
					 node->jpath.path.pathtype,
1132 1133
					 node->jpath.path.startup_cost,
					 node->jpath.path.total_cost);
1134
	_outNode(str, node->jpath.path.pathkeys);
1135 1136
	appendStringInfo(str, " :jointype %d :outerjoinpath ",
					 (int) node->jpath.jointype);
1137 1138 1139 1140 1141
	_outNode(str, node->jpath.outerjoinpath);
	appendStringInfo(str, " :innerjoinpath ");
	_outNode(str, node->jpath.innerjoinpath);
	appendStringInfo(str, " :joinrestrictinfo ");
	_outNode(str, node->jpath.joinrestrictinfo);
1142

1143
	appendStringInfo(str, " :path_mergeclauses ");
1144 1145
	_outNode(str, node->path_mergeclauses);

1146
	appendStringInfo(str, " :outersortkeys ");
1147 1148
	_outNode(str, node->outersortkeys);

1149
	appendStringInfo(str, " :innersortkeys ");
1150
	_outNode(str, node->innersortkeys);
1151 1152 1153
}

/*
1154
 *	HashPath is a subclass of NestPath.
1155 1156
 */
static void
1157
_outHashPath(StringInfo str, HashPath *node)
1158
{
B
Bruce Momjian 已提交
1159
	appendStringInfo(str,
1160
					 " HASHPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
B
Bruce Momjian 已提交
1161
					 node->jpath.path.pathtype,
1162 1163
					 node->jpath.path.startup_cost,
					 node->jpath.path.total_cost);
1164
	_outNode(str, node->jpath.path.pathkeys);
1165 1166
	appendStringInfo(str, " :jointype %d :outerjoinpath ",
					 (int) node->jpath.jointype);
1167 1168 1169 1170 1171
	_outNode(str, node->jpath.outerjoinpath);
	appendStringInfo(str, " :innerjoinpath ");
	_outNode(str, node->jpath.innerjoinpath);
	appendStringInfo(str, " :joinrestrictinfo ");
	_outNode(str, node->jpath.joinrestrictinfo);
1172

1173
	appendStringInfo(str, " :path_hashclauses ");
1174
	_outNode(str, node->path_hashclauses);
1175 1176 1177
}

/*
1178
 *	PathKeyItem is a subclass of Node.
1179 1180
 */
static void
1181
_outPathKeyItem(StringInfo str, PathKeyItem *node)
1182
{
1183 1184 1185
	appendStringInfo(str, " PATHKEYITEM :sortop %u :key ",
					 node->sortop);
	_outNode(str, node->key);
1186 1187 1188
}

/*
1189
 *	RestrictInfo is a subclass of Node.
1190 1191
 */
static void
1192
_outRestrictInfo(StringInfo str, RestrictInfo *node)
1193
{
B
Bruce Momjian 已提交
1194
	appendStringInfo(str, " RESTRICTINFO :clause ");
1195 1196
	_outNode(str, node->clause);

1197
	appendStringInfo(str, " :ispusheddown %s :subclauseindices ",
1198
					 booltostr(node->ispusheddown));
1199
	_outNode(str, node->subclauseindices);
1200

1201 1202 1203
	appendStringInfo(str, " :mergejoinoperator %u ", node->mergejoinoperator);
	appendStringInfo(str, " :left_sortop %u ", node->left_sortop);
	appendStringInfo(str, " :right_sortop %u ", node->right_sortop);
M
 
Marc G. Fournier 已提交
1204
	appendStringInfo(str, " :hashjoinoperator %u ", node->hashjoinoperator);
1205 1206 1207
}

/*
1208
 *	JoinInfo is a subclass of Node.
1209 1210
 */
static void
1211
_outJoinInfo(StringInfo str, JoinInfo *node)
1212
{
B
Bruce Momjian 已提交
1213 1214
	appendStringInfo(str, " JINFO :unjoined_relids ");
	_outIntList(str, node->unjoined_relids);
1215

1216 1217
	appendStringInfo(str, " :jinfo_restrictinfo ");
	_outNode(str, node->jinfo_restrictinfo);
1218 1219 1220 1221 1222 1223
}

/*
 * Print the value of a Datum given its type.
 */
static void
1224
_outDatum(StringInfo str, Datum value, int typlen, bool typbyval)
1225
{
1226 1227
	Size		length,
				i;
1228
	char	   *s;
1229

1230
	length = datumGetSize(value, typbyval, typlen);
1231

1232
	if (typbyval)
1233 1234
	{
		s = (char *) (&value);
1235
		appendStringInfo(str, " %u [ ", (unsigned int) length);
1236
		for (i = 0; i < (Size) sizeof(Datum); i++)
1237
			appendStringInfo(str, "%d ", (int) (s[i]));
M
 
Marc G. Fournier 已提交
1238
		appendStringInfo(str, "] ");
1239
	}
1240
	else
1241
	{
1242 1243
		s = (char *) DatumGetPointer(value);
		if (!PointerIsValid(s))
M
 
Marc G. Fournier 已提交
1244
			appendStringInfo(str, " 0 [ ] ");
1245 1246
		else
		{
1247
			appendStringInfo(str, " %u [ ", (unsigned int) length);
1248
			for (i = 0; i < length; i++)
1249
				appendStringInfo(str, "%d ", (int) (s[i]));
M
 
Marc G. Fournier 已提交
1250
			appendStringInfo(str, "] ");
1251
		}
1252 1253 1254 1255
	}
}

static void
1256
_outStream(StringInfo str, Stream *node)
1257
{
B
Bruce Momjian 已提交
1258
	appendStringInfo(str,
B
Bruce Momjian 已提交
1259
	  " STREAM :pathptr @ %p :cinfo @ %p :clausetype %p :upstream @ %p ",
1260 1261 1262 1263
					 node->pathptr,
					 node->cinfo,
					 node->clausetype,
					 node->upstream);
1264

B
Bruce Momjian 已提交
1265
	appendStringInfo(str,
B
Bruce Momjian 已提交
1266
			 " :downstream @ %p :groupup %d :groupcost %f :groupsel %f ",
1267
					 node->downstream,
B
Bruce Momjian 已提交
1268 1269 1270
					 node->groupup,
					 node->groupcost,
					 node->groupsel);
1271
}
1272

1273 1274 1275
static void
_outAExpr(StringInfo str, A_Expr *node)
{
1276
	appendStringInfo(str, " AEXPR ");
1277 1278 1279
	switch (node->oper)
	{
		case AND:
1280
			appendStringInfo(str, "AND ");
1281 1282
			break;
		case OR:
1283
			appendStringInfo(str, "OR ");
1284 1285
			break;
		case NOT:
1286
			appendStringInfo(str, "NOT ");
1287
			break;
1288
		case OP:
1289
			_outNode(str, node->name);
1290
			appendStringInfo(str, " ");
1291
			break;
1292 1293 1294
		default:
			appendStringInfo(str, "?? ");
			break;
1295
	}
1296
	_outNode(str, node->lexpr);
1297
	appendStringInfo(str, " ");
1298 1299 1300
	_outNode(str, node->rexpr);
}

1301
static void
1302
_outValue(StringInfo str, Value *value)
1303
{
1304 1305
	switch (value->type)
	{
1306
		case T_Integer:
1307
			appendStringInfo(str, " %ld ", value->val.ival);
1308 1309
			break;
		case T_Float:
1310 1311 1312 1313

			/*
			 * We assume the value is a valid numeric literal and so does
			 * not need quoting.
1314 1315 1316 1317 1318 1319 1320
			 */
			appendStringInfo(str, " %s ", value->val.str);
			break;
		case T_String:
			appendStringInfo(str, " \"");
			_outToken(str, value->val.str);
			appendStringInfo(str, "\" ");
1321
			break;
1322
		case T_BitString:
1323 1324
			/* internal representation already has leading 'b' */
			appendStringInfo(str, " %s ", value->val.str);
1325
			break;
1326
		default:
B
Bruce Momjian 已提交
1327
			elog(WARNING, "_outValue: don't know how to print type %d ",
1328
				 value->type);
1329
			break;
1330
	}
1331 1332
}

1333
static void
1334
_outRangeVar(StringInfo str, RangeVar *node)
1335
{
1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348
	appendStringInfo(str, " RANGEVAR :relation ");
	/*
	 * we deliberately ignore catalogname here, since it is presently not
	 * semantically meaningful
	 */
	_outToken(str, node->schemaname);
	appendStringInfo(str, " . ");
	_outToken(str, node->relname);
	appendStringInfo(str, " :inhopt %d :istemp %s",
					(int) node->inhOpt,
					booltostr(node->istemp));
	appendStringInfo(str, " :alias ");
	_outNode(str, node->alias);
1349 1350
}

1351
static void
1352
_outColumnRef(StringInfo str, ColumnRef *node)
1353
{
1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373
	appendStringInfo(str, " COLUMNREF :fields ");
	_outNode(str, node->fields);
	appendStringInfo(str, " :indirection ");
	_outNode(str, node->indirection);
}

static void
_outParamRef(StringInfo str, ParamRef *node)
{
	appendStringInfo(str, " PARAMREF :number %d :fields ", node->number);
	_outNode(str, node->fields);
	appendStringInfo(str, " :indirection ");
	_outNode(str, node->indirection);
}

static void
_outIdent(StringInfo str, Ident *node)
{
	appendStringInfo(str, " IDENT ");
	_outToken(str, node->name);
1374 1375
}

1376 1377 1378
static void
_outAConst(StringInfo str, A_Const *node)
{
1379
	appendStringInfo(str, "CONST ");
1380
	_outValue(str, &(node->val));
1381 1382
	appendStringInfo(str, " :typename ");
	_outNode(str, node->typename);
1383 1384
}

1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395
static void
_outExprFieldSelect(StringInfo str, ExprFieldSelect *node)
{
	appendStringInfo(str, " EXPRFIELDSELECT :arg ");
	_outNode(str, node->arg);
	appendStringInfo(str, " :fields ");
	_outNode(str, node->fields);
	appendStringInfo(str, " :indirection ");
	_outNode(str, node->indirection);
}

T
Thomas G. Lockhart 已提交
1396 1397 1398
static void
_outConstraint(StringInfo str, Constraint *node)
{
1399
	appendStringInfo(str, " CONSTRAINT :name ");
1400 1401
	_outToken(str, node->name);
	appendStringInfo(str, " :type ");
T
Thomas G. Lockhart 已提交
1402 1403 1404 1405

	switch (node->contype)
	{
		case CONSTR_PRIMARY:
1406
			appendStringInfo(str, "PRIMARY_KEY :keys ");
T
Thomas G. Lockhart 已提交
1407 1408 1409 1410
			_outNode(str, node->keys);
			break;

		case CONSTR_CHECK:
1411
			appendStringInfo(str, "CHECK :raw ");
1412
			_outNode(str, node->raw_expr);
1413 1414
			appendStringInfo(str, " :cooked ");
			_outToken(str, node->cooked_expr);
T
Thomas G. Lockhart 已提交
1415 1416 1417
			break;

		case CONSTR_DEFAULT:
1418
			appendStringInfo(str, "DEFAULT :raw ");
1419
			_outNode(str, node->raw_expr);
1420 1421
			appendStringInfo(str, " :cooked ");
			_outToken(str, node->cooked_expr);
T
Thomas G. Lockhart 已提交
1422 1423 1424
			break;

		case CONSTR_NOTNULL:
1425
			appendStringInfo(str, "NOT_NULL");
T
Thomas G. Lockhart 已提交
1426 1427 1428
			break;

		case CONSTR_UNIQUE:
1429
			appendStringInfo(str, "UNIQUE :keys ");
T
Thomas G. Lockhart 已提交
1430 1431 1432 1433
			_outNode(str, node->keys);
			break;

		default:
1434
			appendStringInfo(str, "<unrecognized_constraint>");
T
Thomas G. Lockhart 已提交
1435 1436 1437 1438
			break;
	}
}

1439 1440 1441 1442 1443
static void
_outFkConstraint(StringInfo str, FkConstraint *node)
{
	appendStringInfo(str, " FKCONSTRAINT :constr_name ");
	_outToken(str, node->constr_name);
1444 1445
	appendStringInfo(str, " :pktable ");
	_outNode(str, node->pktable);
1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457
	appendStringInfo(str, " :fk_attrs ");
	_outNode(str, node->fk_attrs);
	appendStringInfo(str, " :pk_attrs ");
	_outNode(str, node->pk_attrs);
	appendStringInfo(str, " :match_type ");
	_outToken(str, node->match_type);
	appendStringInfo(str, " :actions %d :deferrable %s :initdeferred %s",
					 node->actions,
					 booltostr(node->deferrable),
					 booltostr(node->initdeferred));
}

T
Thomas G. Lockhart 已提交
1458
static void
1459
_outCaseExpr(StringInfo str, CaseExpr *node)
T
Thomas G. Lockhart 已提交
1460
{
1461 1462 1463 1464 1465
	appendStringInfo(str, " CASE :casetype %u :arg ",
					 node->casetype);
	_outNode(str, node->arg);

	appendStringInfo(str, " :args ");
T
Thomas G. Lockhart 已提交
1466
	_outNode(str, node->args);
M
 
Marc G. Fournier 已提交
1467

1468
	appendStringInfo(str, " :defresult ");
T
Thomas G. Lockhart 已提交
1469 1470 1471 1472
	_outNode(str, node->defresult);
}

static void
1473
_outCaseWhen(StringInfo str, CaseWhen *node)
T
Thomas G. Lockhart 已提交
1474
{
1475
	appendStringInfo(str, " WHEN ");
T
Thomas G. Lockhart 已提交
1476
	_outNode(str, node->expr);
M
 
Marc G. Fournier 已提交
1477

1478
	appendStringInfo(str, " :then ");
T
Thomas G. Lockhart 已提交
1479 1480 1481
	_outNode(str, node->result);
}

1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507
/*
 *	NullTest
 */
static void
_outNullTest(StringInfo str, NullTest *node)
{
	appendStringInfo(str, " NULLTEST :arg ");
	_outNode(str, node->arg);

	appendStringInfo(str, " :nulltesttype %d ",
					 (int) node->nulltesttype);
}

/*
 *	BooleanTest
 */
static void
_outBooleanTest(StringInfo str, BooleanTest *node)
{
	appendStringInfo(str, " BOOLEANTEST :arg ");
	_outNode(str, node->arg);

	appendStringInfo(str, " :booltesttype %d ",
					 (int) node->booltesttype);
}

1508 1509
/*
 * _outNode -
1510
 *	  converts a Node into ascii string and append it to 'str'
1511 1512 1513 1514
 */
static void
_outNode(StringInfo str, void *obj)
{
1515 1516
	if (obj == NULL)
	{
B
Bruce Momjian 已提交
1517
		appendStringInfo(str, "<>");
1518 1519
		return;
	}
1520

1521
	if (IsA(obj, List))
1522
	{
1523
		List	   *l;
1524

1525
		appendStringInfoChar(str, '(');
1526 1527 1528 1529
		foreach(l, (List *) obj)
		{
			_outNode(str, lfirst(l));
			if (lnext(l))
1530
				appendStringInfoChar(str, ' ');
1531
		}
1532
		appendStringInfoChar(str, ')');
1533
	}
1534
	else if (IsA(obj, Integer) || IsA(obj, Float) || IsA(obj, String) || IsA(obj, BitString))
1535 1536 1537 1538
	{
		/* nodeRead does not want to see { } around these! */
		_outValue(str, obj);
	}
1539 1540
	else
	{
1541
		appendStringInfoChar(str, '{');
1542 1543
		switch (nodeTag(obj))
		{
1544 1545 1546 1547 1548 1549
			case T_CreateStmt:
				_outCreateStmt(str, obj);
				break;
			case T_IndexStmt:
				_outIndexStmt(str, obj);
				break;
1550 1551 1552 1553 1554 1555
			case T_NotifyStmt:
				_outNotifyStmt(str, obj);
				break;
			case T_SelectStmt:
				_outSelectStmt(str, obj);
				break;
1556 1557 1558
			case T_ColumnDef:
				_outColumnDef(str, obj);
				break;
1559 1560 1561
			case T_TypeName:
				_outTypeName(str, obj);
				break;
1562 1563 1564
			case T_TypeCast:
				_outTypeCast(str, obj);
				break;
1565 1566 1567
			case T_IndexElem:
				_outIndexElem(str, obj);
				break;
1568 1569 1570
			case T_Query:
				_outQuery(str, obj);
				break;
1571 1572 1573 1574 1575
			case T_SortClause:
				_outSortClause(str, obj);
				break;
			case T_GroupClause:
				_outGroupClause(str, obj);
1576
				break;
1577 1578 1579
			case T_SetOperationStmt:
				_outSetOperationStmt(str, obj);
				break;
1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609
			case T_Plan:
				_outPlan(str, obj);
				break;
			case T_Result:
				_outResult(str, obj);
				break;
			case T_Append:
				_outAppend(str, obj);
				break;
			case T_Join:
				_outJoin(str, obj);
				break;
			case T_NestLoop:
				_outNestLoop(str, obj);
				break;
			case T_MergeJoin:
				_outMergeJoin(str, obj);
				break;
			case T_HashJoin:
				_outHashJoin(str, obj);
				break;
			case T_Scan:
				_outScan(str, obj);
				break;
			case T_SeqScan:
				_outSeqScan(str, obj);
				break;
			case T_IndexScan:
				_outIndexScan(str, obj);
				break;
1610 1611 1612
			case T_TidScan:
				_outTidScan(str, obj);
				break;
1613 1614 1615
			case T_SubqueryScan:
				_outSubqueryScan(str, obj);
				break;
1616 1617 1618
			case T_FunctionScan:
				_outFunctionScan(str, obj);
				break;
1619 1620 1621
			case T_Material:
				_outMaterial(str, obj);
				break;
1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633
			case T_Sort:
				_outSort(str, obj);
				break;
			case T_Agg:
				_outAgg(str, obj);
				break;
			case T_Group:
				_outGroup(str, obj);
				break;
			case T_Unique:
				_outUnique(str, obj);
				break;
1634 1635 1636
			case T_SetOp:
				_outSetOp(str, obj);
				break;
1637 1638 1639
			case T_Limit:
				_outLimit(str, obj);
				break;
1640 1641 1642
			case T_Hash:
				_outHash(str, obj);
				break;
V
Vadim B. Mikheev 已提交
1643 1644 1645
			case T_SubPlan:
				_outSubPlan(str, obj);
				break;
1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660
			case T_Resdom:
				_outResdom(str, obj);
				break;
			case T_Fjoin:
				_outFjoin(str, obj);
				break;
			case T_Expr:
				_outExpr(str, obj);
				break;
			case T_Var:
				_outVar(str, obj);
				break;
			case T_Const:
				_outConst(str, obj);
				break;
B
Bruce Momjian 已提交
1661 1662
			case T_Aggref:
				_outAggref(str, obj);
1663
				break;
1664 1665 1666
			case T_SubLink:
				_outSubLink(str, obj);
				break;
1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678
			case T_ArrayRef:
				_outArrayRef(str, obj);
				break;
			case T_Func:
				_outFunc(str, obj);
				break;
			case T_Oper:
				_outOper(str, obj);
				break;
			case T_Param:
				_outParam(str, obj);
				break;
1679 1680 1681 1682 1683 1684 1685 1686 1687
			case T_FieldSelect:
				_outFieldSelect(str, obj);
				break;
			case T_RelabelType:
				_outRelabelType(str, obj);
				break;
			case T_RangeTblRef:
				_outRangeTblRef(str, obj);
				break;
1688 1689 1690
			case T_FromExpr:
				_outFromExpr(str, obj);
				break;
1691 1692 1693
			case T_JoinExpr:
				_outJoinExpr(str, obj);
				break;
1694 1695 1696
			case T_TargetEntry:
				_outTargetEntry(str, obj);
				break;
1697 1698 1699
			case T_Alias:
				_outAlias(str, obj);
				break;
1700 1701 1702 1703 1704 1705 1706 1707 1708
			case T_RangeTblEntry:
				_outRangeTblEntry(str, obj);
				break;
			case T_Path:
				_outPath(str, obj);
				break;
			case T_IndexPath:
				_outIndexPath(str, obj);
				break;
1709 1710 1711
			case T_TidPath:
				_outTidPath(str, obj);
				break;
1712 1713 1714
			case T_AppendPath:
				_outAppendPath(str, obj);
				break;
1715 1716
			case T_NestPath:
				_outNestPath(str, obj);
1717 1718 1719 1720 1721 1722 1723
				break;
			case T_MergePath:
				_outMergePath(str, obj);
				break;
			case T_HashPath:
				_outHashPath(str, obj);
				break;
1724 1725
			case T_PathKeyItem:
				_outPathKeyItem(str, obj);
1726
				break;
1727 1728
			case T_RestrictInfo:
				_outRestrictInfo(str, obj);
1729
				break;
1730 1731
			case T_JoinInfo:
				_outJoinInfo(str, obj);
1732 1733 1734 1735
				break;
			case T_Stream:
				_outStream(str, obj);
				break;
1736 1737 1738
			case T_A_Expr:
				_outAExpr(str, obj);
				break;
1739 1740 1741 1742 1743 1744 1745 1746 1747
			case T_RangeVar:
				_outRangeVar(str, obj);
				break;
			case T_ColumnRef:
				_outColumnRef(str, obj);
				break;
			case T_ParamRef:
				_outParamRef(str, obj);
				break;
1748 1749 1750 1751 1752 1753
			case T_Ident:
				_outIdent(str, obj);
				break;
			case T_A_Const:
				_outAConst(str, obj);
				break;
1754 1755 1756
			case T_ExprFieldSelect:
				_outExprFieldSelect(str, obj);
				break;
T
Thomas G. Lockhart 已提交
1757 1758 1759
			case T_Constraint:
				_outConstraint(str, obj);
				break;
1760 1761 1762
			case T_FkConstraint:
				_outFkConstraint(str, obj);
				break;
T
Thomas G. Lockhart 已提交
1763 1764 1765 1766 1767 1768
			case T_CaseExpr:
				_outCaseExpr(str, obj);
				break;
			case T_CaseWhen:
				_outCaseWhen(str, obj);
				break;
1769 1770 1771 1772 1773 1774
			case T_NullTest:
				_outNullTest(str, obj);
				break;
			case T_BooleanTest:
				_outBooleanTest(str, obj);
				break;
1775 1776 1777 1778
			case T_FuncCall:
				_outFuncCall(str, obj);
				break;

1779
			default:
B
Bruce Momjian 已提交
1780
				elog(WARNING, "_outNode: don't know how to print type %d ",
1781 1782
					 nodeTag(obj));
				break;
1783
		}
1784
		appendStringInfoChar(str, '}');
1785 1786 1787 1788 1789
	}
}

/*
 * nodeToString -
1790
 *	   returns the ascii representation of the Node as a palloc'd string
1791
 */
1792
char *
1793 1794
nodeToString(void *obj)
{
B
Bruce Momjian 已提交
1795
	StringInfoData str;
1796

1797 1798 1799 1800
	/* see stringinfo.h for an explanation of this maneuver */
	initStringInfo(&str);
	_outNode(&str, obj);
	return str.data;
1801
}