outfuncs.c 37.1 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.119 2000/06/16 05:27:02 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 <ctype.h>
24

25
#include "postgres.h"
26

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((int) *s) ||
		(*s == '-' && isdigit((int) 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

	appendStringInfo(str, " :lossy %s :unique %s ",
B
Bruce Momjian 已提交
143 144
					 node->lossy ? "true" : "false",
					 node->unique ? "true" : "false");
145
}
146

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

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

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

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

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

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

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

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

223 224 225 226 227
	if (node->utilityStmt)
	{
		switch (nodeTag(node->utilityStmt))
		{
			case T_CreateStmt:
228 229 230
				appendStringInfo(str, " :create ");
				_outToken(str, ((CreateStmt *) (node->utilityStmt))->relname);
				appendStringInfo(str, " ");
231 232 233 234
				_outNode(str, node->utilityStmt);
				break;

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

			case T_NotifyStmt:
244 245
				appendStringInfo(str, " :utility ");
				_outToken(str, ((NotifyStmt *) (node->utilityStmt))->relname);
246 247 248
				break;

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

255 256 257 258
	appendStringInfo(str, " :resultRelation %u :into ",
					 node->resultRelation);
	_outToken(str, node->into);

B
Bruce Momjian 已提交
259
	appendStringInfo(str,
260
	" :isPortal %s :isBinary %s :isTemp %s :unionall %s :distinctClause ",
B
Bruce Momjian 已提交
261 262 263 264
					 node->isPortal ? "true" : "false",
					 node->isBinary ? "true" : "false",
					 node->isTemp ? "true" : "false",
					 node->unionall ? "true" : "false");
265 266
	_outNode(str, node->distinctClause);

267
	appendStringInfo(str, " :sortClause ");
268
	_outNode(str, node->sortClause);
M
 
Marc G. Fournier 已提交
269

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

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

276
	appendStringInfo(str, " :qual ");
277
	_outNode(str, node->qual);
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

	appendStringInfo(str, " :hasAggs %s :hasSubLinks %s :unionClause ",
B
Bruce Momjian 已提交
286 287
					 node->hasAggs ? "true" : "false",
					 node->hasSubLinks ? "true" : "false");
288
	_outNode(str, node->unionClause);
M
 
Marc G. Fournier 已提交
289

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

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

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

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

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
}

/*
 * print the basic stuff of all nodes that inherit from Plan
 */
static void
322
_outPlanInfo(StringInfo str, Plan *node)
323
{
B
Bruce Momjian 已提交
324
	appendStringInfo(str,
325 326 327
					 ":startup_cost %.2f :total_cost %.2f :rows %.0f :width %d :state %s :qptargetlist ",
					 node->startup_cost,
					 node->total_cost,
328
					 node->plan_rows,
B
Bruce Momjian 已提交
329 330
					 node->plan_width,
					 node->state ? "not-NULL" : "<>");
331
	_outNode(str, node->targetlist);
M
 
Marc G. Fournier 已提交
332

333
	appendStringInfo(str, " :qpqual ");
334
	_outNode(str, node->qual);
M
 
Marc G. Fournier 已提交
335

336
	appendStringInfo(str, " :lefttree ");
337
	_outNode(str, node->lefttree);
M
 
Marc G. Fournier 已提交
338

339
	appendStringInfo(str, " :righttree ");
340
	_outNode(str, node->righttree);
M
 
Marc G. Fournier 已提交
341

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

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

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

M
 
Marc G. Fournier 已提交
351
	appendStringInfo(str, " :nprm %d ", node->nParamExec);
352 353 354
}

/*
355
 *	Stuff from plannodes.h
356 357
 */
static void
358
_outPlan(StringInfo str, Plan *node)
359
{
360
	appendStringInfo(str, " PLAN ");
361
	_outPlanInfo(str, (Plan *) node);
362 363 364
}

static void
365
_outResult(StringInfo str, Result *node)
366
{
367
	appendStringInfo(str, " RESULT ");
368 369
	_outPlanInfo(str, (Plan *) node);

370
	appendStringInfo(str, " :resconstantqual ");
371 372
	_outNode(str, node->resconstantqual);

373 374 375
}

/*
376
 *	Append is a subclass of Plan.
377 378
 */
static void
B
Bruce Momjian 已提交
379
_outAppend(StringInfo str, Append *node)
380
{
381
	appendStringInfo(str, " APPEND ");
382 383
	_outPlanInfo(str, (Plan *) node);

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

387 388
	appendStringInfo(str, " :unionrtables ");
	_outNode(str, node->unionrtables);
389

B
Bruce Momjian 已提交
390 391 392
	appendStringInfo(str,
					 " :inheritrelid %u :inheritrtable ",
					 node->inheritrelid);
393
	_outNode(str, node->inheritrtable);
394

395 396 397
}

/*
398
 *	Join is a subclass of Plan
399 400
 */
static void
401
_outJoin(StringInfo str, Join *node)
402
{
403
	appendStringInfo(str, " JOIN ");
404 405
	_outPlanInfo(str, (Plan *) node);

406 407 408
}

/*
409
 *	NestLoop is a subclass of Join
410 411
 */
static void
412
_outNestLoop(StringInfo str, NestLoop *node)
413
{
414
	appendStringInfo(str, " NESTLOOP ");
415
	_outPlanInfo(str, (Plan *) node);
416 417 418
}

/*
419
 *	MergeJoin is a subclass of Join
420 421
 */
static void
422
_outMergeJoin(StringInfo str, MergeJoin *node)
423
{
424
	appendStringInfo(str, " MERGEJOIN ");
425 426
	_outPlanInfo(str, (Plan *) node);

427
	appendStringInfo(str, " :mergeclauses ");
428
	_outNode(str, node->mergeclauses);
429 430 431
}

/*
432
 *	HashJoin is a subclass of Join.
433 434
 */
static void
435
_outHashJoin(StringInfo str, HashJoin *node)
436
{
437
	appendStringInfo(str, " HASHJOIN ");
438 439
	_outPlanInfo(str, (Plan *) node);

440
	appendStringInfo(str, " :hashclauses ");
441 442
	_outNode(str, node->hashclauses);

B
Bruce Momjian 已提交
443 444 445
	appendStringInfo(str,
					 " :hashjoinop %u ",
					 node->hashjoinop);
M
 
Marc G. Fournier 已提交
446

B
Bruce Momjian 已提交
447 448 449
	appendStringInfo(str,
					 " :hashdone %d ",
					 node->hashdone);
450 451
}

V
Vadim B. Mikheev 已提交
452 453 454
static void
_outSubPlan(StringInfo str, SubPlan *node)
{
M
 
Marc G. Fournier 已提交
455
	appendStringInfo(str, " SUBPLAN :plan ");
V
Vadim B. Mikheev 已提交
456
	_outNode(str, node->plan);
M
 
Marc G. Fournier 已提交
457 458

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

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

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

V
Vadim B. Mikheev 已提交
467 468 469 470
	appendStringInfo(str, " :slink ");
	_outNode(str, node->sublink);
}

471
/*
472
 *	Scan is a subclass of Node
473 474
 */
static void
475
_outScan(StringInfo str, Scan *node)
476
{
477
	appendStringInfo(str, " SCAN ");
478 479
	_outPlanInfo(str, (Plan *) node);

480
	appendStringInfo(str, " :scanrelid %u ", node->scanrelid);
481 482 483
}

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

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

/*
496
 *	IndexScan is a subclass of Scan
497 498
 */
static void
499
_outIndexScan(StringInfo str, IndexScan *node)
500
{
501
	appendStringInfo(str, " INDEXSCAN ");
502 503
	_outPlanInfo(str, (Plan *) node);

504
	appendStringInfo(str, " :scanrelid %u :indxid ", node->scan.scanrelid);
505 506
	_outIntList(str, node->indxid);

507
	appendStringInfo(str, " :indxqual ");
508 509
	_outNode(str, node->indxqual);

V
Vadim B. Mikheev 已提交
510 511 512
	appendStringInfo(str, " :indxqualorig ");
	_outNode(str, node->indxqualorig);

513
	appendStringInfo(str, " :indxorderdir %d ", node->indxorderdir);
514 515
}

516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532
/*
 *	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);

}

533
/*
534
 *	Noname is a subclass of Plan
535 536
 */
static void
537
_outNoname(StringInfo str, Noname *node)
538
{
539
	appendStringInfo(str, " NONAME ");
540 541
	_outPlanInfo(str, (Plan *) node);

B
Bruce Momjian 已提交
542 543 544
	appendStringInfo(str, " :nonameid %u :keycount %d ",
					 node->nonameid,
					 node->keycount);
545 546
}

547 548 549 550 551 552 553 554 555 556 557 558 559 560
/*
 *	Material is a subclass of Noname
 */
static void
_outMaterial(StringInfo str, Material *node)
{
	appendStringInfo(str, " MATERIAL ");
	_outPlanInfo(str, (Plan *) node);

	appendStringInfo(str, " :nonameid %u :keycount %d ",
					 node->nonameid,
					 node->keycount);
}

561
/*
562
 *	Sort is a subclass of Noname
563 564
 */
static void
565
_outSort(StringInfo str, Sort *node)
566
{
567
	appendStringInfo(str, " SORT ");
568 569
	_outPlanInfo(str, (Plan *) node);

570
	appendStringInfo(str, " :nonameid %u :keycount %d ",
B
Bruce Momjian 已提交
571 572
					 node->nonameid,
					 node->keycount);
573 574 575
}

static void
B
Bruce Momjian 已提交
576
_outAgg(StringInfo str, Agg *node)
577
{
578

579
	appendStringInfo(str, " AGG ");
580
	_outPlanInfo(str, (Plan *) node);
581 582 583
}

static void
584
_outGroup(StringInfo str, Group *node)
585
{
586
	appendStringInfo(str, " GRP ");
587 588 589
	_outPlanInfo(str, (Plan *) node);

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

595
/*
596
 *	For some reason, unique is a subclass of Noname.
597 598
 */
static void
599
_outUnique(StringInfo str, Unique *node)
600
{
601 602
	int		i;

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

606
	appendStringInfo(str, " :nonameid %u :keycount %d :numCols %d :uniqColIdx ",
B
Bruce Momjian 已提交
607
					 node->nonameid,
608 609
					 node->keycount,
					 node->numCols);
610

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

/*
616
 *	Hash is a subclass of Noname
617 618
 */
static void
619
_outHash(StringInfo str, Hash *node)
620
{
621
	appendStringInfo(str, " HASH ");
622 623
	_outPlanInfo(str, (Plan *) node);

624
	appendStringInfo(str, " :hashkey ");
625
	_outNode(str, node->hashkey);
626 627 628 629
}

/*****************************************************************************
 *
630
 *	Stuff from primnodes.h.
631 632 633 634
 *
 *****************************************************************************/

/*
635
 *	Resdom is a subclass of Node
636 637
 */
static void
638
_outResdom(StringInfo str, Resdom *node)
639
{
640
	appendStringInfo(str,
641
				 " RESDOM :resno %d :restype %u :restypmod %d :resname ",
B
Bruce Momjian 已提交
642 643 644
					 node->resno,
					 node->restype,
					 node->restypmod);
645 646
	_outToken(str, node->resname);
	appendStringInfo(str, " :reskey %d :reskeyop %u :ressortgroupref %d :resjunk %s ",
B
Bruce Momjian 已提交
647
					 node->reskey,
648
					 node->reskeyop,
649
					 node->ressortgroupref,
B
Bruce Momjian 已提交
650
					 node->resjunk ? "true" : "false");
651 652 653
}

static void
654
_outFjoin(StringInfo str, Fjoin *node)
655
{
656
	int			i;
657

M
 
Marc G. Fournier 已提交
658
	appendStringInfo(str, " FJOIN :initialized %s :nNodes %d ",
B
Bruce Momjian 已提交
659 660
					 node->fj_initialized ? "true" : "false",
					 node->fj_nNodes);
661 662 663 664

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

B
Bruce Momjian 已提交
665 666
	appendStringInfo(str, " :results @ 0x%x :alwaysdone",
					 (int) node->fj_results);
667 668

	for (i = 0; i < node->fj_nNodes; i++)
669
		appendStringInfo(str, (node->fj_alwaysDone[i]) ? "true" : "false");
670 671 672
}

/*
673
 *	Expr is a subclass of Node
674 675
 */
static void
676
_outExpr(StringInfo str, Expr *node)
677
{
678
	char	   *opstr = NULL;
679

M
 
Marc G. Fournier 已提交
680
	appendStringInfo(str, " EXPR :typeOid %u ",
B
Bruce Momjian 已提交
681
					 node->typeOid);
682 683 684

	switch (node->opType)
	{
685 686 687 688 689 690 691 692 693 694 695 696 697 698 699
		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 已提交
700 701 702
		case SUBPLAN_EXPR:
			opstr = "subp";
			break;
703
	}
704 705 706
	appendStringInfo(str, " :opType ");
	_outToken(str, opstr);
	appendStringInfo(str, " :oper ");
707
	_outNode(str, node->oper);
M
 
Marc G. Fournier 已提交
708

709
	appendStringInfo(str, " :args ");
710
	_outNode(str, node->args);
711 712 713
}

/*
714
 *	Var is a subclass of Expr
715 716
 */
static void
717
_outVar(StringInfo str, Var *node)
718
{
B
Bruce Momjian 已提交
719 720 721 722 723 724
	appendStringInfo(str,
				" VAR :varno %d :varattno %d :vartype %u :vartypmod %d ",
					 node->varno,
					 node->varattno,
					 node->vartype,
					 node->vartypmod);
M
 
Marc G. Fournier 已提交
725

B
Bruce Momjian 已提交
726 727 728 729
	appendStringInfo(str, " :varlevelsup %u :varnoold %d :varoattno %d",
					 node->varlevelsup,
					 node->varnoold,
					 node->varoattno);
730 731 732
}

/*
733
 *	Const is a subclass of Expr
734 735
 */
static void
736
_outConst(StringInfo str, Const *node)
737
{
B
Bruce Momjian 已提交
738 739 740 741 742
	appendStringInfo(str,
		" CONST :consttype %u :constlen %d :constisnull %s :constvalue ",
					 node->consttype,
					 node->constlen,
					 node->constisnull ? "true" : "false");
M
 
Marc G. Fournier 已提交
743

744
	if (node->constisnull)
B
Bruce Momjian 已提交
745
		appendStringInfo(str, "<>");
746 747
	else
		_outDatum(str, node->constvalue, node->consttype);
M
 
Marc G. Fournier 已提交
748

B
Bruce Momjian 已提交
749 750
	appendStringInfo(str, " :constbyval %s ",
					 node->constbyval ? "true" : "false");
751 752 753
}

/*
B
Bruce Momjian 已提交
754
 *	Aggref
755 756
 */
static void
757
_outAggref(StringInfo str, Aggref *node)
758
{
759 760 761
	appendStringInfo(str, " AGGREG :aggname ");
	_outToken(str, node->aggname);
	appendStringInfo(str, " :basetype %u :aggtype %u :target ",
B
Bruce Momjian 已提交
762 763
					 node->basetype,
					 node->aggtype);
764
	_outNode(str, node->target);
M
 
Marc G. Fournier 已提交
765

766 767 768 769 770
	appendStringInfo(str, " :usenulls %s :aggstar %s :aggdistinct %s ",
					 node->usenulls ? "true" : "false",
					 node->aggstar ? "true" : "false",
					 node->aggdistinct ? "true" : "false");
	/* aggno is not dumped */
771 772
}

773 774 775 776 777 778
/*
 *	SubLink
 */
static void
_outSubLink(StringInfo str, SubLink *node)
{
B
Bruce Momjian 已提交
779 780 781 782
	appendStringInfo(str,
					 " SUBLINK :subLinkType %d :useor %s :lefthand ",
					 node->subLinkType,
					 node->useor ? "true" : "false");
783
	_outNode(str, node->lefthand);
M
 
Marc G. Fournier 已提交
784

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

788 789 790 791
	appendStringInfo(str, " :subselect ");
	_outNode(str, node->subselect);
}

792 793 794 795 796 797 798 799 800 801 802 803 804
/*
 *	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);
}

805
/*
806
 *	Array is a subclass of Expr
807 808
 */
static void
B
Bruce Momjian 已提交
809
_outArray(StringInfo str, Array *node)
810
{
811
	int			i;
812

B
Bruce Momjian 已提交
813 814 815 816 817
	appendStringInfo(str,
	  " ARRAY :arrayelemtype %u :arrayelemlength %d :arrayelembyval %c ",
					 node->arrayelemtype,
					 node->arrayelemlength,
					 node->arrayelembyval ? 't' : 'f');
M
 
Marc G. Fournier 已提交
818

M
 
Marc G. Fournier 已提交
819
	appendStringInfo(str, " :arrayndim %d :arraylow ", node->arrayndim);
820
	for (i = 0; i < node->arrayndim; i++)
M
 
Marc G. Fournier 已提交
821
		appendStringInfo(str, " %d ", node->arraylow.indx[i]);
822
	appendStringInfo(str, " :arrayhigh ");
823
	for (i = 0; i < node->arrayndim; i++)
M
 
Marc G. Fournier 已提交
824 825
		appendStringInfo(str, " %d ", node->arrayhigh.indx[i]);
	appendStringInfo(str, " :arraylen %d ", node->arraylen);
826 827 828
}

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

B
Bruce Momjian 已提交
840 841
	appendStringInfo(str, " :refelembyval %c :refupperindex ",
					 node->refelembyval ? 't' : 'f');
842 843
	_outNode(str, node->refupperindexpr);

844
	appendStringInfo(str, " :reflowerindex ");
845 846
	_outNode(str, node->reflowerindexpr);

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

850
	appendStringInfo(str, " :refassgnexpr ");
851
	_outNode(str, node->refassgnexpr);
852 853 854
}

/*
855
 *	Func is a subclass of Expr
856 857
 */
static void
858
_outFunc(StringInfo str, Func *node)
859
{
B
Bruce Momjian 已提交
860 861 862 863 864 865
	appendStringInfo(str,
		   " FUNC :funcid %u :functype %u :funcisindex %s :funcsize %d ",
					 node->funcid,
					 node->functype,
					 node->funcisindex ? "true" : "false",
					 node->funcsize);
M
 
Marc G. Fournier 已提交
866 867

	appendStringInfo(str, " :func_fcache @ 0x%x :func_tlist ",
B
Bruce Momjian 已提交
868
					 (int) node->func_fcache);
869 870 871 872
	_outNode(str, node->func_tlist);

	appendStringInfo(str, " :func_planlist ");
	_outNode(str, node->func_planlist);
873 874 875
}

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

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

/*
904
 *	Stuff from execnodes.h
905 906 907
 */

/*
908
 *	EState is a subclass of Node.
909 910
 */
static void
911
_outEState(StringInfo str, EState *node)
912
{
B
Bruce Momjian 已提交
913 914 915
	appendStringInfo(str,
					 " ESTATE :direction %d :range_table ",
					 node->es_direction);
916 917
	_outNode(str, node->es_range_table);

M
 
Marc G. Fournier 已提交
918
	appendStringInfo(str, " :result_relation_info @ 0x%x ",
B
Bruce Momjian 已提交
919
					 (int) (node->es_result_relation_info));
920 921 922
}

/*
923
 *	Stuff from relation.h
924
 */
925

926
static void
927
_outRelOptInfo(StringInfo str, RelOptInfo *node)
928
{
M
 
Marc G. Fournier 已提交
929
	appendStringInfo(str, " RELOPTINFO :relids ");
930 931
	_outIntList(str, node->relids);

B
Bruce Momjian 已提交
932
	appendStringInfo(str,
933
					 " :rows %.0f :width %d :indexed %s :pages %ld :tuples %.0f :targetlist ",
934 935
					 node->rows,
					 node->width,
B
Bruce Momjian 已提交
936 937
					 node->indexed ? "true" : "false",
					 node->pages,
938
					 node->tuples);
939 940
	_outNode(str, node->targetlist);

941
	appendStringInfo(str, " :pathlist ");
942 943
	_outNode(str, node->pathlist);

944 945 946 947
	appendStringInfo(str, " :cheapest_startup_path ");
	_outNode(str, node->cheapest_startup_path);
	appendStringInfo(str, " :cheapest_total_path ");
	_outNode(str, node->cheapest_total_path);
948

B
Bruce Momjian 已提交
949
	appendStringInfo(str,
950
					 " :pruneable %s :baserestrictinfo ",
B
Bruce Momjian 已提交
951
					 node->pruneable ? "true" : "false");
952
	_outNode(str, node->baserestrictinfo);
953

954
	appendStringInfo(str, " :joininfo ");
955 956
	_outNode(str, node->joininfo);

957
	appendStringInfo(str, " :innerjoin ");
958
	_outNode(str, node->innerjoin);
959 960
}

961 962 963 964 965 966 967 968 969
static void
_outIndexOptInfo(StringInfo str, IndexOptInfo *node)
{
	appendStringInfo(str, " INDEXOPTINFO :indexoid %u :pages %ld :tuples %g ",
					 node->indexoid,
					 node->pages,
					 node->tuples);
}

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

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

static void
984
_outRangeTblEntry(StringInfo str, RangeTblEntry *node)
985
{
986 987
	appendStringInfo(str, " RTE :relname ");
	_outToken(str, node->relname);
988 989
	appendStringInfo(str, " :ref ");
	_outNode(str, node->ref);
B
Bruce Momjian 已提交
990
	appendStringInfo(str,
991
			 " :relid %u :inh %s :inFromCl %s :inJoinSet %s :skipAcl %s",
B
Bruce Momjian 已提交
992 993 994
					 node->relid,
					 node->inh ? "true" : "false",
					 node->inFromCl ? "true" : "false",
995
					 node->inJoinSet ? "true" : "false",
B
Bruce Momjian 已提交
996
					 node->skipAcl ? "true" : "false");
997
}
998

999
static void
1000
_outRowMark(StringInfo str, RowMark *node)
1001 1002 1003 1004
{
	appendStringInfo(str, " ROWMARK :rti %u :info %u", node->rti, node->info);
}

1005
/*
1006
 *	Path is a subclass of Node.
1007 1008
 */
static void
1009
_outPath(StringInfo str, Path *node)
1010
{
1011
	appendStringInfo(str,
1012
	 " PATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
B
Bruce Momjian 已提交
1013
					 node->pathtype,
1014 1015
					 node->startup_cost,
					 node->total_cost);
1016
	_outNode(str, node->pathkeys);
1017 1018 1019
}

/*
1020
 *	IndexPath is a subclass of Path.
1021 1022
 */
static void
1023
_outIndexPath(StringInfo str, IndexPath *node)
1024
{
B
Bruce Momjian 已提交
1025
	appendStringInfo(str,
1026
					 " INDEXPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
B
Bruce Momjian 已提交
1027
					 node->path.pathtype,
1028 1029
					 node->path.startup_cost,
					 node->path.total_cost);
1030
	_outNode(str, node->path.pathkeys);
1031

1032
	appendStringInfo(str, " :indexid ");
1033 1034
	_outIntList(str, node->indexid);

1035
	appendStringInfo(str, " :indexqual ");
1036
	_outNode(str, node->indexqual);
1037

1038 1039
	appendStringInfo(str, " :indexscandir %d :joinrelids ",
					 (int) node->indexscandir);
1040
	_outIntList(str, node->joinrelids);
1041 1042 1043

	appendStringInfo(str, " :rows %.2f ",
					 node->rows);
1044 1045
}

1046 1047 1048 1049 1050 1051 1052
/*
 *	TidPath is a subclass of Path.
 */
static void
_outTidPath(StringInfo str, TidPath *node)
{
	appendStringInfo(str,
1053
					 " TIDPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
1054
					 node->path.pathtype,
1055 1056
					 node->path.startup_cost,
					 node->path.total_cost);
1057 1058 1059 1060 1061 1062 1063 1064 1065
	_outNode(str, node->path.pathkeys);

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

	appendStringInfo(str, " :un joined_relids ");
	_outIntList(str, node->unjoined_relids);
}

1066
/*
1067
 *	NestPath is a subclass of Path
1068 1069
 */
static void
1070
_outNestPath(StringInfo str, NestPath *node)
1071
{
B
Bruce Momjian 已提交
1072
	appendStringInfo(str,
1073
					 " NESTPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
B
Bruce Momjian 已提交
1074
					 node->path.pathtype,
1075 1076
					 node->path.startup_cost,
					 node->path.total_cost);
1077
	_outNode(str, node->path.pathkeys);
1078 1079 1080 1081 1082 1083
	appendStringInfo(str, " :outerjoinpath ");
	_outNode(str, node->outerjoinpath);
	appendStringInfo(str, " :innerjoinpath ");
	_outNode(str, node->innerjoinpath);
	appendStringInfo(str, " :joinrestrictinfo ");
	_outNode(str, node->joinrestrictinfo);
1084 1085 1086
}

/*
1087
 *	MergePath is a subclass of NestPath.
1088 1089
 */
static void
1090
_outMergePath(StringInfo str, MergePath *node)
1091
{
B
Bruce Momjian 已提交
1092
	appendStringInfo(str,
1093
					 " MERGEPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
B
Bruce Momjian 已提交
1094
					 node->jpath.path.pathtype,
1095 1096
					 node->jpath.path.startup_cost,
					 node->jpath.path.total_cost);
1097
	_outNode(str, node->jpath.path.pathkeys);
1098 1099 1100 1101 1102 1103
	appendStringInfo(str, " :outerjoinpath ");
	_outNode(str, node->jpath.outerjoinpath);
	appendStringInfo(str, " :innerjoinpath ");
	_outNode(str, node->jpath.innerjoinpath);
	appendStringInfo(str, " :joinrestrictinfo ");
	_outNode(str, node->jpath.joinrestrictinfo);
1104

1105
	appendStringInfo(str, " :path_mergeclauses ");
1106 1107
	_outNode(str, node->path_mergeclauses);

1108
	appendStringInfo(str, " :outersortkeys ");
1109 1110
	_outNode(str, node->outersortkeys);

1111
	appendStringInfo(str, " :innersortkeys ");
1112
	_outNode(str, node->innersortkeys);
1113 1114 1115
}

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

1134
	appendStringInfo(str, " :path_hashclauses ");
1135
	_outNode(str, node->path_hashclauses);
1136 1137 1138
}

/*
1139
 *	PathKeyItem is a subclass of Node.
1140 1141
 */
static void
1142
_outPathKeyItem(StringInfo str, PathKeyItem *node)
1143
{
1144 1145 1146
	appendStringInfo(str, " PATHKEYITEM :sortop %u :key ",
					 node->sortop);
	_outNode(str, node->key);
1147 1148 1149
}

/*
1150
 *	RestrictInfo is a subclass of Node.
1151 1152
 */
static void
1153
_outRestrictInfo(StringInfo str, RestrictInfo *node)
1154
{
B
Bruce Momjian 已提交
1155
	appendStringInfo(str, " RESTRICTINFO :clause ");
1156 1157
	_outNode(str, node->clause);

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

1161 1162 1163
	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 已提交
1164
	appendStringInfo(str, " :hashjoinoperator %u ", node->hashjoinoperator);
1165 1166 1167
}

/*
1168
 *	JoinInfo is a subclass of Node.
1169 1170
 */
static void
1171
_outJoinInfo(StringInfo str, JoinInfo *node)
1172
{
B
Bruce Momjian 已提交
1173 1174
	appendStringInfo(str, " JINFO :unjoined_relids ");
	_outIntList(str, node->unjoined_relids);
1175

1176 1177
	appendStringInfo(str, " :jinfo_restrictinfo ");
	_outNode(str, node->jinfo_restrictinfo);
1178 1179 1180 1181 1182 1183 1184 1185
}

/*
 * Print the value of a Datum given its type.
 */
static void
_outDatum(StringInfo str, Datum value, Oid type)
{
B
Bruce Momjian 已提交
1186
	char	   *s;
1187
	Size		length,
B
Bruce Momjian 已提交
1188
				typeLength;
1189 1190
	bool		byValue;
	int			i;
1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202

	/*
	 * find some information about the type and the "real" length of the
	 * datum.
	 */
	byValue = get_typbyval(type);
	typeLength = get_typlen(type);
	length = datumGetSize(value, type, byValue, typeLength);

	if (byValue)
	{
		s = (char *) (&value);
M
 
Marc G. Fournier 已提交
1203
		appendStringInfo(str, " %d [ ", length);
1204
		for (i = 0; i < (int) sizeof(Datum); i++)
1205
			appendStringInfo(str, "%d ", (int) (s[i]));
M
 
Marc G. Fournier 已提交
1206
		appendStringInfo(str, "] ");
1207
	}
1208 1209 1210 1211
	else
	{							/* !byValue */
		s = (char *) DatumGetPointer(value);
		if (!PointerIsValid(s))
M
 
Marc G. Fournier 已提交
1212
			appendStringInfo(str, " 0 [ ] ");
1213 1214
		else
		{
B
Bruce Momjian 已提交
1215

1216 1217 1218 1219 1220 1221
			/*
			 * length is unsigned - very bad to do < comparison to -1
			 * without casting it to int first!! -mer 8 Jan 1991
			 */
			if (((int) length) <= -1)
				length = VARSIZE(s);
M
 
Marc G. Fournier 已提交
1222
			appendStringInfo(str, " %d [ ", length);
1223
			for (i = 0; i < (int) length; i++)
1224
				appendStringInfo(str, "%d ", (int) (s[i]));
M
 
Marc G. Fournier 已提交
1225
			appendStringInfo(str, "] ");
1226
		}
1227 1228 1229 1230
	}
}

static void
1231
_outIter(StringInfo str, Iter *node)
1232
{
M
 
Marc G. Fournier 已提交
1233
	appendStringInfo(str, " ITER :iterexpr ");
1234
	_outNode(str, node->iterexpr);
1235 1236 1237
}

static void
1238
_outStream(StringInfo str, Stream *node)
1239
{
B
Bruce Momjian 已提交
1240 1241 1242 1243 1244 1245
	appendStringInfo(str,
					 " STREAM :pathptr @ 0x%x :cinfo @ 0x%x :clausetype %d :upstream @ 0x%x ",
					 (int) node->pathptr,
					 (int) node->cinfo,
					 (int) node->clausetype,
					 (int) node->upstream);
1246

B
Bruce Momjian 已提交
1247 1248 1249 1250 1251 1252
	appendStringInfo(str,
		   " :downstream @ 0x%x :groupup %d :groupcost %f :groupsel %f ",
					 (int) node->downstream,
					 node->groupup,
					 node->groupcost,
					 node->groupsel);
1253
}
1254

1255 1256 1257
static void
_outAExpr(StringInfo str, A_Expr *node)
{
1258
	appendStringInfo(str, " AEXPR ");
1259 1260 1261
	switch (node->oper)
	{
		case AND:
1262
			appendStringInfo(str, "AND ");
1263 1264
			break;
		case OR:
1265
			appendStringInfo(str, "OR ");
1266 1267
			break;
		case NOT:
1268
			appendStringInfo(str, "NOT ");
1269 1270
			break;
		case ISNULL:
1271
			appendStringInfo(str, "ISNULL ");
1272 1273
			break;
		case NOTNULL:
1274
			appendStringInfo(str, "NOTNULL ");
1275
			break;
1276
		case OP:
1277 1278
			_outToken(str, node->opname);
			appendStringInfo(str, " ");
1279
			break;
1280 1281 1282
		default:
			appendStringInfo(str, "?? ");
			break;
1283
	}
1284
	_outNode(str, node->lexpr);
1285
	appendStringInfo(str, " ");
1286 1287 1288
	_outNode(str, node->rexpr);
}

1289
static void
1290
_outValue(StringInfo str, Value *value)
1291
{
1292 1293
	switch (value->type)
	{
1294
			case T_Integer:
1295
			appendStringInfo(str, " %ld ", value->val.ival);
1296 1297
			break;
		case T_Float:
1298 1299 1300 1301

			/*
			 * We assume the value is a valid numeric literal and so does
			 * not need quoting.
1302 1303 1304 1305 1306 1307 1308
			 */
			appendStringInfo(str, " %s ", value->val.str);
			break;
		case T_String:
			appendStringInfo(str, " \"");
			_outToken(str, value->val.str);
			appendStringInfo(str, "\" ");
1309 1310
			break;
		default:
1311 1312
			elog(NOTICE, "_outValue: don't know how to print type %d ",
				 value->type);
1313
			break;
1314
	}
1315 1316
}

1317 1318 1319
static void
_outIdent(StringInfo str, Ident *node)
{
1320 1321
	appendStringInfo(str, " IDENT ");
	_outToken(str, node->name);
1322 1323
}

1324 1325 1326
static void
_outAttr(StringInfo str, Attr *node)
{
1327
	appendStringInfo(str, " ATTR :relname ");
1328
	_outToken(str, node->relname);
1329 1330
	appendStringInfo(str, " :attrs ");
	_outNode(str, node->attrs);
1331 1332
}

1333 1334 1335
static void
_outAConst(StringInfo str, A_Const *node)
{
1336
	appendStringInfo(str, "CONST ");
1337
	_outValue(str, &(node->val));
1338 1339
	appendStringInfo(str, " :typename ");
	_outNode(str, node->typename);
1340 1341
}

T
Thomas G. Lockhart 已提交
1342 1343 1344
static void
_outConstraint(StringInfo str, Constraint *node)
{
1345 1346 1347
	appendStringInfo(str, " ");
	_outToken(str, node->name);
	appendStringInfo(str, " :type ");
T
Thomas G. Lockhart 已提交
1348 1349 1350 1351

	switch (node->contype)
	{
		case CONSTR_PRIMARY:
1352
			appendStringInfo(str, "PRIMARY KEY ");
T
Thomas G. Lockhart 已提交
1353 1354 1355 1356
			_outNode(str, node->keys);
			break;

		case CONSTR_CHECK:
1357
			appendStringInfo(str, "CHECK :raw ");
1358
			_outNode(str, node->raw_expr);
1359 1360
			appendStringInfo(str, " :cooked ");
			_outToken(str, node->cooked_expr);
T
Thomas G. Lockhart 已提交
1361 1362 1363
			break;

		case CONSTR_DEFAULT:
1364
			appendStringInfo(str, "DEFAULT :raw ");
1365
			_outNode(str, node->raw_expr);
1366 1367
			appendStringInfo(str, " :cooked ");
			_outToken(str, node->cooked_expr);
T
Thomas G. Lockhart 已提交
1368 1369 1370
			break;

		case CONSTR_NOTNULL:
1371
			appendStringInfo(str, "NOT NULL");
T
Thomas G. Lockhart 已提交
1372 1373 1374
			break;

		case CONSTR_UNIQUE:
1375
			appendStringInfo(str, "UNIQUE ");
T
Thomas G. Lockhart 已提交
1376 1377 1378 1379
			_outNode(str, node->keys);
			break;

		default:
1380
			appendStringInfo(str, "<unrecognized_constraint>");
T
Thomas G. Lockhart 已提交
1381 1382 1383 1384 1385
			break;
	}
}

static void
1386
_outCaseExpr(StringInfo str, CaseExpr *node)
T
Thomas G. Lockhart 已提交
1387
{
1388 1389 1390 1391 1392
	appendStringInfo(str, " CASE :casetype %u :arg ",
					 node->casetype);
	_outNode(str, node->arg);

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

1395
	appendStringInfo(str, " :defresult ");
T
Thomas G. Lockhart 已提交
1396 1397 1398 1399
	_outNode(str, node->defresult);
}

static void
1400
_outCaseWhen(StringInfo str, CaseWhen *node)
T
Thomas G. Lockhart 已提交
1401
{
1402
	appendStringInfo(str, " WHEN ");
T
Thomas G. Lockhart 已提交
1403
	_outNode(str, node->expr);
M
 
Marc G. Fournier 已提交
1404

1405
	appendStringInfo(str, " :then ");
T
Thomas G. Lockhart 已提交
1406 1407 1408
	_outNode(str, node->result);
}

1409 1410
/*
 * _outNode -
1411
 *	  converts a Node into ascii string and append it to 'str'
1412 1413 1414 1415
 */
static void
_outNode(StringInfo str, void *obj)
{
1416 1417
	if (obj == NULL)
	{
B
Bruce Momjian 已提交
1418
		appendStringInfo(str, "<>");
1419 1420
		return;
	}
1421

1422
	if (IsA(obj, List))
1423
	{
1424
		List	   *l;
1425

1426
		appendStringInfoChar(str, '(');
1427 1428 1429 1430
		foreach(l, (List *) obj)
		{
			_outNode(str, lfirst(l));
			if (lnext(l))
1431
				appendStringInfoChar(str, ' ');
1432
		}
1433
		appendStringInfoChar(str, ')');
1434
	}
1435 1436 1437 1438 1439
	else if (IsA_Value(obj))
	{
		/* nodeRead does not want to see { } around these! */
		_outValue(str, obj);
	}
1440 1441
	else
	{
1442
		appendStringInfoChar(str, '{');
1443 1444
		switch (nodeTag(obj))
		{
1445 1446 1447 1448 1449 1450 1451 1452 1453
			case T_CreateStmt:
				_outCreateStmt(str, obj);
				break;
			case T_IndexStmt:
				_outIndexStmt(str, obj);
				break;
			case T_ColumnDef:
				_outColumnDef(str, obj);
				break;
1454 1455 1456
			case T_TypeName:
				_outTypeName(str, obj);
				break;
1457 1458 1459
			case T_TypeCast:
				_outTypeCast(str, obj);
				break;
1460 1461 1462
			case T_IndexElem:
				_outIndexElem(str, obj);
				break;
1463 1464 1465
			case T_Query:
				_outQuery(str, obj);
				break;
1466 1467 1468 1469 1470
			case T_SortClause:
				_outSortClause(str, obj);
				break;
			case T_GroupClause:
				_outGroupClause(str, obj);
1471
				break;
1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501
			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;
1502 1503 1504
			case T_TidScan:
				_outTidScan(str, obj);
				break;
1505 1506
			case T_Noname:
				_outNoname(str, obj);
1507
				break;
1508 1509 1510
			case T_Material:
				_outMaterial(str, obj);
				break;
1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525
			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;
			case T_Hash:
				_outHash(str, obj);
				break;
V
Vadim B. Mikheev 已提交
1526 1527 1528
			case T_SubPlan:
				_outSubPlan(str, obj);
				break;
1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543
			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 已提交
1544 1545
			case T_Aggref:
				_outAggref(str, obj);
1546
				break;
1547 1548 1549
			case T_SubLink:
				_outSubLink(str, obj);
				break;
1550 1551 1552
			case T_RelabelType:
				_outRelabelType(str, obj);
				break;
1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570
			case T_Array:
				_outArray(str, obj);
				break;
			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;
			case T_EState:
				_outEState(str, obj);
				break;
B
Bruce Momjian 已提交
1571
			case T_RelOptInfo:
B
Bruce Momjian 已提交
1572
				_outRelOptInfo(str, obj);
1573
				break;
1574 1575 1576
			case T_IndexOptInfo:
				_outIndexOptInfo(str, obj);
				break;
1577 1578 1579 1580 1581 1582
			case T_TargetEntry:
				_outTargetEntry(str, obj);
				break;
			case T_RangeTblEntry:
				_outRangeTblEntry(str, obj);
				break;
1583 1584 1585
			case T_RowMark:
				_outRowMark(str, obj);
				break;
1586 1587 1588 1589 1590 1591
			case T_Path:
				_outPath(str, obj);
				break;
			case T_IndexPath:
				_outIndexPath(str, obj);
				break;
1592 1593 1594
			case T_TidPath:
				_outTidPath(str, obj);
				break;
1595 1596
			case T_NestPath:
				_outNestPath(str, obj);
1597 1598 1599 1600 1601 1602 1603
				break;
			case T_MergePath:
				_outMergePath(str, obj);
				break;
			case T_HashPath:
				_outHashPath(str, obj);
				break;
1604 1605
			case T_PathKeyItem:
				_outPathKeyItem(str, obj);
1606
				break;
1607 1608
			case T_RestrictInfo:
				_outRestrictInfo(str, obj);
1609
				break;
1610 1611
			case T_JoinInfo:
				_outJoinInfo(str, obj);
1612 1613 1614 1615 1616 1617 1618
				break;
			case T_Iter:
				_outIter(str, obj);
				break;
			case T_Stream:
				_outStream(str, obj);
				break;
1619 1620 1621 1622 1623 1624 1625 1626 1627
			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 已提交
1628 1629 1630 1631 1632 1633 1634 1635 1636
			case T_Constraint:
				_outConstraint(str, obj);
				break;
			case T_CaseExpr:
				_outCaseExpr(str, obj);
				break;
			case T_CaseWhen:
				_outCaseWhen(str, obj);
				break;
1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649

			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;

1650
			default:
B
Bruce Momjian 已提交
1651
				elog(NOTICE, "_outNode: don't know how to print type %d ",
1652 1653
					 nodeTag(obj));
				break;
1654
		}
1655
		appendStringInfoChar(str, '}');
1656 1657 1658 1659 1660
	}
}

/*
 * nodeToString -
1661
 *	   returns the ascii representation of the Node as a palloc'd string
1662
 */
1663
char *
1664 1665
nodeToString(void *obj)
{
B
Bruce Momjian 已提交
1666
	StringInfoData str;
1667

1668 1669 1670 1671
	/* see stringinfo.h for an explanation of this maneuver */
	initStringInfo(&str);
	_outNode(&str, obj);
	return str.data;
1672
}