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

18 19
#include <ctype.h>

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

29

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

270 271 272
	appendStringInfo(str, " :jointree ");
	_outNode(str, node->jointree);

273 274 275
	appendStringInfo(str, " :rowMarks ");
	_outIntList(str, node->rowMarks);

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

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

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

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

288 289
	appendStringInfo(str, " :sortClause ");
	_outNode(str, node->sortClause);
290

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

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

	appendStringInfo(str, " :setOperations ");
	_outNode(str, node->setOperations);
299 300 301

	appendStringInfo(str, " :resultRelations ");
	_outIntList(str, node->resultRelations);
302 303 304
}

static void
305
_outSortClause(StringInfo str, SortClause *node)
306
{
307
	appendStringInfo(str, " SORTCLAUSE :tleSortGroupRef %u :sortop %u ",
308
					 node->tleSortGroupRef, node->sortop);
309 310 311 312 313
}

static void
_outGroupClause(StringInfo str, GroupClause *node)
{
314
	appendStringInfo(str, " GROUPCLAUSE :tleSortGroupRef %u :sortop %u ",
315
					 node->tleSortGroupRef, node->sortop);
316 317
}

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

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

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

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

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

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

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

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

M
 
Marc G. Fournier 已提交
365
	appendStringInfo(str, " :nprm %d ", node->nParamExec);
366 367 368
}

/*
369
 *	Stuff from plannodes.h
370 371
 */
static void
372
_outPlan(StringInfo str, Plan *node)
373
{
374
	appendStringInfo(str, " PLAN ");
375
	_outPlanInfo(str, (Plan *) node);
376 377 378
}

static void
379
_outResult(StringInfo str, Result *node)
380
{
381
	appendStringInfo(str, " RESULT ");
382 383
	_outPlanInfo(str, (Plan *) node);

384
	appendStringInfo(str, " :resconstantqual ");
385 386
	_outNode(str, node->resconstantqual);

387 388 389
}

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

398 399
	appendStringInfo(str, " :appendplans ");
	_outNode(str, node->appendplans);
400

401
	appendStringInfo(str, " :isTarget %s ",
402
					 booltostr(node->isTarget));
403 404 405
}

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

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

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

443
	appendStringInfo(str, " :mergeclauses ");
444
	_outNode(str, node->mergeclauses);
445 446 447
}

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

459
	appendStringInfo(str, " :hashclauses ");
460
	_outNode(str, node->hashclauses);
461
	appendStringInfo(str, " :hashjoinop %u ",
B
Bruce Momjian 已提交
462
					 node->hashjoinop);
463 464
}

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

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

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

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

V
Vadim B. Mikheev 已提交
480 481 482 483
	appendStringInfo(str, " :slink ");
	_outNode(str, node->sublink);
}

484
/*
485
 *	Scan is a subclass of Node
486 487
 */
static void
488
_outScan(StringInfo str, Scan *node)
489
{
490
	appendStringInfo(str, " SCAN ");
491 492
	_outPlanInfo(str, (Plan *) node);

493
	appendStringInfo(str, " :scanrelid %u ", node->scanrelid);
494 495 496
}

/*
497
 *	SeqScan is a subclass of Scan
498 499
 */
static void
500
_outSeqScan(StringInfo str, SeqScan *node)
501
{
502
	appendStringInfo(str, " SEQSCAN ");
503 504
	_outPlanInfo(str, (Plan *) node);

505
	appendStringInfo(str, " :scanrelid %u ", node->scanrelid);
506 507 508
}

/*
509
 *	IndexScan is a subclass of Scan
510 511
 */
static void
512
_outIndexScan(StringInfo str, IndexScan *node)
513
{
514
	appendStringInfo(str, " INDEXSCAN ");
515 516
	_outPlanInfo(str, (Plan *) node);

517
	appendStringInfo(str, " :scanrelid %u :indxid ", node->scan.scanrelid);
518
	_outOidList(str, node->indxid);
519

520
	appendStringInfo(str, " :indxqual ");
521 522
	_outNode(str, node->indxqual);

V
Vadim B. Mikheev 已提交
523 524 525
	appendStringInfo(str, " :indxqualorig ");
	_outNode(str, node->indxqualorig);

526
	appendStringInfo(str, " :indxorderdir %d ", node->indxorderdir);
527 528
}

529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545
/*
 *	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);

}

546 547 548 549 550 551 552 553 554 555 556 557 558
/*
 *	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);
}

559 560 561 562 563 564 565 566 567 568 569 570
/*
 *	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);
}

571
/*
572
 *	Material is a subclass of Plan
573 574 575 576 577 578 579 580
 */
static void
_outMaterial(StringInfo str, Material *node)
{
	appendStringInfo(str, " MATERIAL ");
	_outPlanInfo(str, (Plan *) node);
}

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

static void
B
Bruce Momjian 已提交
593
_outAgg(StringInfo str, Agg *node)
594
{
595
	appendStringInfo(str, " AGG ");
596
	_outPlanInfo(str, (Plan *) node);
597 598 599
}

static void
600
_outGroup(StringInfo str, Group *node)
601
{
602
	appendStringInfo(str, " GRP ");
603 604 605
	_outPlanInfo(str, (Plan *) node);

	/* the actual Group fields */
M
 
Marc G. Fournier 已提交
606
	appendStringInfo(str, " :numCols %d :tuplePerGroup %s ",
B
Bruce Momjian 已提交
607
					 node->numCols,
608
					 booltostr(node->tuplePerGroup));
609
}
610

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

616
	appendStringInfo(str, " UNIQUE ");
617 618
	_outPlanInfo(str, (Plan *) node);

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

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

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

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

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

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

/*****************************************************************************
 *
668
 *	Stuff from primnodes.h.
669 670 671 672
 *
 *****************************************************************************/

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

847
	appendStringInfo(str, " :reflowerindexpr ");
848 849
	_outNode(str, node->reflowerindexpr);

850
	appendStringInfo(str, " :refexpr ");
851 852
	_outNode(str, node->refexpr);

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

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

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

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

898 899 900 901 902 903 904 905 906 907
/*
 *	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 已提交
908
				   node->fieldnum, node->resulttype, node->resulttypmod);
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);
919 920 921 922 923
	appendStringInfo(str,
					 " :resulttype %u :resulttypmod %d :relabelformat %d ",
					 node->resulttype,
					 node->resulttypmod,
					 (int) node->relabelformat);
924 925 926 927 928 929 930 931 932 933 934 935
}

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

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

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

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

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

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

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

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

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

1062 1063
	appendStringInfo(str, " :indexinfo ");
	_outNode(str, node->indexinfo);
1064

1065
	appendStringInfo(str, " :indexqual ");
1066
	_outNode(str, node->indexqual);
1067

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

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

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

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

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

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

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

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

1155
	appendStringInfo(str, " :path_mergeclauses ");
1156 1157
	_outNode(str, node->path_mergeclauses);

1158
	appendStringInfo(str, " :outersortkeys ");
1159 1160
	_outNode(str, node->outersortkeys);

1161
	appendStringInfo(str, " :innersortkeys ");
1162
	_outNode(str, node->innersortkeys);
1163 1164 1165
}

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

1185
	appendStringInfo(str, " :path_hashclauses ");
1186
	_outNode(str, node->path_hashclauses);
1187 1188 1189
}

/*
1190
 *	PathKeyItem is a subclass of Node.
1191 1192
 */
static void
1193
_outPathKeyItem(StringInfo str, PathKeyItem *node)
1194
{
1195 1196 1197
	appendStringInfo(str, " PATHKEYITEM :sortop %u :key ",
					 node->sortop);
	_outNode(str, node->key);
1198 1199 1200
}

/*
1201
 *	RestrictInfo is a subclass of Node.
1202 1203
 */
static void
1204
_outRestrictInfo(StringInfo str, RestrictInfo *node)
1205
{
B
Bruce Momjian 已提交
1206
	appendStringInfo(str, " RESTRICTINFO :clause ");
1207 1208
	_outNode(str, node->clause);

1209
	appendStringInfo(str, " :ispusheddown %s :subclauseindices ",
1210
					 booltostr(node->ispusheddown));
1211
	_outNode(str, node->subclauseindices);
1212

1213 1214 1215
	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 已提交
1216
	appendStringInfo(str, " :hashjoinoperator %u ", node->hashjoinoperator);
1217 1218 1219
}

/*
1220
 *	JoinInfo is a subclass of Node.
1221 1222
 */
static void
1223
_outJoinInfo(StringInfo str, JoinInfo *node)
1224
{
B
Bruce Momjian 已提交
1225 1226
	appendStringInfo(str, " JINFO :unjoined_relids ");
	_outIntList(str, node->unjoined_relids);
1227

1228 1229
	appendStringInfo(str, " :jinfo_restrictinfo ");
	_outNode(str, node->jinfo_restrictinfo);
1230 1231 1232 1233 1234 1235
}

/*
 * Print the value of a Datum given its type.
 */
static void
1236
_outDatum(StringInfo str, Datum value, int typlen, bool typbyval)
1237
{
1238 1239
	Size		length,
				i;
1240
	char	   *s;
1241

1242
	length = datumGetSize(value, typbyval, typlen);
1243

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

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

1295
static void
1296
_outValue(StringInfo str, Value *value)
1297
{
1298 1299
	switch (value->type)
	{
1300
		case T_Integer:
1301
			appendStringInfo(str, " %ld ", value->val.ival);
1302 1303
			break;
		case T_Float:
1304 1305 1306 1307

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

1327
static void
1328
_outRangeVar(StringInfo str, RangeVar *node)
1329
{
1330
	appendStringInfo(str, " RANGEVAR :relation ");
B
Bruce Momjian 已提交
1331

1332 1333 1334 1335 1336 1337 1338 1339
	/*
	 * 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 已提交
1340 1341
					 (int) node->inhOpt,
					 booltostr(node->istemp));
1342 1343
	appendStringInfo(str, " :alias ");
	_outNode(str, node->alias);
1344 1345
}

1346
static void
1347
_outColumnRef(StringInfo str, ColumnRef *node)
1348
{
1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363
	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);
}

1364 1365 1366
static void
_outAConst(StringInfo str, A_Const *node)
{
1367
	appendStringInfo(str, "CONST ");
1368
	_outValue(str, &(node->val));
1369 1370
	appendStringInfo(str, " :typename ");
	_outNode(str, node->typename);
1371 1372
}

1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383
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 已提交
1384 1385 1386
static void
_outConstraint(StringInfo str, Constraint *node)
{
1387
	appendStringInfo(str, " CONSTRAINT :name ");
1388 1389
	_outToken(str, node->name);
	appendStringInfo(str, " :type ");
T
Thomas G. Lockhart 已提交
1390 1391 1392 1393

	switch (node->contype)
	{
		case CONSTR_PRIMARY:
1394
			appendStringInfo(str, "PRIMARY_KEY :keys ");
T
Thomas G. Lockhart 已提交
1395 1396 1397 1398
			_outNode(str, node->keys);
			break;

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

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

		case CONSTR_NOTNULL:
1413
			appendStringInfo(str, "NOT_NULL");
T
Thomas G. Lockhart 已提交
1414 1415 1416
			break;

		case CONSTR_UNIQUE:
1417
			appendStringInfo(str, "UNIQUE :keys ");
T
Thomas G. Lockhart 已提交
1418 1419 1420 1421
			_outNode(str, node->keys);
			break;

		default:
1422
			appendStringInfo(str, "<unrecognized_constraint>");
T
Thomas G. Lockhart 已提交
1423 1424 1425 1426
			break;
	}
}

1427 1428 1429 1430 1431
static void
_outFkConstraint(StringInfo str, FkConstraint *node)
{
	appendStringInfo(str, " FKCONSTRAINT :constr_name ");
	_outToken(str, node->constr_name);
1432 1433
	appendStringInfo(str, " :pktable ");
	_outNode(str, node->pktable);
1434 1435 1436 1437
	appendStringInfo(str, " :fk_attrs ");
	_outNode(str, node->fk_attrs);
	appendStringInfo(str, " :pk_attrs ");
	_outNode(str, node->pk_attrs);
1438 1439 1440 1441
	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,
1442
					 booltostr(node->deferrable),
1443 1444
					 booltostr(node->initdeferred),
					 booltostr(node->skip_validation));
1445 1446
}

T
Thomas G. Lockhart 已提交
1447
static void
1448
_outCaseExpr(StringInfo str, CaseExpr *node)
T
Thomas G. Lockhart 已提交
1449
{
1450 1451 1452 1453 1454
	appendStringInfo(str, " CASE :casetype %u :arg ",
					 node->casetype);
	_outNode(str, node->arg);

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

1457
	appendStringInfo(str, " :defresult ");
T
Thomas G. Lockhart 已提交
1458 1459 1460 1461
	_outNode(str, node->defresult);
}

static void
1462
_outCaseWhen(StringInfo str, CaseWhen *node)
T
Thomas G. Lockhart 已提交
1463
{
1464
	appendStringInfo(str, " WHEN ");
T
Thomas G. Lockhart 已提交
1465
	_outNode(str, node->expr);
M
 
Marc G. Fournier 已提交
1466

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

1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494
/*
 *	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);
}

1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509
/*
 *	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);
	appendStringInfo(str, " :check_expr ");
	_outNode(str, node->check_expr);
}

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

1523
	if (IsA(obj, List))
1524
	{
1525
		List	   *l;
1526

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

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

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

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