outfuncs.c 38.8 KB
Newer Older
M
 
Marc G. Fournier 已提交
1
/*
2
 * outfuncs.c
3
 *	  routines to convert a node to ascii representation
4
 *
5
 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
B
Add:  
Bruce Momjian 已提交
6
 * Portions Copyright (c) 1994, Regents of the University of California
7
 *
B
Bruce Momjian 已提交
8
 *	$Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.140 2001/03/22 03:59:32 momjian 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 :relname ");
	_outToken(str, node->relname);
110 111

	appendStringInfo(str, " :istemp %s ",
112
					 booltostr(node->istemp));
113 114

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

117
	appendStringInfo(str, " :inhRelnames ");
118
	_outNode(str, node->inhRelnames);
M
 
Marc G. Fournier 已提交
119

120
	appendStringInfo(str, " :constraints ");
121
	_outNode(str, node->constraints);
122
}
123 124 125 126

static void
_outIndexStmt(StringInfo str, IndexStmt *node)
{
127 128 129 130 131 132 133
	appendStringInfo(str, " INDEX :idxname ");
	_outToken(str, node->idxname);
	appendStringInfo(str, " :relname ");
	_outToken(str, node->relname);
	appendStringInfo(str, " :accessMethod ");
	_outToken(str, node->accessMethod);
	appendStringInfo(str, " :indexParams ");
134
	_outNode(str, node->indexParams);
M
 
Marc G. Fournier 已提交
135

136 137
	appendStringInfo(str, " :withClause ");
	_outNode(str, node->withClause);
M
 
Marc G. Fournier 已提交
138

139 140
	appendStringInfo(str, " :whereClause ");
	_outNode(str, node->whereClause);
M
 
Marc G. Fournier 已提交
141

142 143
	appendStringInfo(str, " :rangetable ");
	_outNode(str, node->rangetable);
M
 
Marc G. Fournier 已提交
144

145
	appendStringInfo(str, " :unique %s :primary %s ",
146 147
					 booltostr(node->unique),
					 booltostr(node->primary));
148
}
149

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

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

170 171 172
static void
_outColumnDef(StringInfo str, ColumnDef *node)
{
173 174 175
	appendStringInfo(str, " COLUMNDEF :colname ");
	_outToken(str, node->colname);
	appendStringInfo(str, " :typename ");
176
	_outNode(str, node->typename);
177
	appendStringInfo(str, " :is_not_null %s :is_sequence %s :raw_default ",
178 179
					 booltostr(node->is_not_null),
					 booltostr(node->is_sequence));
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
	appendStringInfo(str, " TYPENAME :name ");
	_outToken(str, node->name);
	appendStringInfo(str, " :timezone %s :setof %s typmod %d :arrayBounds ",
193 194
					 booltostr(node->timezone),
					 booltostr(node->setof),
B
Bruce Momjian 已提交
195
					 node->typmod);
196 197
	_outNode(str, node->arrayBounds);
}
198

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

208 209 210
static void
_outIndexElem(StringInfo str, IndexElem *node)
{
211 212 213
	appendStringInfo(str, " INDEXELEM :name ");
	_outToken(str, node->name);
	appendStringInfo(str, " :args ");
214
	_outNode(str, node->args);
215 216
	appendStringInfo(str, " :class ");
	_outToken(str, node->class);
217
}
218

219
static void
220
_outQuery(StringInfo str, Query *node)
221
{
222

M
 
Marc G. Fournier 已提交
223
	appendStringInfo(str, " QUERY :command %d ", node->commandType);
224

225 226
	if (node->utilityStmt)
	{
B
Bruce Momjian 已提交
227

228 229 230
		/*
		 * Hack to make up for lack of outfuncs for utility-stmt nodes
		 */
231 232 233
		switch (nodeTag(node->utilityStmt))
		{
			case T_CreateStmt:
234 235 236
				appendStringInfo(str, " :create ");
				_outToken(str, ((CreateStmt *) (node->utilityStmt))->relname);
				appendStringInfo(str, " ");
237 238 239 240
				_outNode(str, node->utilityStmt);
				break;

			case T_IndexStmt:
241 242 243 244 245
				appendStringInfo(str, " :index ");
				_outToken(str, ((IndexStmt *) (node->utilityStmt))->idxname);
				appendStringInfo(str, " on ");
				_outToken(str, ((IndexStmt *) (node->utilityStmt))->relname);
				appendStringInfo(str, " ");
246 247 248 249
				_outNode(str, node->utilityStmt);
				break;

			case T_NotifyStmt:
250
				appendStringInfo(str, " :notify ");
251
				_outToken(str, ((NotifyStmt *) (node->utilityStmt))->relname);
252 253 254
				break;

			default:
255
				appendStringInfo(str, " :utility ? ");
256 257
		}
	}
258
	else
259
		appendStringInfo(str, " :utility <>");
260

261
	appendStringInfo(str, " :resultRelation %d :into ",
262 263 264
					 node->resultRelation);
	_outToken(str, node->into);

265
	appendStringInfo(str, " :isPortal %s :isBinary %s :isTemp %s"
266
					 " :hasAggs %s :hasSubLinks %s :rtable ",
267 268 269 270 271
					 booltostr(node->isPortal),
					 booltostr(node->isBinary),
					 booltostr(node->isTemp),
					 booltostr(node->hasAggs),
					 booltostr(node->hasSubLinks));
272
	_outNode(str, node->rtable);
M
 
Marc G. Fournier 已提交
273

274 275 276
	appendStringInfo(str, " :jointree ");
	_outNode(str, node->jointree);

277 278 279
	appendStringInfo(str, " :rowMarks ");
	_outIntList(str, node->rowMarks);

280 281
	appendStringInfo(str, " :targetList ");
	_outNode(str, node->targetList);
M
 
Marc G. Fournier 已提交
282

283 284
	appendStringInfo(str, " :groupClause ");
	_outNode(str, node->groupClause);
M
 
Marc G. Fournier 已提交
285

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

289 290
	appendStringInfo(str, " :distinctClause ");
	_outNode(str, node->distinctClause);
B
Hi!  
Bruce Momjian 已提交
291

292 293
	appendStringInfo(str, " :sortClause ");
	_outNode(str, node->sortClause);
294

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

B
Bruce Momjian 已提交
298 299
	appendStringInfo(str, " :limitCount ");
	_outNode(str, node->limitCount);
300 301 302

	appendStringInfo(str, " :setOperations ");
	_outNode(str, node->setOperations);
303 304 305

	appendStringInfo(str, " :resultRelations ");
	_outIntList(str, node->resultRelations);
306 307 308
}

static void
309
_outSortClause(StringInfo str, SortClause *node)
310
{
311
	appendStringInfo(str, " SORTCLAUSE :tleSortGroupRef %u :sortop %u ",
312
					 node->tleSortGroupRef, node->sortop);
313 314 315 316 317
}

static void
_outGroupClause(StringInfo str, GroupClause *node)
{
318
	appendStringInfo(str, " GROUPCLAUSE :tleSortGroupRef %u :sortop %u ",
319
					 node->tleSortGroupRef, node->sortop);
320 321
}

322 323 324 325 326
static void
_outSetOperationStmt(StringInfo str, SetOperationStmt *node)
{
	appendStringInfo(str, " SETOPERATIONSTMT :op %d :all %s :larg ",
					 (int) node->op,
327
					 booltostr(node->all));
328 329 330 331
	_outNode(str, node->larg);
	appendStringInfo(str, " :rarg ");
	_outNode(str, node->rarg);
	appendStringInfo(str, " :colTypes ");
332
	_outOidList(str, node->colTypes);
333 334
}

335 336
/*
 * print the basic stuff of all nodes that inherit from Plan
337 338
 *
 * NOTE: we deliberately omit the execution state (EState)
339 340
 */
static void
341
_outPlanInfo(StringInfo str, Plan *node)
342
{
B
Bruce Momjian 已提交
343
	appendStringInfo(str,
344
					 ":startup_cost %.2f :total_cost %.2f :rows %.0f :width %d :qptargetlist ",
345 346
					 node->startup_cost,
					 node->total_cost,
347
					 node->plan_rows,
348
					 node->plan_width);
349
	_outNode(str, node->targetlist);
M
 
Marc G. Fournier 已提交
350

351
	appendStringInfo(str, " :qpqual ");
352
	_outNode(str, node->qual);
M
 
Marc G. Fournier 已提交
353

354
	appendStringInfo(str, " :lefttree ");
355
	_outNode(str, node->lefttree);
M
 
Marc G. Fournier 已提交
356

357
	appendStringInfo(str, " :righttree ");
358
	_outNode(str, node->righttree);
M
 
Marc G. Fournier 已提交
359

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

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

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

M
 
Marc G. Fournier 已提交
369
	appendStringInfo(str, " :nprm %d ", node->nParamExec);
370 371 372
}

/*
373
 *	Stuff from plannodes.h
374 375
 */
static void
376
_outPlan(StringInfo str, Plan *node)
377
{
378
	appendStringInfo(str, " PLAN ");
379
	_outPlanInfo(str, (Plan *) node);
380 381 382
}

static void
383
_outResult(StringInfo str, Result *node)
384
{
385
	appendStringInfo(str, " RESULT ");
386 387
	_outPlanInfo(str, (Plan *) node);

388
	appendStringInfo(str, " :resconstantqual ");
389 390
	_outNode(str, node->resconstantqual);

391 392 393
}

/*
394
 *	Append is a subclass of Plan.
395 396
 */
static void
B
Bruce Momjian 已提交
397
_outAppend(StringInfo str, Append *node)
398
{
399
	appendStringInfo(str, " APPEND ");
400 401
	_outPlanInfo(str, (Plan *) node);

402 403
	appendStringInfo(str, " :appendplans ");
	_outNode(str, node->appendplans);
404

405
	appendStringInfo(str, " :isTarget %s ",
406
					 booltostr(node->isTarget));
407 408 409
}

/*
410
 *	Join is a subclass of Plan
411 412
 */
static void
413
_outJoin(StringInfo str, Join *node)
414
{
415
	appendStringInfo(str, " JOIN ");
416
	_outPlanInfo(str, (Plan *) node);
417 418 419
	appendStringInfo(str, " :jointype %d :joinqual ",
					 (int) node->jointype);
	_outNode(str, node->joinqual);
420 421 422
}

/*
423
 *	NestLoop is a subclass of Join
424 425
 */
static void
426
_outNestLoop(StringInfo str, NestLoop *node)
427
{
428
	appendStringInfo(str, " NESTLOOP ");
429
	_outPlanInfo(str, (Plan *) node);
430 431 432
	appendStringInfo(str, " :jointype %d :joinqual ",
					 (int) node->join.jointype);
	_outNode(str, node->join.joinqual);
433 434 435
}

/*
436
 *	MergeJoin is a subclass of Join
437 438
 */
static void
439
_outMergeJoin(StringInfo str, MergeJoin *node)
440
{
441
	appendStringInfo(str, " MERGEJOIN ");
442
	_outPlanInfo(str, (Plan *) node);
443 444 445
	appendStringInfo(str, " :jointype %d :joinqual ",
					 (int) node->join.jointype);
	_outNode(str, node->join.joinqual);
446

447
	appendStringInfo(str, " :mergeclauses ");
448
	_outNode(str, node->mergeclauses);
449 450 451
}

/*
452
 *	HashJoin is a subclass of Join.
453 454
 */
static void
455
_outHashJoin(StringInfo str, HashJoin *node)
456
{
457
	appendStringInfo(str, " HASHJOIN ");
458
	_outPlanInfo(str, (Plan *) node);
459 460 461
	appendStringInfo(str, " :jointype %d :joinqual ",
					 (int) node->join.jointype);
	_outNode(str, node->join.joinqual);
462

463
	appendStringInfo(str, " :hashclauses ");
464
	_outNode(str, node->hashclauses);
465
	appendStringInfo(str, " :hashjoinop %u ",
B
Bruce Momjian 已提交
466
					 node->hashjoinop);
467 468
}

V
Vadim B. Mikheev 已提交
469 470 471
static void
_outSubPlan(StringInfo str, SubPlan *node)
{
M
 
Marc G. Fournier 已提交
472
	appendStringInfo(str, " SUBPLAN :plan ");
V
Vadim B. Mikheev 已提交
473
	_outNode(str, node->plan);
M
 
Marc G. Fournier 已提交
474

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

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

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

V
Vadim B. Mikheev 已提交
484 485 486 487
	appendStringInfo(str, " :slink ");
	_outNode(str, node->sublink);
}

488
/*
489
 *	Scan is a subclass of Node
490 491
 */
static void
492
_outScan(StringInfo str, Scan *node)
493
{
494
	appendStringInfo(str, " SCAN ");
495 496
	_outPlanInfo(str, (Plan *) node);

497
	appendStringInfo(str, " :scanrelid %u ", node->scanrelid);
498 499 500
}

/*
501
 *	SeqScan is a subclass of Scan
502 503
 */
static void
504
_outSeqScan(StringInfo str, SeqScan *node)
505
{
506
	appendStringInfo(str, " SEQSCAN ");
507 508
	_outPlanInfo(str, (Plan *) node);

509
	appendStringInfo(str, " :scanrelid %u ", node->scanrelid);
510 511 512
}

/*
513
 *	IndexScan is a subclass of Scan
514 515
 */
static void
516
_outIndexScan(StringInfo str, IndexScan *node)
517
{
518
	appendStringInfo(str, " INDEXSCAN ");
519 520
	_outPlanInfo(str, (Plan *) node);

521
	appendStringInfo(str, " :scanrelid %u :indxid ", node->scan.scanrelid);
522
	_outOidList(str, node->indxid);
523

524
	appendStringInfo(str, " :indxqual ");
525 526
	_outNode(str, node->indxqual);

V
Vadim B. Mikheev 已提交
527 528 529
	appendStringInfo(str, " :indxqualorig ");
	_outNode(str, node->indxqualorig);

530
	appendStringInfo(str, " :indxorderdir %d ", node->indxorderdir);
531 532
}

533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549
/*
 *	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);

}

550 551 552 553 554 555 556 557 558 559 560 561 562
/*
 *	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);
}

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

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

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

static void
592
_outGroup(StringInfo str, Group *node)
593
{
594
	appendStringInfo(str, " GRP ");
595 596 597
	_outPlanInfo(str, (Plan *) node);

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

603
static void
604
_outUnique(StringInfo str, Unique *node)
605
{
B
Bruce Momjian 已提交
606
	int			i;
607

608
	appendStringInfo(str, " UNIQUE ");
609 610
	_outPlanInfo(str, (Plan *) node);

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

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

	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);
}

633 634 635 636 637 638 639 640 641 642 643 644
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);
}

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

654
	appendStringInfo(str, " :hashkey ");
655
	_outNode(str, node->hashkey);
656 657 658 659
}

/*****************************************************************************
 *
660
 *	Stuff from primnodes.h.
661 662 663 664
 *
 *****************************************************************************/

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

static void
684
_outFjoin(StringInfo str, Fjoin *node)
685
{
686
	int			i;
687

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

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

695 696
	appendStringInfo(str, " :results @ 0x%p :alwaysdone",
					 node->fj_results);
697 698

	for (i = 0; i < node->fj_nNodes; i++)
699 700
		appendStringInfo(str,
						 booltostr(node->fj_alwaysDone[i]));
701 702 703
}

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

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

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

740
	appendStringInfo(str, " :args ");
741
	_outNode(str, node->args);
742 743 744
}

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

757
	appendStringInfo(str, " :varlevelsup %u :varnoold %u :varoattno %d",
B
Bruce Momjian 已提交
758 759 760
					 node->varlevelsup,
					 node->varnoold,
					 node->varoattno);
761 762 763
}

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

777
	if (node->constisnull)
B
Bruce Momjian 已提交
778
		appendStringInfo(str, "<>");
779
	else
780
		_outDatum(str, node->constvalue, node->constlen, node->constbyval);
781 782 783
}

/*
B
Bruce Momjian 已提交
784
 *	Aggref
785 786
 */
static void
787
_outAggref(StringInfo str, Aggref *node)
788
{
789 790 791
	appendStringInfo(str, " AGGREG :aggname ");
	_outToken(str, node->aggname);
	appendStringInfo(str, " :basetype %u :aggtype %u :target ",
792
					 node->basetype, node->aggtype);
793
	_outNode(str, node->target);
M
 
Marc G. Fournier 已提交
794

795
	appendStringInfo(str, " :aggstar %s :aggdistinct %s ",
796 797
					 booltostr(node->aggstar),
					 booltostr(node->aggdistinct));
798
	/* aggno is not dumped */
799 800
}

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

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

816 817 818 819
	appendStringInfo(str, " :subselect ");
	_outNode(str, node->subselect);
}

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

B
Bruce Momjian 已提交
832 833
	appendStringInfo(str, " :refelembyval %c :refupperindex ",
					 node->refelembyval ? 't' : 'f');
834 835
	_outNode(str, node->refupperindexpr);

836
	appendStringInfo(str, " :reflowerindex ");
837 838
	_outNode(str, node->reflowerindexpr);

839
	appendStringInfo(str, " :refexpr ");
840 841
	_outNode(str, node->refexpr);

842
	appendStringInfo(str, " :refassgnexpr ");
843
	_outNode(str, node->refassgnexpr);
844 845 846
}

/*
847
 *	Func is a subclass of Expr
848 849
 */
static void
850
_outFunc(StringInfo str, Func *node)
851
{
852
	appendStringInfo(str, " FUNC :funcid %u :functype %u ",
B
Bruce Momjian 已提交
853
					 node->funcid,
854
					 node->functype);
855 856 857
}

/*
858
 *	Oper is a subclass of Expr
859 860
 */
static void
861
_outOper(StringInfo str, Oper *node)
862
{
B
Bruce Momjian 已提交
863 864 865 866 867
	appendStringInfo(str,
					 " OPER :opno %u :opid %u :opresulttype %u ",
					 node->opno,
					 node->opid,
					 node->opresulttype);
868 869 870
}

/*
871
 *	Param is a subclass of Expr
872 873
 */
static void
874
_outParam(StringInfo str, Param *node)
875
{
876
	appendStringInfo(str, " PARAM :paramkind %d :paramid %d :paramname ",
B
Bruce Momjian 已提交
877
					 node->paramkind,
878 879
					 node->paramid);
	_outToken(str, node->paramname);
880
	appendStringInfo(str, " :paramtype %u ", node->paramtype);
881 882
}

883 884 885 886 887 888 889 890 891 892
/*
 *	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 已提交
893
				   node->fieldnum, node->resulttype, node->resulttypmod);
894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918
}

/*
 *	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);
}

919 920 921 922 923 924 925 926 927 928 929 930
/*
 *	FromExpr
 */
static void
_outFromExpr(StringInfo str, FromExpr *node)
{
	appendStringInfo(str, " FROMEXPR :fromlist ");
	_outNode(str, node->fromlist);
	appendStringInfo(str, " :quals ");
	_outNode(str, node->quals);
}

931 932 933 934 935 936 937 938
/*
 *	JoinExpr
 */
static void
_outJoinExpr(StringInfo str, JoinExpr *node)
{
	appendStringInfo(str, " JOINEXPR :jointype %d :isNatural %s :larg ",
					 (int) node->jointype,
939
					 booltostr(node->isNatural));
940 941 942 943 944 945 946 947 948 949 950 951 952 953 954
	_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);
	appendStringInfo(str, " :colnames ");
	_outNode(str, node->colnames);
	appendStringInfo(str, " :colvars ");
	_outNode(str, node->colvars);
}

955
/*
956
 *	Stuff from relation.h
957
 */
958

959
static void
960
_outRelOptInfo(StringInfo str, RelOptInfo *node)
961
{
M
 
Marc G. Fournier 已提交
962
	appendStringInfo(str, " RELOPTINFO :relids ");
963 964
	_outIntList(str, node->relids);

965
	appendStringInfo(str, " :rows %.0f :width %d :targetlist ",
966
					 node->rows,
967
					 node->width);
968 969
	_outNode(str, node->targetlist);

970
	appendStringInfo(str, " :pathlist ");
971
	_outNode(str, node->pathlist);
972 973 974 975
	appendStringInfo(str, " :cheapest_startup_path ");
	_outNode(str, node->cheapest_startup_path);
	appendStringInfo(str, " :cheapest_total_path ");
	_outNode(str, node->cheapest_total_path);
976

977
	appendStringInfo(str, " :pruneable %s :issubquery %s :indexed %s :pages %ld :tuples %.0f :subplan ",
978 979 980
					 booltostr(node->pruneable),
					 booltostr(node->issubquery),
					 booltostr(node->indexed),
981 982 983
					 node->pages,
					 node->tuples);
	_outNode(str, node->subplan);
984

985 986 987
	appendStringInfo(str, " :baserestrictinfo ");
	_outNode(str, node->baserestrictinfo);
	appendStringInfo(str, " :baserestrictcost %.2f :outerjoinset ",
988 989
					 node->baserestrictcost);
	_outIntList(str, node->outerjoinset);
990
	appendStringInfo(str, " :joininfo ");
991
	_outNode(str, node->joininfo);
992
	appendStringInfo(str, " :innerjoin ");
993
	_outNode(str, node->innerjoin);
994 995
}

996 997 998 999 1000 1001 1002 1003 1004
static void
_outIndexOptInfo(StringInfo str, IndexOptInfo *node)
{
	appendStringInfo(str, " INDEXOPTINFO :indexoid %u :pages %ld :tuples %g ",
					 node->indexoid,
					 node->pages,
					 node->tuples);
}

1005
/*
1006
 *	TargetEntry is a subclass of Node.
1007 1008
 */
static void
1009
_outTargetEntry(StringInfo str, TargetEntry *node)
1010
{
M
 
Marc G. Fournier 已提交
1011
	appendStringInfo(str, " TARGETENTRY :resdom ");
1012 1013
	_outNode(str, node->resdom);

1014 1015
	appendStringInfo(str, " :expr ");
	_outNode(str, node->expr);
1016
}
1017 1018

static void
1019
_outRangeTblEntry(StringInfo str, RangeTblEntry *node)
1020
{
1021 1022
	appendStringInfo(str, " RTE :relname ");
	_outToken(str, node->relname);
1023
	appendStringInfo(str, " :relid %u ",
1024
					 node->relid);
1025 1026 1027
	appendStringInfo(str, " :subquery ");
	_outNode(str, node->subquery);
	appendStringInfo(str, " :alias ");
1028 1029 1030
	_outNode(str, node->alias);
	appendStringInfo(str, " :eref ");
	_outNode(str, node->eref);
1031 1032
	appendStringInfo(str, " :inh %s :inFromCl %s :checkForRead %s"
					 " :checkForWrite %s :checkAsUser %u",
1033 1034 1035 1036
					 booltostr(node->inh),
					 booltostr(node->inFromCl),
					 booltostr(node->checkForRead),
					 booltostr(node->checkForWrite),
1037
					 node->checkAsUser);
1038 1039
}

1040
/*
1041
 *	Path is a subclass of Node.
1042 1043
 */
static void
1044
_outPath(StringInfo str, Path *node)
1045
{
1046
	appendStringInfo(str,
1047
	 " PATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
B
Bruce Momjian 已提交
1048
					 node->pathtype,
1049 1050
					 node->startup_cost,
					 node->total_cost);
1051
	_outNode(str, node->pathkeys);
1052 1053 1054
}

/*
1055
 *	IndexPath is a subclass of Path.
1056 1057
 */
static void
1058
_outIndexPath(StringInfo str, IndexPath *node)
1059
{
B
Bruce Momjian 已提交
1060
	appendStringInfo(str,
1061
					 " INDEXPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
B
Bruce Momjian 已提交
1062
					 node->path.pathtype,
1063 1064
					 node->path.startup_cost,
					 node->path.total_cost);
1065
	_outNode(str, node->path.pathkeys);
1066

1067
	appendStringInfo(str, " :indexid ");
1068
	_outOidList(str, node->indexid);
1069

1070
	appendStringInfo(str, " :indexqual ");
1071
	_outNode(str, node->indexqual);
1072

1073 1074
	appendStringInfo(str, " :indexscandir %d :joinrelids ",
					 (int) node->indexscandir);
1075
	_outIntList(str, node->joinrelids);
1076

1077
	appendStringInfo(str, " :alljoinquals %s :rows %.2f ",
1078
					 booltostr(node->alljoinquals),
1079
					 node->rows);
1080 1081
}

1082 1083 1084 1085 1086 1087 1088
/*
 *	TidPath is a subclass of Path.
 */
static void
_outTidPath(StringInfo str, TidPath *node)
{
	appendStringInfo(str,
1089
					 " TIDPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
1090
					 node->path.pathtype,
1091 1092
					 node->path.startup_cost,
					 node->path.total_cost);
1093 1094 1095 1096 1097
	_outNode(str, node->path.pathkeys);

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

1098
	appendStringInfo(str, " :unjoined_relids ");
1099 1100 1101
	_outIntList(str, node->unjoined_relids);
}

1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118
/*
 *	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);
}

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

/*
1141
 *	MergePath is a subclass of NestPath.
1142 1143
 */
static void
1144
_outMergePath(StringInfo str, MergePath *node)
1145
{
B
Bruce Momjian 已提交
1146
	appendStringInfo(str,
1147
					 " MERGEPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
B
Bruce Momjian 已提交
1148
					 node->jpath.path.pathtype,
1149 1150
					 node->jpath.path.startup_cost,
					 node->jpath.path.total_cost);
1151
	_outNode(str, node->jpath.path.pathkeys);
1152 1153
	appendStringInfo(str, " :jointype %d :outerjoinpath ",
					 (int) node->jpath.jointype);
1154 1155 1156 1157 1158
	_outNode(str, node->jpath.outerjoinpath);
	appendStringInfo(str, " :innerjoinpath ");
	_outNode(str, node->jpath.innerjoinpath);
	appendStringInfo(str, " :joinrestrictinfo ");
	_outNode(str, node->jpath.joinrestrictinfo);
1159

1160
	appendStringInfo(str, " :path_mergeclauses ");
1161 1162
	_outNode(str, node->path_mergeclauses);

1163
	appendStringInfo(str, " :outersortkeys ");
1164 1165
	_outNode(str, node->outersortkeys);

1166
	appendStringInfo(str, " :innersortkeys ");
1167
	_outNode(str, node->innersortkeys);
1168 1169 1170
}

/*
1171
 *	HashPath is a subclass of NestPath.
1172 1173
 */
static void
1174
_outHashPath(StringInfo str, HashPath *node)
1175
{
B
Bruce Momjian 已提交
1176
	appendStringInfo(str,
1177
					 " HASHPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
B
Bruce Momjian 已提交
1178
					 node->jpath.path.pathtype,
1179 1180
					 node->jpath.path.startup_cost,
					 node->jpath.path.total_cost);
1181
	_outNode(str, node->jpath.path.pathkeys);
1182 1183
	appendStringInfo(str, " :jointype %d :outerjoinpath ",
					 (int) node->jpath.jointype);
1184 1185 1186 1187 1188
	_outNode(str, node->jpath.outerjoinpath);
	appendStringInfo(str, " :innerjoinpath ");
	_outNode(str, node->jpath.innerjoinpath);
	appendStringInfo(str, " :joinrestrictinfo ");
	_outNode(str, node->jpath.joinrestrictinfo);
1189

1190
	appendStringInfo(str, " :path_hashclauses ");
1191
	_outNode(str, node->path_hashclauses);
1192 1193 1194
}

/*
1195
 *	PathKeyItem is a subclass of Node.
1196 1197
 */
static void
1198
_outPathKeyItem(StringInfo str, PathKeyItem *node)
1199
{
1200 1201 1202
	appendStringInfo(str, " PATHKEYITEM :sortop %u :key ",
					 node->sortop);
	_outNode(str, node->key);
1203 1204 1205
}

/*
1206
 *	RestrictInfo is a subclass of Node.
1207 1208
 */
static void
1209
_outRestrictInfo(StringInfo str, RestrictInfo *node)
1210
{
B
Bruce Momjian 已提交
1211
	appendStringInfo(str, " RESTRICTINFO :clause ");
1212 1213
	_outNode(str, node->clause);

1214
	appendStringInfo(str, " :ispusheddown %s :subclauseindices ",
1215
					 booltostr(node->ispusheddown));
1216
	_outNode(str, node->subclauseindices);
1217

1218 1219 1220
	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 已提交
1221
	appendStringInfo(str, " :hashjoinoperator %u ", node->hashjoinoperator);
1222 1223 1224
}

/*
1225
 *	JoinInfo is a subclass of Node.
1226 1227
 */
static void
1228
_outJoinInfo(StringInfo str, JoinInfo *node)
1229
{
B
Bruce Momjian 已提交
1230 1231
	appendStringInfo(str, " JINFO :unjoined_relids ");
	_outIntList(str, node->unjoined_relids);
1232

1233 1234
	appendStringInfo(str, " :jinfo_restrictinfo ");
	_outNode(str, node->jinfo_restrictinfo);
1235 1236 1237 1238 1239 1240
}

/*
 * Print the value of a Datum given its type.
 */
static void
1241
_outDatum(StringInfo str, Datum value, int typlen, bool typbyval)
1242
{
1243 1244
	Size		length,
				i;
1245
	char	   *s;
1246

1247
	length = datumGetSize(value, typbyval, typlen);
1248

1249
	if (typbyval)
1250 1251
	{
		s = (char *) (&value);
1252
		appendStringInfo(str, " %u [ ", (unsigned int) length);
1253
		for (i = 0; i < (Size) sizeof(Datum); i++)
1254
			appendStringInfo(str, "%d ", (int) (s[i]));
M
 
Marc G. Fournier 已提交
1255
		appendStringInfo(str, "] ");
1256
	}
1257
	else
1258
	{
1259 1260
		s = (char *) DatumGetPointer(value);
		if (!PointerIsValid(s))
M
 
Marc G. Fournier 已提交
1261
			appendStringInfo(str, " 0 [ ] ");
1262 1263
		else
		{
1264
			appendStringInfo(str, " %u [ ", (unsigned int) length);
1265
			for (i = 0; i < length; i++)
1266
				appendStringInfo(str, "%d ", (int) (s[i]));
M
 
Marc G. Fournier 已提交
1267
			appendStringInfo(str, "] ");
1268
		}
1269 1270 1271 1272
	}
}

static void
1273
_outIter(StringInfo str, Iter *node)
1274
{
M
 
Marc G. Fournier 已提交
1275
	appendStringInfo(str, " ITER :iterexpr ");
1276
	_outNode(str, node->iterexpr);
1277 1278 1279
}

static void
1280
_outStream(StringInfo str, Stream *node)
1281
{
B
Bruce Momjian 已提交
1282
	appendStringInfo(str,
B
Bruce Momjian 已提交
1283
	  " STREAM :pathptr @ %p :cinfo @ %p :clausetype %p :upstream @ %p ",
1284 1285 1286 1287
					 node->pathptr,
					 node->cinfo,
					 node->clausetype,
					 node->upstream);
1288

B
Bruce Momjian 已提交
1289
	appendStringInfo(str,
B
Bruce Momjian 已提交
1290
			 " :downstream @ %p :groupup %d :groupcost %f :groupsel %f ",
1291
					 node->downstream,
B
Bruce Momjian 已提交
1292 1293 1294
					 node->groupup,
					 node->groupcost,
					 node->groupsel);
1295
}
1296

1297 1298 1299
static void
_outAExpr(StringInfo str, A_Expr *node)
{
1300
	appendStringInfo(str, " AEXPR ");
1301 1302 1303
	switch (node->oper)
	{
		case AND:
1304
			appendStringInfo(str, "AND ");
1305 1306
			break;
		case OR:
1307
			appendStringInfo(str, "OR ");
1308 1309
			break;
		case NOT:
1310
			appendStringInfo(str, "NOT ");
1311 1312
			break;
		case ISNULL:
1313
			appendStringInfo(str, "ISNULL ");
1314 1315
			break;
		case NOTNULL:
1316
			appendStringInfo(str, "NOTNULL ");
1317
			break;
1318
		case OP:
1319 1320
			_outToken(str, node->opname);
			appendStringInfo(str, " ");
1321
			break;
1322 1323 1324
		default:
			appendStringInfo(str, "?? ");
			break;
1325
	}
1326
	_outNode(str, node->lexpr);
1327
	appendStringInfo(str, " ");
1328 1329 1330
	_outNode(str, node->rexpr);
}

1331
static void
1332
_outValue(StringInfo str, Value *value)
1333
{
1334 1335
	switch (value->type)
	{
B
Bruce Momjian 已提交
1336
			case T_Integer:
1337
			appendStringInfo(str, " %ld ", value->val.ival);
1338 1339
			break;
		case T_Float:
1340 1341 1342 1343

			/*
			 * We assume the value is a valid numeric literal and so does
			 * not need quoting.
1344 1345 1346 1347 1348 1349 1350
			 */
			appendStringInfo(str, " %s ", value->val.str);
			break;
		case T_String:
			appendStringInfo(str, " \"");
			_outToken(str, value->val.str);
			appendStringInfo(str, "\" ");
1351
			break;
1352
		case T_BitString:
1353 1354
			/* internal representation already has leading 'b' */
			appendStringInfo(str, " %s ", value->val.str);
1355
			break;
1356
		default:
1357 1358
			elog(NOTICE, "_outValue: don't know how to print type %d ",
				 value->type);
1359
			break;
1360
	}
1361 1362
}

1363 1364 1365
static void
_outIdent(StringInfo str, Ident *node)
{
1366 1367
	appendStringInfo(str, " IDENT ");
	_outToken(str, node->name);
1368 1369
}

1370 1371 1372
static void
_outAttr(StringInfo str, Attr *node)
{
1373
	appendStringInfo(str, " ATTR :relname ");
1374
	_outToken(str, node->relname);
1375 1376
	appendStringInfo(str, " :attrs ");
	_outNode(str, node->attrs);
1377 1378
}

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

T
Thomas G. Lockhart 已提交
1388 1389 1390
static void
_outConstraint(StringInfo str, Constraint *node)
{
1391 1392 1393
	appendStringInfo(str, " ");
	_outToken(str, node->name);
	appendStringInfo(str, " :type ");
T
Thomas G. Lockhart 已提交
1394 1395 1396 1397

	switch (node->contype)
	{
		case CONSTR_PRIMARY:
1398
			appendStringInfo(str, "PRIMARY KEY ");
T
Thomas G. Lockhart 已提交
1399 1400 1401 1402
			_outNode(str, node->keys);
			break;

		case CONSTR_CHECK:
1403
			appendStringInfo(str, "CHECK :raw ");
1404
			_outNode(str, node->raw_expr);
1405 1406
			appendStringInfo(str, " :cooked ");
			_outToken(str, node->cooked_expr);
T
Thomas G. Lockhart 已提交
1407 1408 1409
			break;

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

		case CONSTR_NOTNULL:
1417
			appendStringInfo(str, "NOT NULL");
T
Thomas G. Lockhart 已提交
1418 1419 1420
			break;

		case CONSTR_UNIQUE:
1421
			appendStringInfo(str, "UNIQUE ");
T
Thomas G. Lockhart 已提交
1422 1423 1424 1425
			_outNode(str, node->keys);
			break;

		default:
1426
			appendStringInfo(str, "<unrecognized_constraint>");
T
Thomas G. Lockhart 已提交
1427 1428 1429 1430 1431
			break;
	}
}

static void
1432
_outCaseExpr(StringInfo str, CaseExpr *node)
T
Thomas G. Lockhart 已提交
1433
{
1434 1435 1436 1437 1438
	appendStringInfo(str, " CASE :casetype %u :arg ",
					 node->casetype);
	_outNode(str, node->arg);

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

1441
	appendStringInfo(str, " :defresult ");
T
Thomas G. Lockhart 已提交
1442 1443 1444 1445
	_outNode(str, node->defresult);
}

static void
1446
_outCaseWhen(StringInfo str, CaseWhen *node)
T
Thomas G. Lockhart 已提交
1447
{
1448
	appendStringInfo(str, " WHEN ");
T
Thomas G. Lockhart 已提交
1449
	_outNode(str, node->expr);
M
 
Marc G. Fournier 已提交
1450

1451
	appendStringInfo(str, " :then ");
T
Thomas G. Lockhart 已提交
1452 1453 1454
	_outNode(str, node->result);
}

1455 1456
/*
 * _outNode -
1457
 *	  converts a Node into ascii string and append it to 'str'
1458 1459 1460 1461
 */
static void
_outNode(StringInfo str, void *obj)
{
1462 1463
	if (obj == NULL)
	{
B
Bruce Momjian 已提交
1464
		appendStringInfo(str, "<>");
1465 1466
		return;
	}
1467

1468
	if (IsA(obj, List))
1469
	{
1470
		List	   *l;
1471

1472
		appendStringInfoChar(str, '(');
1473 1474 1475 1476
		foreach(l, (List *) obj)
		{
			_outNode(str, lfirst(l));
			if (lnext(l))
1477
				appendStringInfoChar(str, ' ');
1478
		}
1479
		appendStringInfoChar(str, ')');
1480
	}
1481
	else if (IsA(obj, Integer) || IsA(obj, Float) || IsA(obj, String) || IsA(obj, BitString))
1482 1483 1484 1485
	{
		/* nodeRead does not want to see { } around these! */
		_outValue(str, obj);
	}
1486 1487
	else
	{
1488
		appendStringInfoChar(str, '{');
1489 1490
		switch (nodeTag(obj))
		{
1491 1492 1493 1494 1495 1496 1497 1498 1499
			case T_CreateStmt:
				_outCreateStmt(str, obj);
				break;
			case T_IndexStmt:
				_outIndexStmt(str, obj);
				break;
			case T_ColumnDef:
				_outColumnDef(str, obj);
				break;
1500 1501 1502
			case T_TypeName:
				_outTypeName(str, obj);
				break;
1503 1504 1505
			case T_TypeCast:
				_outTypeCast(str, obj);
				break;
1506 1507 1508
			case T_IndexElem:
				_outIndexElem(str, obj);
				break;
1509 1510 1511
			case T_Query:
				_outQuery(str, obj);
				break;
1512 1513 1514 1515 1516
			case T_SortClause:
				_outSortClause(str, obj);
				break;
			case T_GroupClause:
				_outGroupClause(str, obj);
1517
				break;
1518 1519 1520
			case T_SetOperationStmt:
				_outSetOperationStmt(str, obj);
				break;
1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550
			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;
1551 1552 1553
			case T_TidScan:
				_outTidScan(str, obj);
				break;
1554 1555 1556
			case T_SubqueryScan:
				_outSubqueryScan(str, obj);
				break;
1557 1558 1559
			case T_Material:
				_outMaterial(str, obj);
				break;
1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571
			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;
1572 1573 1574
			case T_SetOp:
				_outSetOp(str, obj);
				break;
1575 1576 1577
			case T_Limit:
				_outLimit(str, obj);
				break;
1578 1579 1580
			case T_Hash:
				_outHash(str, obj);
				break;
V
Vadim B. Mikheev 已提交
1581 1582 1583
			case T_SubPlan:
				_outSubPlan(str, obj);
				break;
1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598
			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 已提交
1599 1600
			case T_Aggref:
				_outAggref(str, obj);
1601
				break;
1602 1603 1604
			case T_SubLink:
				_outSubLink(str, obj);
				break;
1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616
			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;
1617 1618 1619 1620 1621 1622 1623 1624 1625
			case T_FieldSelect:
				_outFieldSelect(str, obj);
				break;
			case T_RelabelType:
				_outRelabelType(str, obj);
				break;
			case T_RangeTblRef:
				_outRangeTblRef(str, obj);
				break;
1626 1627 1628
			case T_FromExpr:
				_outFromExpr(str, obj);
				break;
1629 1630 1631
			case T_JoinExpr:
				_outJoinExpr(str, obj);
				break;
B
Bruce Momjian 已提交
1632
			case T_RelOptInfo:
B
Bruce Momjian 已提交
1633
				_outRelOptInfo(str, obj);
1634
				break;
1635 1636 1637
			case T_IndexOptInfo:
				_outIndexOptInfo(str, obj);
				break;
1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649
			case T_TargetEntry:
				_outTargetEntry(str, obj);
				break;
			case T_RangeTblEntry:
				_outRangeTblEntry(str, obj);
				break;
			case T_Path:
				_outPath(str, obj);
				break;
			case T_IndexPath:
				_outIndexPath(str, obj);
				break;
1650 1651 1652
			case T_TidPath:
				_outTidPath(str, obj);
				break;
1653 1654 1655
			case T_AppendPath:
				_outAppendPath(str, obj);
				break;
1656 1657
			case T_NestPath:
				_outNestPath(str, obj);
1658 1659 1660 1661 1662 1663 1664
				break;
			case T_MergePath:
				_outMergePath(str, obj);
				break;
			case T_HashPath:
				_outHashPath(str, obj);
				break;
1665 1666
			case T_PathKeyItem:
				_outPathKeyItem(str, obj);
1667
				break;
1668 1669
			case T_RestrictInfo:
				_outRestrictInfo(str, obj);
1670
				break;
1671 1672
			case T_JoinInfo:
				_outJoinInfo(str, obj);
1673 1674 1675 1676 1677 1678 1679
				break;
			case T_Iter:
				_outIter(str, obj);
				break;
			case T_Stream:
				_outStream(str, obj);
				break;
1680 1681 1682 1683 1684 1685 1686 1687 1688
			case T_A_Expr:
				_outAExpr(str, obj);
				break;
			case T_Ident:
				_outIdent(str, obj);
				break;
			case T_A_Const:
				_outAConst(str, obj);
				break;
T
Thomas G. Lockhart 已提交
1689 1690 1691 1692 1693 1694 1695 1696 1697
			case T_Constraint:
				_outConstraint(str, obj);
				break;
			case T_CaseExpr:
				_outCaseExpr(str, obj);
				break;
			case T_CaseWhen:
				_outCaseWhen(str, obj);
				break;
1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710

			case T_VariableSetStmt:
				break;
			case T_SelectStmt:
				_outSelectStmt(str, obj);
				break;
			case T_FuncCall:
				_outFuncCall(str, obj);
				break;
			case T_Attr:
				_outAttr(str, obj);
				break;

1711
			default:
B
Bruce Momjian 已提交
1712
				elog(NOTICE, "_outNode: don't know how to print type %d ",
1713 1714
					 nodeTag(obj));
				break;
1715
		}
1716
		appendStringInfoChar(str, '}');
1717 1718 1719 1720 1721
	}
}

/*
 * nodeToString -
1722
 *	   returns the ascii representation of the Node as a palloc'd string
1723
 */
1724
char *
1725 1726
nodeToString(void *obj)
{
B
Bruce Momjian 已提交
1727
	StringInfoData str;
1728

1729 1730 1731 1732
	/* see stringinfo.h for an explanation of this maneuver */
	initStringInfo(&str);
	_outNode(&str, obj);
	return str.data;
1733
}