outfuncs.c 42.1 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
 *
B
Bruce Momjian 已提交
8
 *	$Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.180 2002/11/15 02:50:07 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 :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 121 122
	appendStringInfo(str, " :hasoids %s :oncommit %d ",
					 booltostr(node->hasoids),
					 (int) node->oncommit);
123
}
124 125 126 127

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

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

153 154 155
static void
_outSelectStmt(StringInfo str, SelectStmt *node)
{
156
	/* XXX this is pretty durn incomplete */
157
	appendStringInfo(str, " SELECT :where ");
158 159 160 161 162 163
	_outNode(str, node->whereClause);
}

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

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

static void
_outTypeName(StringInfo str, TypeName *node)
{
196 197 198
	appendStringInfo(str, " TYPENAME :names ");
	_outNode(str, node->names);
	appendStringInfo(str, " :typeid %u :timezone %s :setof %s"
199
					 " :pct_type %s :typmod %d :arrayBounds ",
200
					 node->typeid,
201 202
					 booltostr(node->timezone),
					 booltostr(node->setof),
203
					 booltostr(node->pct_type),
B
Bruce Momjian 已提交
204
					 node->typmod);
205 206
	_outNode(str, node->arrayBounds);
}
207

208 209 210 211 212 213 214 215 216
static void
_outTypeCast(StringInfo str, TypeCast *node)
{
	appendStringInfo(str, " TYPECAST :arg ");
	_outNode(str, node->arg);
	appendStringInfo(str, " :typename ");
	_outNode(str, node->typename);
}

217 218 219
static void
_outIndexElem(StringInfo str, IndexElem *node)
{
220 221
	appendStringInfo(str, " INDEXELEM :name ");
	_outToken(str, node->name);
222 223
	appendStringInfo(str, " :funcname ");
	_outNode(str, node->funcname);
224
	appendStringInfo(str, " :args ");
225
	_outNode(str, node->args);
226 227
	appendStringInfo(str, " :opclass ");
	_outNode(str, node->opclass);
228
}
229

230
static void
231
_outQuery(StringInfo str, Query *node)
232
{
233 234
	appendStringInfo(str, " QUERY :command %d :source %d :utility ",
					 (int) node->commandType, (int) node->querySource);
235

236 237
	/*
	 * Hack to work around missing outfuncs routines for a lot of the
B
Bruce Momjian 已提交
238 239 240 241
	 * 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.
242
	 */
243 244 245 246 247 248 249
	if (node->utilityStmt)
	{
		switch (nodeTag(node->utilityStmt))
		{
			case T_CreateStmt:
			case T_IndexStmt:
			case T_NotifyStmt:
250
				_outNode(str, node->utilityStmt);
251 252
				break;
			default:
253 254
				appendStringInfo(str, "?");
				break;
255 256
		}
	}
257
	else
258
		appendStringInfo(str, "<>");
259

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

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

272 273 274
	appendStringInfo(str, " :jointree ");
	_outNode(str, node->jointree);

275 276 277
	appendStringInfo(str, " :rowMarks ");
	_outIntList(str, node->rowMarks);

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

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

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

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

290 291
	appendStringInfo(str, " :sortClause ");
	_outNode(str, node->sortClause);
292

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

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

	appendStringInfo(str, " :setOperations ");
	_outNode(str, node->setOperations);
301 302 303

	appendStringInfo(str, " :resultRelations ");
	_outIntList(str, node->resultRelations);
304 305

	/* planner-internal fields are not written out */
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 565 566 567 568 569 570 571 572 573 574
/*
 *	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);
}

575
/*
576
 *	Material is a subclass of Plan
577 578 579 580 581 582 583 584
 */
static void
_outMaterial(StringInfo str, Material *node)
{
	appendStringInfo(str, " MATERIAL ");
	_outPlanInfo(str, (Plan *) node);
}

585
/*
586
 *	Sort is a subclass of Plan
587 588
 */
static void
589
_outSort(StringInfo str, Sort *node)
590
{
591
	appendStringInfo(str, " SORT ");
592
	_outPlanInfo(str, (Plan *) node);
593
	appendStringInfo(str, " :keycount %d ", node->keycount);
594 595 596
}

static void
B
Bruce Momjian 已提交
597
_outAgg(StringInfo str, Agg *node)
598
{
599
	appendStringInfo(str, " AGG ");
600
	_outPlanInfo(str, (Plan *) node);
601 602
	appendStringInfo(str, " :aggstrategy %d :numCols %d :numGroups %ld ",
					 (int) node->aggstrategy, node->numCols, node->numGroups);
603 604 605
}

static void
606
_outGroup(StringInfo str, Group *node)
607
{
608
	appendStringInfo(str, " GRP ");
609
	_outPlanInfo(str, (Plan *) node);
610
	appendStringInfo(str, " :numCols %d ", node->numCols);
611
}
612

613
static void
614
_outUnique(StringInfo str, Unique *node)
615
{
B
Bruce Momjian 已提交
616
	int			i;
617

618
	appendStringInfo(str, " UNIQUE ");
619 620
	_outPlanInfo(str, (Plan *) node);

621
	appendStringInfo(str, " :numCols %d :uniqColIdx ",
622
					 node->numCols);
623 624 625
	for (i = 0; i < node->numCols; i++)
		appendStringInfo(str, "%d ", (int) node->uniqColIdx[i]);
}
626

627 628 629
static void
_outSetOp(StringInfo str, SetOp *node)
{
B
Bruce Momjian 已提交
630
	int			i;
631 632 633 634 635 636 637 638 639 640 641 642

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

643 644 645 646 647 648 649 650 651 652 653 654
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);
}

655
/*
656
 *	Hash is a subclass of Plan
657 658
 */
static void
659
_outHash(StringInfo str, Hash *node)
660
{
661
	appendStringInfo(str, " HASH ");
662 663
	_outPlanInfo(str, (Plan *) node);

664
	appendStringInfo(str, " :hashkey ");
665
	_outNode(str, node->hashkey);
666 667 668 669
}

/*****************************************************************************
 *
670
 *	Stuff from primnodes.h.
671 672 673 674
 *
 *****************************************************************************/

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

static void
694
_outFjoin(StringInfo str, Fjoin *node)
695
{
696
	int			i;
697

M
 
Marc G. Fournier 已提交
698
	appendStringInfo(str, " FJOIN :initialized %s :nNodes %d ",
699
					 booltostr(node->fj_initialized),
B
Bruce Momjian 已提交
700
					 node->fj_nNodes);
701 702 703 704

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

705 706
	appendStringInfo(str, " :results @ 0x%p :alwaysdone",
					 node->fj_results);
707 708

	for (i = 0; i < node->fj_nNodes; i++)
709 710
		appendStringInfo(str,
						 booltostr(node->fj_alwaysDone[i]));
711 712 713
}

/*
714
 *	Expr is a subclass of Node
715 716
 */
static void
717
_outExpr(StringInfo str, Expr *node)
718
{
719
	char	   *opstr = NULL;
720

M
 
Marc G. Fournier 已提交
721
	appendStringInfo(str, " EXPR :typeOid %u ",
B
Bruce Momjian 已提交
722
					 node->typeOid);
723 724 725

	switch (node->opType)
	{
726 727 728
		case OP_EXPR:
			opstr = "op";
			break;
729 730 731
		case DISTINCT_EXPR:
			opstr = "distinct";
			break;
732 733 734 735 736 737 738 739 740 741 742 743
		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 已提交
744 745 746
		case SUBPLAN_EXPR:
			opstr = "subp";
			break;
747
	}
748 749 750
	appendStringInfo(str, " :opType ");
	_outToken(str, opstr);
	appendStringInfo(str, " :oper ");
751
	_outNode(str, node->oper);
M
 
Marc G. Fournier 已提交
752

753
	appendStringInfo(str, " :args ");
754
	_outNode(str, node->args);
755 756 757
}

/*
758
 *	Var is a subclass of Expr
759 760
 */
static void
761
_outVar(StringInfo str, Var *node)
762
{
B
Bruce Momjian 已提交
763
	appendStringInfo(str,
764
				" VAR :varno %u :varattno %d :vartype %u :vartypmod %d ",
B
Bruce Momjian 已提交
765 766 767 768
					 node->varno,
					 node->varattno,
					 node->vartype,
					 node->vartypmod);
M
 
Marc G. Fournier 已提交
769

770
	appendStringInfo(str, " :varlevelsup %u :varnoold %u :varoattno %d",
B
Bruce Momjian 已提交
771 772 773
					 node->varlevelsup,
					 node->varnoold,
					 node->varoattno);
774 775 776
}

/*
777
 *	Const is a subclass of Expr
778 779
 */
static void
780
_outConst(StringInfo str, Const *node)
781
{
B
Bruce Momjian 已提交
782
	appendStringInfo(str,
783 784
					 " CONST :consttype %u :constlen %d :constbyval %s"
					 " :constisnull %s :constvalue ",
B
Bruce Momjian 已提交
785 786
					 node->consttype,
					 node->constlen,
787 788
					 booltostr(node->constbyval),
					 booltostr(node->constisnull));
M
 
Marc G. Fournier 已提交
789

790
	if (node->constisnull)
B
Bruce Momjian 已提交
791
		appendStringInfo(str, "<>");
792
	else
793
		_outDatum(str, node->constvalue, node->constlen, node->constbyval);
794 795 796
}

/*
B
Bruce Momjian 已提交
797
 *	Aggref
798 799
 */
static void
800
_outAggref(StringInfo str, Aggref *node)
801
{
802 803
	appendStringInfo(str, " AGGREG :aggfnoid %u :aggtype %u :target ",
					 node->aggfnoid, node->aggtype);
804
	_outNode(str, node->target);
M
 
Marc G. Fournier 已提交
805

806
	appendStringInfo(str, " :aggstar %s :aggdistinct %s ",
807 808
					 booltostr(node->aggstar),
					 booltostr(node->aggdistinct));
809
	/* aggno is not dumped */
810 811
}

812 813 814 815 816 817
/*
 *	SubLink
 */
static void
_outSubLink(StringInfo str, SubLink *node)
{
B
Bruce Momjian 已提交
818 819 820
	appendStringInfo(str,
					 " SUBLINK :subLinkType %d :useor %s :lefthand ",
					 node->subLinkType,
821
					 booltostr(node->useor));
822
	_outNode(str, node->lefthand);
M
 
Marc G. Fournier 已提交
823

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

827 828 829 830
	appendStringInfo(str, " :subselect ");
	_outNode(str, node->subselect);
}

831
/*
832
 *	ArrayRef is a subclass of Expr
833 834
 */
static void
B
Bruce Momjian 已提交
835
_outArrayRef(StringInfo str, ArrayRef *node)
836
{
B
Bruce Momjian 已提交
837
	appendStringInfo(str,
B
Bruce Momjian 已提交
838
		 " ARRAYREF :refrestype %u :refattrlength %d :refelemlength %d ",
839
					 node->refrestype,
B
Bruce Momjian 已提交
840 841
					 node->refattrlength,
					 node->refelemlength);
M
 
Marc G. Fournier 已提交
842

843
	appendStringInfo(str,
B
Bruce Momjian 已提交
844
				   ":refelembyval %s :refelemalign %c :refupperindexpr ",
845 846
					 booltostr(node->refelembyval),
					 node->refelemalign);
847 848
	_outNode(str, node->refupperindexpr);

849
	appendStringInfo(str, " :reflowerindexpr ");
850 851
	_outNode(str, node->reflowerindexpr);

852
	appendStringInfo(str, " :refexpr ");
853 854
	_outNode(str, node->refexpr);

855
	appendStringInfo(str, " :refassgnexpr ");
856
	_outNode(str, node->refassgnexpr);
857 858 859
}

/*
860
 *	Func is a subclass of Expr
861 862
 */
static void
863
_outFunc(StringInfo str, Func *node)
864
{
865
	appendStringInfo(str,
866
		" FUNC :funcid %u :funcresulttype %u :funcretset %s :funcformat %d ",
B
Bruce Momjian 已提交
867
					 node->funcid,
868
					 node->funcresulttype,
869 870
					 booltostr(node->funcretset),
					 (int) node->funcformat);
871 872 873
}

/*
874
 *	Oper is a subclass of Expr
875 876
 */
static void
877
_outOper(StringInfo str, Oper *node)
878
{
B
Bruce Momjian 已提交
879
	appendStringInfo(str,
B
Bruce Momjian 已提交
880
				" OPER :opno %u :opid %u :opresulttype %u :opretset %s ",
B
Bruce Momjian 已提交
881 882
					 node->opno,
					 node->opid,
883 884
					 node->opresulttype,
					 booltostr(node->opretset));
885 886 887
}

/*
888
 *	Param is a subclass of Expr
889 890
 */
static void
891
_outParam(StringInfo str, Param *node)
892
{
893
	appendStringInfo(str, " PARAM :paramkind %d :paramid %d :paramname ",
B
Bruce Momjian 已提交
894
					 node->paramkind,
895 896
					 node->paramid);
	_outToken(str, node->paramname);
897
	appendStringInfo(str, " :paramtype %u ", node->paramtype);
898 899
}

900 901 902 903 904 905 906 907 908 909
/*
 *	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 已提交
910
				   node->fieldnum, node->resulttype, node->resulttypmod);
911 912 913 914 915 916 917 918 919 920
}

/*
 *	RelabelType
 */
static void
_outRelabelType(StringInfo str, RelabelType *node)
{
	appendStringInfo(str, " RELABELTYPE :arg ");
	_outNode(str, node->arg);
921 922 923 924 925
	appendStringInfo(str,
					 " :resulttype %u :resulttypmod %d :relabelformat %d ",
					 node->resulttype,
					 node->resulttypmod,
					 (int) node->relabelformat);
926 927 928 929 930 931 932 933 934 935 936 937
}

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

938 939 940 941 942 943 944 945 946 947 948 949
/*
 *	FromExpr
 */
static void
_outFromExpr(StringInfo str, FromExpr *node)
{
	appendStringInfo(str, " FROMEXPR :fromlist ");
	_outNode(str, node->fromlist);
	appendStringInfo(str, " :quals ");
	_outNode(str, node->quals);
}

950 951 952 953 954 955 956 957
/*
 *	JoinExpr
 */
static void
_outJoinExpr(StringInfo str, JoinExpr *node)
{
	appendStringInfo(str, " JOINEXPR :jointype %d :isNatural %s :larg ",
					 (int) node->jointype,
958
					 booltostr(node->isNatural));
959 960 961 962 963 964 965 966 967
	_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);
968
	appendStringInfo(str, " :rtindex %d ", node->rtindex);
969 970
}

971
/*
972
 *	TargetEntry is a subclass of Node.
973 974
 */
static void
975
_outTargetEntry(StringInfo str, TargetEntry *node)
976
{
M
 
Marc G. Fournier 已提交
977
	appendStringInfo(str, " TARGETENTRY :resdom ");
978 979
	_outNode(str, node->resdom);

980 981
	appendStringInfo(str, " :expr ");
	_outNode(str, node->expr);
982
}
983

984 985 986 987 988 989 990 991 992
static void
_outAlias(StringInfo str, Alias *node)
{
	appendStringInfo(str, " ALIAS :aliasname ");
	_outToken(str, node->aliasname);
	appendStringInfo(str, " :colnames ");
	_outNode(str, node->colnames);
}

993
static void
994
_outRangeTblEntry(StringInfo str, RangeTblEntry *node)
995
{
996 997
	/* put alias + eref first to make dump more legible */
	appendStringInfo(str, " RTE :alias ");
998 999 1000
	_outNode(str, node->alias);
	appendStringInfo(str, " :eref ");
	_outNode(str, node->eref);
1001 1002 1003 1004 1005 1006
	appendStringInfo(str, " :rtekind %d ",
					 (int) node->rtekind);
	switch (node->rtekind)
	{
		case RTE_RELATION:
		case RTE_SPECIAL:
1007
			appendStringInfo(str, ":relid %u", node->relid);
1008 1009 1010 1011 1012
			break;
		case RTE_SUBQUERY:
			appendStringInfo(str, ":subquery ");
			_outNode(str, node->subquery);
			break;
1013 1014 1015
		case RTE_FUNCTION:
			appendStringInfo(str, ":funcexpr ");
			_outNode(str, node->funcexpr);
1016
			appendStringInfo(str, " :coldeflist ");
1017
			_outNode(str, node->coldeflist);
1018
			break;
1019
		case RTE_JOIN:
1020
			appendStringInfo(str, ":jointype %d :joinaliasvars ",
1021
							 (int) node->jointype);
1022
			_outNode(str, node->joinaliasvars);
1023 1024 1025 1026 1027
			break;
		default:
			elog(ERROR, "bogus rte kind %d", (int) node->rtekind);
			break;
	}
1028 1029
	appendStringInfo(str, " :inh %s :inFromCl %s :checkForRead %s"
					 " :checkForWrite %s :checkAsUser %u",
1030 1031 1032 1033
					 booltostr(node->inh),
					 booltostr(node->inFromCl),
					 booltostr(node->checkForRead),
					 booltostr(node->checkForWrite),
1034
					 node->checkAsUser);
1035 1036
}

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

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

1064 1065
	appendStringInfo(str, " :indexinfo ");
	_outNode(str, node->indexinfo);
1066

1067
	appendStringInfo(str, " :indexqual ");
1068
	_outNode(str, node->indexqual);
1069

1070 1071
	appendStringInfo(str, " :indexscandir %d :joinrelids ",
					 (int) node->indexscandir);
1072
	_outIntList(str, node->joinrelids);
1073

1074
	appendStringInfo(str, " :alljoinquals %s :rows %.2f ",
1075
					 booltostr(node->alljoinquals),
1076
					 node->rows);
1077 1078
}

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

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

1095
	appendStringInfo(str, " :unjoined_relids ");
1096 1097 1098
	_outIntList(str, node->unjoined_relids);
}

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

1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135
/*
 *	ResultPath is a subclass of Path.
 */
static void
_outResultPath(StringInfo str, ResultPath *node)
{
	appendStringInfo(str,
					 " RESULTPATH :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, " :subpath ");
	_outNode(str, node->subpath);

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

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

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

1177
	appendStringInfo(str, " :path_mergeclauses ");
1178 1179
	_outNode(str, node->path_mergeclauses);

1180
	appendStringInfo(str, " :outersortkeys ");
1181 1182
	_outNode(str, node->outersortkeys);

1183
	appendStringInfo(str, " :innersortkeys ");
1184
	_outNode(str, node->innersortkeys);
1185 1186 1187
}

/*
1188
 *	HashPath is a subclass of NestPath.
1189 1190
 */
static void
1191
_outHashPath(StringInfo str, HashPath *node)
1192
{
B
Bruce Momjian 已提交
1193
	appendStringInfo(str,
1194
					 " HASHPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
B
Bruce Momjian 已提交
1195
					 node->jpath.path.pathtype,
1196 1197
					 node->jpath.path.startup_cost,
					 node->jpath.path.total_cost);
1198
	_outNode(str, node->jpath.path.pathkeys);
1199 1200
	appendStringInfo(str, " :jointype %d :outerjoinpath ",
					 (int) node->jpath.jointype);
1201 1202 1203 1204 1205
	_outNode(str, node->jpath.outerjoinpath);
	appendStringInfo(str, " :innerjoinpath ");
	_outNode(str, node->jpath.innerjoinpath);
	appendStringInfo(str, " :joinrestrictinfo ");
	_outNode(str, node->jpath.joinrestrictinfo);
1206

1207
	appendStringInfo(str, " :path_hashclauses ");
1208
	_outNode(str, node->path_hashclauses);
1209 1210 1211
}

/*
1212
 *	PathKeyItem is a subclass of Node.
1213 1214
 */
static void
1215
_outPathKeyItem(StringInfo str, PathKeyItem *node)
1216
{
1217 1218 1219
	appendStringInfo(str, " PATHKEYITEM :sortop %u :key ",
					 node->sortop);
	_outNode(str, node->key);
1220 1221 1222
}

/*
1223
 *	RestrictInfo is a subclass of Node.
1224 1225
 */
static void
1226
_outRestrictInfo(StringInfo str, RestrictInfo *node)
1227
{
B
Bruce Momjian 已提交
1228
	appendStringInfo(str, " RESTRICTINFO :clause ");
1229 1230
	_outNode(str, node->clause);

1231
	appendStringInfo(str, " :ispusheddown %s :subclauseindices ",
1232
					 booltostr(node->ispusheddown));
1233
	_outNode(str, node->subclauseindices);
1234

1235 1236 1237
	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 已提交
1238
	appendStringInfo(str, " :hashjoinoperator %u ", node->hashjoinoperator);
1239 1240 1241
}

/*
1242
 *	JoinInfo is a subclass of Node.
1243 1244
 */
static void
1245
_outJoinInfo(StringInfo str, JoinInfo *node)
1246
{
B
Bruce Momjian 已提交
1247 1248
	appendStringInfo(str, " JINFO :unjoined_relids ");
	_outIntList(str, node->unjoined_relids);
1249

1250 1251
	appendStringInfo(str, " :jinfo_restrictinfo ");
	_outNode(str, node->jinfo_restrictinfo);
1252 1253 1254 1255 1256 1257
}

/*
 * Print the value of a Datum given its type.
 */
static void
1258
_outDatum(StringInfo str, Datum value, int typlen, bool typbyval)
1259
{
1260 1261
	Size		length,
				i;
1262
	char	   *s;
1263

1264
	length = datumGetSize(value, typbyval, typlen);
1265

1266
	if (typbyval)
1267 1268
	{
		s = (char *) (&value);
1269
		appendStringInfo(str, " %u [ ", (unsigned int) length);
1270
		for (i = 0; i < (Size) sizeof(Datum); i++)
1271
			appendStringInfo(str, "%d ", (int) (s[i]));
M
 
Marc G. Fournier 已提交
1272
		appendStringInfo(str, "] ");
1273
	}
1274
	else
1275
	{
1276 1277
		s = (char *) DatumGetPointer(value);
		if (!PointerIsValid(s))
M
 
Marc G. Fournier 已提交
1278
			appendStringInfo(str, " 0 [ ] ");
1279 1280
		else
		{
1281
			appendStringInfo(str, " %u [ ", (unsigned int) length);
1282
			for (i = 0; i < length; i++)
1283
				appendStringInfo(str, "%d ", (int) (s[i]));
M
 
Marc G. Fournier 已提交
1284
			appendStringInfo(str, "] ");
1285
		}
1286 1287 1288
	}
}

1289 1290 1291
static void
_outAExpr(StringInfo str, A_Expr *node)
{
1292
	appendStringInfo(str, " AEXPR ");
1293 1294 1295
	switch (node->oper)
	{
		case AND:
1296
			appendStringInfo(str, "AND ");
1297 1298
			break;
		case OR:
1299
			appendStringInfo(str, "OR ");
1300 1301
			break;
		case NOT:
1302
			appendStringInfo(str, "NOT ");
1303
			break;
1304
		case OP:
1305
			_outNode(str, node->name);
1306
			appendStringInfo(str, " ");
1307
			break;
1308 1309 1310
		default:
			appendStringInfo(str, "?? ");
			break;
1311
	}
1312
	_outNode(str, node->lexpr);
1313
	appendStringInfo(str, " ");
1314 1315 1316
	_outNode(str, node->rexpr);
}

1317
static void
1318
_outValue(StringInfo str, Value *value)
1319
{
1320 1321
	switch (value->type)
	{
1322
		case T_Integer:
1323
			appendStringInfo(str, " %ld ", value->val.ival);
1324 1325
			break;
		case T_Float:
1326 1327 1328 1329

			/*
			 * We assume the value is a valid numeric literal and so does
			 * not need quoting.
1330 1331 1332 1333 1334 1335 1336
			 */
			appendStringInfo(str, " %s ", value->val.str);
			break;
		case T_String:
			appendStringInfo(str, " \"");
			_outToken(str, value->val.str);
			appendStringInfo(str, "\" ");
1337
			break;
1338
		case T_BitString:
1339 1340
			/* internal representation already has leading 'b' */
			appendStringInfo(str, " %s ", value->val.str);
1341
			break;
1342
		default:
B
Bruce Momjian 已提交
1343
			elog(WARNING, "_outValue: don't know how to print type %d ",
1344
				 value->type);
1345
			break;
1346
	}
1347 1348
}

1349
static void
1350
_outRangeVar(StringInfo str, RangeVar *node)
1351
{
1352
	appendStringInfo(str, " RANGEVAR :relation ");
B
Bruce Momjian 已提交
1353

1354 1355 1356 1357 1358 1359 1360 1361
	/*
	 * 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",
B
Bruce Momjian 已提交
1362 1363
					 (int) node->inhOpt,
					 booltostr(node->istemp));
1364 1365
	appendStringInfo(str, " :alias ");
	_outNode(str, node->alias);
1366 1367
}

1368
static void
1369
_outColumnRef(StringInfo str, ColumnRef *node)
1370
{
1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385
	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);
}

1386 1387 1388
static void
_outAConst(StringInfo str, A_Const *node)
{
1389
	appendStringInfo(str, "CONST ");
1390
	_outValue(str, &(node->val));
1391 1392
	appendStringInfo(str, " :typename ");
	_outNode(str, node->typename);
1393 1394
}

1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405
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 已提交
1406 1407 1408
static void
_outConstraint(StringInfo str, Constraint *node)
{
1409
	appendStringInfo(str, " CONSTRAINT :name ");
1410 1411
	_outToken(str, node->name);
	appendStringInfo(str, " :type ");
T
Thomas G. Lockhart 已提交
1412 1413 1414 1415

	switch (node->contype)
	{
		case CONSTR_PRIMARY:
1416
			appendStringInfo(str, "PRIMARY_KEY :keys ");
T
Thomas G. Lockhart 已提交
1417 1418 1419 1420
			_outNode(str, node->keys);
			break;

		case CONSTR_CHECK:
1421
			appendStringInfo(str, "CHECK :raw ");
1422
			_outNode(str, node->raw_expr);
1423 1424
			appendStringInfo(str, " :cooked ");
			_outToken(str, node->cooked_expr);
T
Thomas G. Lockhart 已提交
1425 1426 1427
			break;

		case CONSTR_DEFAULT:
1428
			appendStringInfo(str, "DEFAULT :raw ");
1429
			_outNode(str, node->raw_expr);
1430 1431
			appendStringInfo(str, " :cooked ");
			_outToken(str, node->cooked_expr);
T
Thomas G. Lockhart 已提交
1432 1433 1434
			break;

		case CONSTR_NOTNULL:
1435
			appendStringInfo(str, "NOT_NULL");
T
Thomas G. Lockhart 已提交
1436 1437 1438
			break;

		case CONSTR_UNIQUE:
1439
			appendStringInfo(str, "UNIQUE :keys ");
T
Thomas G. Lockhart 已提交
1440 1441 1442 1443
			_outNode(str, node->keys);
			break;

		default:
1444
			appendStringInfo(str, "<unrecognized_constraint>");
T
Thomas G. Lockhart 已提交
1445 1446 1447 1448
			break;
	}
}

1449 1450 1451 1452 1453
static void
_outFkConstraint(StringInfo str, FkConstraint *node)
{
	appendStringInfo(str, " FKCONSTRAINT :constr_name ");
	_outToken(str, node->constr_name);
1454 1455
	appendStringInfo(str, " :pktable ");
	_outNode(str, node->pktable);
1456 1457 1458 1459
	appendStringInfo(str, " :fk_attrs ");
	_outNode(str, node->fk_attrs);
	appendStringInfo(str, " :pk_attrs ");
	_outNode(str, node->pk_attrs);
1460 1461 1462 1463
	appendStringInfo(str, " :fk_matchtype %c :fk_upd_action %c :fk_del_action %c :deferrable %s :initdeferred %s :skip_validation %s",
					 node->fk_matchtype,
					 node->fk_upd_action,
					 node->fk_del_action,
1464
					 booltostr(node->deferrable),
1465 1466
					 booltostr(node->initdeferred),
					 booltostr(node->skip_validation));
1467 1468
}

T
Thomas G. Lockhart 已提交
1469
static void
1470
_outCaseExpr(StringInfo str, CaseExpr *node)
T
Thomas G. Lockhart 已提交
1471
{
1472 1473 1474 1475 1476
	appendStringInfo(str, " CASE :casetype %u :arg ",
					 node->casetype);
	_outNode(str, node->arg);

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

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

static void
1484
_outCaseWhen(StringInfo str, CaseWhen *node)
T
Thomas G. Lockhart 已提交
1485
{
1486
	appendStringInfo(str, " WHEN ");
T
Thomas G. Lockhart 已提交
1487
	_outNode(str, node->expr);
M
 
Marc G. Fournier 已提交
1488

1489
	appendStringInfo(str, " :then ");
T
Thomas G. Lockhart 已提交
1490 1491 1492
	_outNode(str, node->result);
}

1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516
/*
 *	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);
}

1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527
/*
 *	ConstraintTest
 */
static void
_outConstraintTest(StringInfo str, ConstraintTest *node)
{
	appendStringInfo(str, " CONSTRAINTTEST :arg ");
	_outNode(str, node->arg);
	appendStringInfo(str, " :testtype %d :name ",
					 (int) node->testtype);
	_outToken(str, node->name);
B
Bruce Momjian 已提交
1528 1529
	appendStringInfo(str, " :domain ");
	_outToken(str, node->domname);
1530 1531 1532 1533
	appendStringInfo(str, " :check_expr ");
	_outNode(str, node->check_expr);
}

B
Bruce Momjian 已提交
1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553
/*
 *	ConstraintTestValue
 */
static void
_outConstraintTestValue(StringInfo str, ConstraintTestValue *node)
{
	appendStringInfo(str, " CONSTRAINTTESTVALUE :typeid %u :typemod %d ",
					 node->typeId,
					 node->typeMod);
}

/*
 *	DomainConstraintValue
 */
static void
_outDomainConstraintValue(StringInfo str, DomainConstraintValue *node)
{
	appendStringInfo(str, " DOMAINCONSTRAINTVALUE ");
}

1554 1555
/*
 * _outNode -
1556
 *	  converts a Node into ascii string and append it to 'str'
1557 1558 1559 1560
 */
static void
_outNode(StringInfo str, void *obj)
{
1561 1562
	if (obj == NULL)
	{
B
Bruce Momjian 已提交
1563
		appendStringInfo(str, "<>");
1564 1565
		return;
	}
1566

1567
	if (IsA(obj, List))
1568
	{
1569
		List	   *l;
1570

1571
		appendStringInfoChar(str, '(');
1572 1573 1574 1575
		foreach(l, (List *) obj)
		{
			_outNode(str, lfirst(l));
			if (lnext(l))
1576
				appendStringInfoChar(str, ' ');
1577
		}
1578
		appendStringInfoChar(str, ')');
1579
	}
1580
	else if (IsA(obj, Integer) || IsA(obj, Float) || IsA(obj, String) || IsA(obj, BitString))
1581 1582 1583 1584
	{
		/* nodeRead does not want to see { } around these! */
		_outValue(str, obj);
	}
1585 1586
	else
	{
1587
		appendStringInfoChar(str, '{');
1588 1589
		switch (nodeTag(obj))
		{
1590 1591 1592 1593 1594 1595
			case T_CreateStmt:
				_outCreateStmt(str, obj);
				break;
			case T_IndexStmt:
				_outIndexStmt(str, obj);
				break;
1596 1597 1598 1599 1600 1601
			case T_NotifyStmt:
				_outNotifyStmt(str, obj);
				break;
			case T_SelectStmt:
				_outSelectStmt(str, obj);
				break;
1602 1603 1604
			case T_ColumnDef:
				_outColumnDef(str, obj);
				break;
1605 1606 1607
			case T_TypeName:
				_outTypeName(str, obj);
				break;
1608 1609 1610
			case T_TypeCast:
				_outTypeCast(str, obj);
				break;
1611 1612 1613
			case T_IndexElem:
				_outIndexElem(str, obj);
				break;
1614 1615 1616
			case T_Query:
				_outQuery(str, obj);
				break;
1617 1618 1619 1620 1621
			case T_SortClause:
				_outSortClause(str, obj);
				break;
			case T_GroupClause:
				_outGroupClause(str, obj);
1622
				break;
1623 1624 1625
			case T_SetOperationStmt:
				_outSetOperationStmt(str, obj);
				break;
1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655
			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;
1656 1657 1658
			case T_TidScan:
				_outTidScan(str, obj);
				break;
1659 1660 1661
			case T_SubqueryScan:
				_outSubqueryScan(str, obj);
				break;
1662 1663 1664
			case T_FunctionScan:
				_outFunctionScan(str, obj);
				break;
1665 1666 1667
			case T_Material:
				_outMaterial(str, obj);
				break;
1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679
			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;
1680 1681 1682
			case T_SetOp:
				_outSetOp(str, obj);
				break;
1683 1684 1685
			case T_Limit:
				_outLimit(str, obj);
				break;
1686 1687 1688
			case T_Hash:
				_outHash(str, obj);
				break;
V
Vadim B. Mikheev 已提交
1689 1690 1691
			case T_SubPlan:
				_outSubPlan(str, obj);
				break;
1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706
			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 已提交
1707 1708
			case T_Aggref:
				_outAggref(str, obj);
1709
				break;
1710 1711 1712
			case T_SubLink:
				_outSubLink(str, obj);
				break;
1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724
			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;
1725 1726 1727 1728 1729 1730 1731 1732 1733
			case T_FieldSelect:
				_outFieldSelect(str, obj);
				break;
			case T_RelabelType:
				_outRelabelType(str, obj);
				break;
			case T_RangeTblRef:
				_outRangeTblRef(str, obj);
				break;
1734 1735 1736
			case T_FromExpr:
				_outFromExpr(str, obj);
				break;
1737 1738 1739
			case T_JoinExpr:
				_outJoinExpr(str, obj);
				break;
1740 1741 1742
			case T_TargetEntry:
				_outTargetEntry(str, obj);
				break;
1743 1744 1745
			case T_Alias:
				_outAlias(str, obj);
				break;
1746 1747 1748 1749 1750 1751 1752 1753 1754
			case T_RangeTblEntry:
				_outRangeTblEntry(str, obj);
				break;
			case T_Path:
				_outPath(str, obj);
				break;
			case T_IndexPath:
				_outIndexPath(str, obj);
				break;
1755 1756 1757
			case T_TidPath:
				_outTidPath(str, obj);
				break;
1758 1759 1760
			case T_AppendPath:
				_outAppendPath(str, obj);
				break;
1761 1762 1763
			case T_ResultPath:
				_outResultPath(str, obj);
				break;
1764 1765
			case T_NestPath:
				_outNestPath(str, obj);
1766 1767 1768 1769 1770 1771 1772
				break;
			case T_MergePath:
				_outMergePath(str, obj);
				break;
			case T_HashPath:
				_outHashPath(str, obj);
				break;
1773 1774
			case T_PathKeyItem:
				_outPathKeyItem(str, obj);
1775
				break;
1776 1777
			case T_RestrictInfo:
				_outRestrictInfo(str, obj);
1778
				break;
1779 1780
			case T_JoinInfo:
				_outJoinInfo(str, obj);
1781
				break;
1782 1783 1784
			case T_A_Expr:
				_outAExpr(str, obj);
				break;
1785 1786 1787 1788 1789 1790 1791 1792 1793
			case T_RangeVar:
				_outRangeVar(str, obj);
				break;
			case T_ColumnRef:
				_outColumnRef(str, obj);
				break;
			case T_ParamRef:
				_outParamRef(str, obj);
				break;
1794 1795 1796
			case T_A_Const:
				_outAConst(str, obj);
				break;
1797 1798 1799
			case T_ExprFieldSelect:
				_outExprFieldSelect(str, obj);
				break;
T
Thomas G. Lockhart 已提交
1800 1801 1802
			case T_Constraint:
				_outConstraint(str, obj);
				break;
1803 1804 1805
			case T_FkConstraint:
				_outFkConstraint(str, obj);
				break;
T
Thomas G. Lockhart 已提交
1806 1807 1808 1809 1810 1811
			case T_CaseExpr:
				_outCaseExpr(str, obj);
				break;
			case T_CaseWhen:
				_outCaseWhen(str, obj);
				break;
1812 1813 1814 1815 1816 1817
			case T_NullTest:
				_outNullTest(str, obj);
				break;
			case T_BooleanTest:
				_outBooleanTest(str, obj);
				break;
1818 1819 1820
			case T_ConstraintTest:
				_outConstraintTest(str, obj);
				break;
B
Bruce Momjian 已提交
1821 1822 1823
			case T_ConstraintTestValue:
				_outConstraintTestValue(str, obj);
				break;
1824 1825 1826
			case T_FuncCall:
				_outFuncCall(str, obj);
				break;
B
Bruce Momjian 已提交
1827 1828 1829
			case T_DomainConstraintValue:
				_outDomainConstraintValue(str, obj);
				break;
1830

1831
			default:
B
Bruce Momjian 已提交
1832
				elog(WARNING, "_outNode: don't know how to print type %d ",
1833 1834
					 nodeTag(obj));
				break;
1835
		}
1836
		appendStringInfoChar(str, '}');
1837 1838 1839 1840 1841
	}
}

/*
 * nodeToString -
1842
 *	   returns the ascii representation of the Node as a palloc'd string
1843
 */
1844
char *
1845 1846
nodeToString(void *obj)
{
B
Bruce Momjian 已提交
1847
	StringInfoData str;
1848

1849 1850 1851 1852
	/* see stringinfo.h for an explanation of this maneuver */
	initStringInfo(&str);
	_outNode(&str, obj);
	return str.data;
1853
}