outfuncs.c 39.3 KB
Newer Older
M
 
Marc G. Fournier 已提交
1
/*
2
 *
3
 * outfuncs.c
4
 *	  routines to convert a node to ascii representation
5
 *
B
Add:  
Bruce Momjian 已提交
6 7
 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
 * Portions Copyright (c) 1994, Regents of the University of California
8
 *
9
 *	$Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.135 2000/12/03 20:45:33 tgl Exp $
10 11
 *
 * NOTES
12 13 14 15 16
 *	  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
 *	  catalogs (eg. indexes). This is also the plan string sent out in
 *	  Mariposa.
17
 *
18 19 20
 *	  These functions update the in/out argument of type StringInfo
 *	  passed to them. This argument contains the string holding the ASCII
 *	  representation plus some other information (string length, etc.)
21 22
 *
 */
23
#include "postgres.h"
24

25 26
#include <ctype.h>

27 28
#include "access/heapam.h"
#include "access/htup.h"
B
Bruce Momjian 已提交
29
#include "catalog/pg_type.h"
30
#include "fmgr.h"
B
Bruce Momjian 已提交
31
#include "lib/stringinfo.h"
32
#include "nodes/execnodes.h"
B
Bruce Momjian 已提交
33 34
#include "nodes/nodes.h"
#include "nodes/parsenodes.h"
35 36 37 38
#include "nodes/pg_list.h"
#include "nodes/plannodes.h"
#include "nodes/primnodes.h"
#include "nodes/relation.h"
39
#include "parser/parse.h"
B
Bruce Momjian 已提交
40 41 42
#include "utils/datum.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
43

44

45 46
static void _outDatum(StringInfo str, Datum value, Oid type);
static void _outNode(StringInfo str, void *obj);
47

48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
/*
 * _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;
	}
63

64 65
	/*
	 * Look for characters or patterns that are treated specially by
66 67
	 * read.c (either in lsptok() or in nodeRead()), and therefore need a
	 * protective backslash.
68 69 70 71 72
	 */
	/* These characters only need to be quoted at the start of the string */
	if (*s == '<' ||
		*s == '\"' ||
		*s == '@' ||
73 74
		isdigit((unsigned char) *s) ||
		(*s == '-' && isdigit((unsigned char) s[1])))
75 76 77 78 79 80 81 82 83 84 85
		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++);
	}
}
86

87 88
/*
 * _outIntList -
89
 *	   converts a List of integers
90
 */
91
static void
92
_outIntList(StringInfo str, List *list)
93
{
B
Bruce Momjian 已提交
94
	List	   *l;
95

96
	appendStringInfoChar(str, '(');
97
	foreach(l, list)
98 99
		appendStringInfo(str, " %d", lfirsti(l));
	appendStringInfoChar(str, ')');
100 101
}

102 103 104
static void
_outCreateStmt(StringInfo str, CreateStmt *node)
{
105 106
	appendStringInfo(str, " CREATE :relname ");
	_outToken(str, node->relname);
107 108

	appendStringInfo(str, " :istemp %s ",
B
Bruce Momjian 已提交
109
					 node->istemp ? "true" : "false");
110 111

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

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

117
	appendStringInfo(str, " :constraints ");
118
	_outNode(str, node->constraints);
119
}
120 121 122 123

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

133 134
	appendStringInfo(str, " :withClause ");
	_outNode(str, node->withClause);
M
 
Marc G. Fournier 已提交
135

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

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

142 143 144
	appendStringInfo(str, " :unique %s :primary %s ",
					 node->unique ? "true" : "false",
					 node->primary ? "true" : "false");
145
}
146

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

static void
_outFuncCall(StringInfo str, FuncCall *node)
{
158 159 160
	appendStringInfo(str, "FUNCTION ");
	_outToken(str, node->funcname);
	appendStringInfo(str, " :args ");
161
	_outNode(str, node->args);
162 163 164
	appendStringInfo(str, " :agg_star %s :agg_distinct %s ",
					 node->agg_star ? "true" : "false",
					 node->agg_distinct ? "true" : "false");
165
}
166

167 168 169
static void
_outColumnDef(StringInfo str, ColumnDef *node)
{
170 171 172
	appendStringInfo(str, " COLUMNDEF :colname ");
	_outToken(str, node->colname);
	appendStringInfo(str, " :typename ");
173
	_outNode(str, node->typename);
174
	appendStringInfo(str, " :is_not_null %s :is_sequence %s :raw_default ",
B
Bruce Momjian 已提交
175
					 node->is_not_null ? "true" : "false",
176 177
					 node->is_sequence ? "true" : "false");
	_outNode(str, node->raw_default);
178 179 180
	appendStringInfo(str, " :cooked_default ");
	_outToken(str, node->cooked_default);
	appendStringInfo(str, " :constraints ");
181
	_outNode(str, node->constraints);
182 183 184 185 186
}

static void
_outTypeName(StringInfo str, TypeName *node)
{
187 188 189
	appendStringInfo(str, " TYPENAME :name ");
	_outToken(str, node->name);
	appendStringInfo(str, " :timezone %s :setof %s typmod %d :arrayBounds ",
B
Bruce Momjian 已提交
190 191 192
					 node->timezone ? "true" : "false",
					 node->setof ? "true" : "false",
					 node->typmod);
193 194
	_outNode(str, node->arrayBounds);
}
195

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

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

216
static void
217
_outQuery(StringInfo str, Query *node)
218
{
219

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

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

			case T_IndexStmt:
237 238 239 240 241
				appendStringInfo(str, " :index ");
				_outToken(str, ((IndexStmt *) (node->utilityStmt))->idxname);
				appendStringInfo(str, " on ");
				_outToken(str, ((IndexStmt *) (node->utilityStmt))->relname);
				appendStringInfo(str, " ");
242 243 244 245
				_outNode(str, node->utilityStmt);
				break;

			case T_NotifyStmt:
246
				appendStringInfo(str, " :notify ");
247
				_outToken(str, ((NotifyStmt *) (node->utilityStmt))->relname);
248 249 250
				break;

			default:
251
				appendStringInfo(str, " :utility ? ");
252 253
		}
	}
254
	else
255
		appendStringInfo(str, " :utility <>");
256

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

261
	appendStringInfo(str, " :isPortal %s :isBinary %s :isTemp %s"
262
					 " :hasAggs %s :hasSubLinks %s :rtable ",
B
Bruce Momjian 已提交
263 264 265
					 node->isPortal ? "true" : "false",
					 node->isBinary ? "true" : "false",
					 node->isTemp ? "true" : "false",
266 267
					 node->hasAggs ? "true" : "false",
					 node->hasSubLinks ? "true" : "false");
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 308
	appendStringInfo(str, " SORTCLAUSE :tleSortGroupRef %d :sortop %u ",
					 node->tleSortGroupRef, node->sortop);
309 310 311 312 313
}

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

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

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 402
	appendStringInfo(str, " :isTarget %s ",
					 node->isTarget ? "true" : "false");
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 %u :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 519
	_outIntList(str, node->indxid);

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
 *	Material is a subclass of Plan
561 562 563 564 565 566 567 568
 */
static void
_outMaterial(StringInfo str, Material *node)
{
	appendStringInfo(str, " MATERIAL ");
	_outPlanInfo(str, (Plan *) node);
}

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

static void
B
Bruce Momjian 已提交
581
_outAgg(StringInfo str, Agg *node)
582
{
583
	appendStringInfo(str, " AGG ");
584
	_outPlanInfo(str, (Plan *) node);
585 586 587
}

static void
588
_outGroup(StringInfo str, Group *node)
589
{
590
	appendStringInfo(str, " GRP ");
591 592 593
	_outPlanInfo(str, (Plan *) node);

	/* the actual Group fields */
M
 
Marc G. Fournier 已提交
594
	appendStringInfo(str, " :numCols %d :tuplePerGroup %s ",
B
Bruce Momjian 已提交
595 596
					 node->numCols,
					 node->tuplePerGroup ? "true" : "false");
597
}
598

599
static void
600
_outUnique(StringInfo str, Unique *node)
601
{
602 603
	int		i;

604
	appendStringInfo(str, " UNIQUE ");
605 606
	_outPlanInfo(str, (Plan *) node);

607
	appendStringInfo(str, " :numCols %d :uniqColIdx ",
608
					 node->numCols);
609 610 611
	for (i = 0; i < node->numCols; i++)
		appendStringInfo(str, "%d ", (int) node->uniqColIdx[i]);
}
612

613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628
static void
_outSetOp(StringInfo str, SetOp *node)
{
	int		i;

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

629 630 631 632 633 634 635 636 637 638 639 640
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);
}

641
/*
642
 *	Hash is a subclass of Plan
643 644
 */
static void
645
_outHash(StringInfo str, Hash *node)
646
{
647
	appendStringInfo(str, " HASH ");
648 649
	_outPlanInfo(str, (Plan *) node);

650
	appendStringInfo(str, " :hashkey ");
651
	_outNode(str, node->hashkey);
652 653 654 655
}

/*****************************************************************************
 *
656
 *	Stuff from primnodes.h.
657 658 659 660
 *
 *****************************************************************************/

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

static void
680
_outFjoin(StringInfo str, Fjoin *node)
681
{
682
	int			i;
683

M
 
Marc G. Fournier 已提交
684
	appendStringInfo(str, " FJOIN :initialized %s :nNodes %d ",
B
Bruce Momjian 已提交
685 686
					 node->fj_initialized ? "true" : "false",
					 node->fj_nNodes);
687 688 689 690

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

691 692
	appendStringInfo(str, " :results @ 0x%p :alwaysdone",
					 node->fj_results);
693 694

	for (i = 0; i < node->fj_nNodes; i++)
695
		appendStringInfo(str, (node->fj_alwaysDone[i]) ? "true" : "false");
696 697 698
}

/*
699
 *	Expr is a subclass of Node
700 701
 */
static void
702
_outExpr(StringInfo str, Expr *node)
703
{
704
	char	   *opstr = NULL;
705

M
 
Marc G. Fournier 已提交
706
	appendStringInfo(str, " EXPR :typeOid %u ",
B
Bruce Momjian 已提交
707
					 node->typeOid);
708 709 710

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

735
	appendStringInfo(str, " :args ");
736
	_outNode(str, node->args);
737 738 739
}

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

B
Bruce Momjian 已提交
752 753 754 755
	appendStringInfo(str, " :varlevelsup %u :varnoold %d :varoattno %d",
					 node->varlevelsup,
					 node->varnoold,
					 node->varoattno);
756 757 758
}

/*
759
 *	Const is a subclass of Expr
760 761
 */
static void
762
_outConst(StringInfo str, Const *node)
763
{
B
Bruce Momjian 已提交
764 765 766 767 768
	appendStringInfo(str,
		" CONST :consttype %u :constlen %d :constisnull %s :constvalue ",
					 node->consttype,
					 node->constlen,
					 node->constisnull ? "true" : "false");
M
 
Marc G. Fournier 已提交
769

770
	if (node->constisnull)
B
Bruce Momjian 已提交
771
		appendStringInfo(str, "<>");
772 773
	else
		_outDatum(str, node->constvalue, node->consttype);
M
 
Marc G. Fournier 已提交
774

B
Bruce Momjian 已提交
775 776
	appendStringInfo(str, " :constbyval %s ",
					 node->constbyval ? "true" : "false");
777 778 779
}

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

791
	appendStringInfo(str, " :aggstar %s :aggdistinct %s ",
792 793 794
					 node->aggstar ? "true" : "false",
					 node->aggdistinct ? "true" : "false");
	/* aggno is not dumped */
795 796
}

797 798 799 800 801 802
/*
 *	SubLink
 */
static void
_outSubLink(StringInfo str, SubLink *node)
{
B
Bruce Momjian 已提交
803 804 805 806
	appendStringInfo(str,
					 " SUBLINK :subLinkType %d :useor %s :lefthand ",
					 node->subLinkType,
					 node->useor ? "true" : "false");
807
	_outNode(str, node->lefthand);
M
 
Marc G. Fournier 已提交
808

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

812 813 814 815
	appendStringInfo(str, " :subselect ");
	_outNode(str, node->subselect);
}

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

B
Bruce Momjian 已提交
828 829
	appendStringInfo(str, " :refelembyval %c :refupperindex ",
					 node->refelembyval ? 't' : 'f');
830 831
	_outNode(str, node->refupperindexpr);

832
	appendStringInfo(str, " :reflowerindex ");
833 834
	_outNode(str, node->reflowerindexpr);

835
	appendStringInfo(str, " :refexpr ");
836 837
	_outNode(str, node->refexpr);

838
	appendStringInfo(str, " :refassgnexpr ");
839
	_outNode(str, node->refassgnexpr);
840 841 842
}

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

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

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

879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914
/*
 *	FieldSelect
 */
static void
_outFieldSelect(StringInfo str, FieldSelect *node)
{
	appendStringInfo(str, " FIELDSELECT :arg ");
	_outNode(str, node->arg);

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

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

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

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

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

927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950
/*
 *	JoinExpr
 */
static void
_outJoinExpr(StringInfo str, JoinExpr *node)
{
	appendStringInfo(str, " JOINEXPR :jointype %d :isNatural %s :larg ",
					 (int) node->jointype,
					 node->isNatural ? "true" : "false");
	_outNode(str, node->larg);
	appendStringInfo(str, " :rarg ");
	_outNode(str, node->rarg);
	appendStringInfo(str, " :using ");
	_outNode(str, node->using);
	appendStringInfo(str, " :quals ");
	_outNode(str, node->quals);
	appendStringInfo(str, " :alias ");
	_outNode(str, node->alias);
	appendStringInfo(str, " :colnames ");
	_outNode(str, node->colnames);
	appendStringInfo(str, " :colvars ");
	_outNode(str, node->colvars);
}

951
/*
952
 *	Stuff from relation.h
953
 */
954

955
static void
956
_outRelOptInfo(StringInfo str, RelOptInfo *node)
957
{
M
 
Marc G. Fournier 已提交
958
	appendStringInfo(str, " RELOPTINFO :relids ");
959 960
	_outIntList(str, node->relids);

961
	appendStringInfo(str, " :rows %.0f :width %d :targetlist ",
962
					 node->rows,
963
					 node->width);
964 965
	_outNode(str, node->targetlist);

966
	appendStringInfo(str, " :pathlist ");
967
	_outNode(str, node->pathlist);
968 969 970 971
	appendStringInfo(str, " :cheapest_startup_path ");
	_outNode(str, node->cheapest_startup_path);
	appendStringInfo(str, " :cheapest_total_path ");
	_outNode(str, node->cheapest_total_path);
972

973 974 975 976 977 978 979
	appendStringInfo(str, " :pruneable %s :issubquery %s :indexed %s :pages %ld :tuples %.0f :subplan ",
					 node->pruneable ? "true" : "false",
					 node->issubquery ? "true" : "false",
					 node->indexed ? "true" : "false",
					 node->pages,
					 node->tuples);
	_outNode(str, node->subplan);
980

981 982 983
	appendStringInfo(str, " :baserestrictinfo ");
	_outNode(str, node->baserestrictinfo);
	appendStringInfo(str, " :baserestrictcost %.2f :outerjoinset ",
984 985
					 node->baserestrictcost);
	_outIntList(str, node->outerjoinset);
986
	appendStringInfo(str, " :joininfo ");
987
	_outNode(str, node->joininfo);
988
	appendStringInfo(str, " :innerjoin ");
989
	_outNode(str, node->innerjoin);
990 991
}

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

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

1010 1011
	appendStringInfo(str, " :expr ");
	_outNode(str, node->expr);
1012
}
1013 1014

static void
1015
_outRangeTblEntry(StringInfo str, RangeTblEntry *node)
1016
{
1017 1018
	appendStringInfo(str, " RTE :relname ");
	_outToken(str, node->relname);
1019
	appendStringInfo(str, " :relid %u ",
1020
					 node->relid);
1021 1022 1023
	appendStringInfo(str, " :subquery ");
	_outNode(str, node->subquery);
	appendStringInfo(str, " :alias ");
1024 1025 1026
	_outNode(str, node->alias);
	appendStringInfo(str, " :eref ");
	_outNode(str, node->eref);
1027 1028
	appendStringInfo(str, " :inh %s :inFromCl %s :checkForRead %s"
					 " :checkForWrite %s :checkAsUser %u",
B
Bruce Momjian 已提交
1029 1030
					 node->inh ? "true" : "false",
					 node->inFromCl ? "true" : "false",
1031 1032 1033
					 node->checkForRead ? "true" : "false",
					 node->checkForWrite ? "true" : "false",
					 node->checkAsUser);
1034 1035
}

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

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

1063
	appendStringInfo(str, " :indexid ");
1064 1065
	_outIntList(str, node->indexid);

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

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

1073 1074
	appendStringInfo(str, " :alljoinquals %s :rows %.2f ",
					 node->alljoinquals ? "true" : "false",
1075
					 node->rows);
1076 1077
}

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

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

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

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

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

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

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

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

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

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

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

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

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

1210 1211
	appendStringInfo(str, " :ispusheddown %s :subclauseindices ",
					 node->ispusheddown ? "true" : "false");
1212
	_outNode(str, node->subclauseindices);
1213

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

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

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

/*
 * Print the value of a Datum given its type.
 */
static void
_outDatum(StringInfo str, Datum value, Oid type)
{
1239
	int16		typeLength;
1240
	bool		byValue;
1241 1242
	Size		length;
	char	   *s;
1243
	int			i;
1244 1245 1246 1247 1248

	/*
	 * find some information about the type and the "real" length of the
	 * datum.
	 */
1249
	get_typlenbyval(type, &typeLength, &byValue);
1250
	length = datumGetSize(value, byValue, typeLength);
1251 1252 1253 1254

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

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

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

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

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

1334
static void
1335
_outValue(StringInfo str, Value *value)
1336
{
1337 1338
	switch (value->type)
	{
1339
			case T_Integer:
1340
			appendStringInfo(str, " %ld ", value->val.ival);
1341 1342
			break;
		case T_Float:
1343 1344 1345 1346

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

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

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

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

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

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

		case CONSTR_CHECK:
1406
			appendStringInfo(str, "CHECK :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_DEFAULT:
1413
			appendStringInfo(str, "DEFAULT :raw ");
1414
			_outNode(str, node->raw_expr);
1415 1416
			appendStringInfo(str, " :cooked ");
			_outToken(str, node->cooked_expr);
T
Thomas G. Lockhart 已提交
1417 1418 1419
			break;

		case CONSTR_NOTNULL:
1420
			appendStringInfo(str, "NOT NULL");
T
Thomas G. Lockhart 已提交
1421 1422 1423
			break;

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

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

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

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

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

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

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

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

1471
	if (IsA(obj, List))
1472
	{
1473
		List	   *l;
1474

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

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

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

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

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