outfuncs.c 36.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.109 2000/02/20 21:32:05 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"
B
Bruce Momjian 已提交
39 40 41
#include "utils/datum.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
42

43 44
#include "../parse.h"

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

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

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

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

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

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

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

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

static void
_outIndexStmt(StringInfo str, IndexStmt *node)
{
123 124 125 126 127 128 129
	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 ");
130
	_outNode(str, node->indexParams);
M
 
Marc G. Fournier 已提交
131

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

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

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

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

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

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

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

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

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

203 204 205
static void
_outIndexElem(StringInfo str, IndexElem *node)
{
206 207 208
	appendStringInfo(str, " INDEXELEM :name ");
	_outToken(str, node->name);
	appendStringInfo(str, " :args ");
209
	_outNode(str, node->args);
210 211 212
	appendStringInfo(str, " :class ");
	_outToken(str, node->class);
	appendStringInfo(str, " :typename ");
213
	_outNode(str, node->typename);
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 224 225 226
	if (node->utilityStmt)
	{
		switch (nodeTag(node->utilityStmt))
		{
			case T_CreateStmt:
227 228 229
				appendStringInfo(str, " :create ");
				_outToken(str, ((CreateStmt *) (node->utilityStmt))->relname);
				appendStringInfo(str, " ");
230 231 232 233
				_outNode(str, node->utilityStmt);
				break;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

301 302 303
}

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

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

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

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

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

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

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

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

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

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

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

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

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

372 373 374
}

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

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

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

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

394 395 396
}

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

405 406 407
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

}

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

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

/*
547
 *	Sort is a subclass of Noname
548 549
 */
static void
550
_outSort(StringInfo str, Sort *node)
551
{
552
	appendStringInfo(str, " SORT ");
553 554
	_outPlanInfo(str, (Plan *) node);

555
	appendStringInfo(str, " :nonameid %u :keycount %d ",
B
Bruce Momjian 已提交
556 557
					 node->nonameid,
					 node->keycount);
558 559 560
}

static void
B
Bruce Momjian 已提交
561
_outAgg(StringInfo str, Agg *node)
562
{
563

564
	appendStringInfo(str, " AGG ");
565
	_outPlanInfo(str, (Plan *) node);
566 567 568
}

static void
569
_outGroup(StringInfo str, Group *node)
570
{
571
	appendStringInfo(str, " GRP ");
572 573 574
	_outPlanInfo(str, (Plan *) node);

	/* the actual Group fields */
M
 
Marc G. Fournier 已提交
575
	appendStringInfo(str, " :numCols %d :tuplePerGroup %s ",
B
Bruce Momjian 已提交
576 577
					 node->numCols,
					 node->tuplePerGroup ? "true" : "false");
578
}
579

580
/*
581
 *	For some reason, unique is a subclass of Noname.
582 583
 */
static void
584
_outUnique(StringInfo str, Unique *node)
585
{
586
	appendStringInfo(str, " UNIQUE ");
587 588
	_outPlanInfo(str, (Plan *) node);

589
	appendStringInfo(str, " :nonameid %u :keycount %d :numCols %d ",
B
Bruce Momjian 已提交
590
					 node->nonameid,
591 592
					 node->keycount,
					 node->numCols);
593 594 595 596
}


/*
597
 *	Hash is a subclass of Noname
598 599
 */
static void
600
_outHash(StringInfo str, Hash *node)
601
{
602
	appendStringInfo(str, " HASH ");
603 604
	_outPlanInfo(str, (Plan *) node);

605
	appendStringInfo(str, " :hashkey ");
606
	_outNode(str, node->hashkey);
607 608 609 610
}

/*****************************************************************************
 *
611
 *	Stuff from primnodes.h.
612 613 614 615
 *
 *****************************************************************************/

/*
616
 *	Resdom is a subclass of Node
617 618
 */
static void
619
_outResdom(StringInfo str, Resdom *node)
620
{
621 622
	appendStringInfo(str,
					 " RESDOM :resno %d :restype %u :restypmod %d :resname ",
B
Bruce Momjian 已提交
623 624 625
					 node->resno,
					 node->restype,
					 node->restypmod);
626 627
	_outToken(str, node->resname);
	appendStringInfo(str, " :reskey %d :reskeyop %u :ressortgroupref %d :resjunk %s ",
B
Bruce Momjian 已提交
628
					 node->reskey,
629
					 node->reskeyop,
630
					 node->ressortgroupref,
B
Bruce Momjian 已提交
631
					 node->resjunk ? "true" : "false");
632 633 634
}

static void
635
_outFjoin(StringInfo str, Fjoin *node)
636
{
637
	int			i;
638

M
 
Marc G. Fournier 已提交
639
	appendStringInfo(str, " FJOIN :initialized %s :nNodes %d ",
B
Bruce Momjian 已提交
640 641
					 node->fj_initialized ? "true" : "false",
					 node->fj_nNodes);
642 643 644 645

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

B
Bruce Momjian 已提交
646 647
	appendStringInfo(str, " :results @ 0x%x :alwaysdone",
					 (int) node->fj_results);
648 649

	for (i = 0; i < node->fj_nNodes; i++)
650
		appendStringInfo(str, (node->fj_alwaysDone[i]) ? "true" : "false");
651 652 653
}

/*
654
 *	Expr is a subclass of Node
655 656
 */
static void
657
_outExpr(StringInfo str, Expr *node)
658
{
659
	char	   *opstr = NULL;
660

M
 
Marc G. Fournier 已提交
661
	appendStringInfo(str, " EXPR :typeOid %u ",
B
Bruce Momjian 已提交
662
					 node->typeOid);
663 664 665

	switch (node->opType)
	{
666 667 668 669 670 671 672 673 674 675 676 677 678 679 680
		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 已提交
681 682 683
		case SUBPLAN_EXPR:
			opstr = "subp";
			break;
684
	}
685 686 687
	appendStringInfo(str, " :opType ");
	_outToken(str, opstr);
	appendStringInfo(str, " :oper ");
688
	_outNode(str, node->oper);
M
 
Marc G. Fournier 已提交
689

690
	appendStringInfo(str, " :args ");
691
	_outNode(str, node->args);
692 693 694
}

/*
695
 *	Var is a subclass of Expr
696 697
 */
static void
698
_outVar(StringInfo str, Var *node)
699
{
B
Bruce Momjian 已提交
700 701 702 703 704 705
	appendStringInfo(str,
				" VAR :varno %d :varattno %d :vartype %u :vartypmod %d ",
					 node->varno,
					 node->varattno,
					 node->vartype,
					 node->vartypmod);
M
 
Marc G. Fournier 已提交
706

B
Bruce Momjian 已提交
707 708 709 710
	appendStringInfo(str, " :varlevelsup %u :varnoold %d :varoattno %d",
					 node->varlevelsup,
					 node->varnoold,
					 node->varoattno);
711 712 713
}

/*
714
 *	Const is a subclass of Expr
715 716
 */
static void
717
_outConst(StringInfo str, Const *node)
718
{
B
Bruce Momjian 已提交
719 720 721 722 723
	appendStringInfo(str,
		" CONST :consttype %u :constlen %d :constisnull %s :constvalue ",
					 node->consttype,
					 node->constlen,
					 node->constisnull ? "true" : "false");
M
 
Marc G. Fournier 已提交
724

725
	if (node->constisnull)
B
Bruce Momjian 已提交
726
		appendStringInfo(str, "<>");
727 728
	else
		_outDatum(str, node->constvalue, node->consttype);
M
 
Marc G. Fournier 已提交
729

B
Bruce Momjian 已提交
730 731
	appendStringInfo(str, " :constbyval %s ",
					 node->constbyval ? "true" : "false");
732 733 734
}

/*
B
Bruce Momjian 已提交
735
 *	Aggref
736 737
 */
static void
738
_outAggref(StringInfo str, Aggref *node)
739
{
740 741 742
	appendStringInfo(str, " AGGREG :aggname ");
	_outToken(str, node->aggname);
	appendStringInfo(str, " :basetype %u :aggtype %u :target ",
B
Bruce Momjian 已提交
743 744
					 node->basetype,
					 node->aggtype);
745
	_outNode(str, node->target);
M
 
Marc G. Fournier 已提交
746

747 748 749 750 751
	appendStringInfo(str, " :usenulls %s :aggstar %s :aggdistinct %s ",
					 node->usenulls ? "true" : "false",
					 node->aggstar ? "true" : "false",
					 node->aggdistinct ? "true" : "false");
	/* aggno is not dumped */
752 753
}

754 755 756 757 758 759
/*
 *	SubLink
 */
static void
_outSubLink(StringInfo str, SubLink *node)
{
B
Bruce Momjian 已提交
760 761 762 763
	appendStringInfo(str,
					 " SUBLINK :subLinkType %d :useor %s :lefthand ",
					 node->subLinkType,
					 node->useor ? "true" : "false");
764
	_outNode(str, node->lefthand);
M
 
Marc G. Fournier 已提交
765

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

769 770 771 772
	appendStringInfo(str, " :subselect ");
	_outNode(str, node->subselect);
}

773 774 775 776 777 778 779 780 781 782 783 784 785
/*
 *	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);
}

786
/*
787
 *	Array is a subclass of Expr
788 789
 */
static void
B
Bruce Momjian 已提交
790
_outArray(StringInfo str, Array *node)
791
{
792
	int			i;
793

B
Bruce Momjian 已提交
794 795 796 797 798
	appendStringInfo(str,
	  " ARRAY :arrayelemtype %u :arrayelemlength %d :arrayelembyval %c ",
					 node->arrayelemtype,
					 node->arrayelemlength,
					 node->arrayelembyval ? 't' : 'f');
M
 
Marc G. Fournier 已提交
799

M
 
Marc G. Fournier 已提交
800
	appendStringInfo(str, " :arrayndim %d :arraylow ", node->arrayndim);
801
	for (i = 0; i < node->arrayndim; i++)
M
 
Marc G. Fournier 已提交
802
		appendStringInfo(str, " %d ", node->arraylow.indx[i]);
803
	appendStringInfo(str, " :arrayhigh ");
804
	for (i = 0; i < node->arrayndim; i++)
M
 
Marc G. Fournier 已提交
805 806
		appendStringInfo(str, " %d ", node->arrayhigh.indx[i]);
	appendStringInfo(str, " :arraylen %d ", node->arraylen);
807 808 809
}

/*
810
 *	ArrayRef is a subclass of Expr
811 812
 */
static void
B
Bruce Momjian 已提交
813
_outArrayRef(StringInfo str, ArrayRef *node)
814
{
B
Bruce Momjian 已提交
815
	appendStringInfo(str,
T
Tom Lane 已提交
816
		" ARRAYREF :refelemtype %u :refattrlength %d :refelemlength %d ",
B
Bruce Momjian 已提交
817 818 819
					 node->refelemtype,
					 node->refattrlength,
					 node->refelemlength);
M
 
Marc G. Fournier 已提交
820

B
Bruce Momjian 已提交
821 822
	appendStringInfo(str, " :refelembyval %c :refupperindex ",
					 node->refelembyval ? 't' : 'f');
823 824
	_outNode(str, node->refupperindexpr);

825
	appendStringInfo(str, " :reflowerindex ");
826 827
	_outNode(str, node->reflowerindexpr);

828
	appendStringInfo(str, " :refexpr ");
829 830
	_outNode(str, node->refexpr);

831
	appendStringInfo(str, " :refassgnexpr ");
832
	_outNode(str, node->refassgnexpr);
833 834 835
}

/*
836
 *	Func is a subclass of Expr
837 838
 */
static void
839
_outFunc(StringInfo str, Func *node)
840
{
B
Bruce Momjian 已提交
841 842 843 844 845 846
	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 已提交
847 848

	appendStringInfo(str, " :func_fcache @ 0x%x :func_tlist ",
B
Bruce Momjian 已提交
849
					 (int) node->func_fcache);
850 851 852 853
	_outNode(str, node->func_tlist);

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

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

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

/*
885
 *	Stuff from execnodes.h
886 887 888
 */

/*
889
 *	EState is a subclass of Node.
890 891
 */
static void
892
_outEState(StringInfo str, EState *node)
893
{
B
Bruce Momjian 已提交
894 895 896
	appendStringInfo(str,
					 " ESTATE :direction %d :range_table ",
					 node->es_direction);
897 898
	_outNode(str, node->es_range_table);

M
 
Marc G. Fournier 已提交
899
	appendStringInfo(str, " :result_relation_info @ 0x%x ",
B
Bruce Momjian 已提交
900
					 (int) (node->es_result_relation_info));
901 902 903
}

/*
904
 *	Stuff from relation.h
905
 */
906

907
static void
908
_outRelOptInfo(StringInfo str, RelOptInfo *node)
909
{
M
 
Marc G. Fournier 已提交
910
	appendStringInfo(str, " RELOPTINFO :relids ");
911 912
	_outIntList(str, node->relids);

B
Bruce Momjian 已提交
913
	appendStringInfo(str,
914 915 916
	 " :rows %.0f :width %d :indexed %s :pages %ld :tuples %.0f :targetlist ",
					 node->rows,
					 node->width,
B
Bruce Momjian 已提交
917 918
					 node->indexed ? "true" : "false",
					 node->pages,
919
					 node->tuples);
920 921
	_outNode(str, node->targetlist);

922
	appendStringInfo(str, " :pathlist ");
923 924
	_outNode(str, node->pathlist);

925 926 927 928
	appendStringInfo(str, " :cheapest_startup_path ");
	_outNode(str, node->cheapest_startup_path);
	appendStringInfo(str, " :cheapest_total_path ");
	_outNode(str, node->cheapest_total_path);
929

B
Bruce Momjian 已提交
930
	appendStringInfo(str,
931
					 " :pruneable %s :baserestrictinfo ",
B
Bruce Momjian 已提交
932
					 node->pruneable ? "true" : "false");
933
	_outNode(str, node->baserestrictinfo);
934

935
	appendStringInfo(str, " :joininfo ");
936 937
	_outNode(str, node->joininfo);

938
	appendStringInfo(str, " :innerjoin ");
939
	_outNode(str, node->innerjoin);
940 941
}

942 943 944 945 946 947 948 949 950
static void
_outIndexOptInfo(StringInfo str, IndexOptInfo *node)
{
	appendStringInfo(str, " INDEXOPTINFO :indexoid %u :pages %ld :tuples %g ",
					 node->indexoid,
					 node->pages,
					 node->tuples);
}

951
/*
952
 *	TargetEntry is a subclass of Node.
953 954
 */
static void
955
_outTargetEntry(StringInfo str, TargetEntry *node)
956
{
M
 
Marc G. Fournier 已提交
957
	appendStringInfo(str, " TARGETENTRY :resdom ");
958 959
	_outNode(str, node->resdom);

960 961
	appendStringInfo(str, " :expr ");
	_outNode(str, node->expr);
962
}
963 964

static void
965
_outRangeTblEntry(StringInfo str, RangeTblEntry *node)
966
{
967 968
	appendStringInfo(str, " RTE :relname ");
	_outToken(str, node->relname);
969 970
	appendStringInfo(str, " :ref ");
	_outNode(str, node->ref);
B
Bruce Momjian 已提交
971
	appendStringInfo(str,
972
					 " :relid %u :inh %s :inFromCl %s :inJoinSet %s :skipAcl %s",
B
Bruce Momjian 已提交
973 974 975
					 node->relid,
					 node->inh ? "true" : "false",
					 node->inFromCl ? "true" : "false",
976
					 node->inJoinSet ? "true" : "false",
B
Bruce Momjian 已提交
977
					 node->skipAcl ? "true" : "false");
978
}
979

980
static void
981
_outRowMark(StringInfo str, RowMark *node)
982 983 984 985
{
	appendStringInfo(str, " ROWMARK :rti %u :info %u", node->rti, node->info);
}

986
/*
987
 *	Path is a subclass of Node.
988 989
 */
static void
990
_outPath(StringInfo str, Path *node)
991
{
992 993
	appendStringInfo(str,
					 " PATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
B
Bruce Momjian 已提交
994
					 node->pathtype,
995 996
					 node->startup_cost,
					 node->total_cost);
997
	_outNode(str, node->pathkeys);
998 999 1000
}

/*
1001
 *	IndexPath is a subclass of Path.
1002 1003
 */
static void
1004
_outIndexPath(StringInfo str, IndexPath *node)
1005
{
B
Bruce Momjian 已提交
1006
	appendStringInfo(str,
1007
					 " INDEXPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
B
Bruce Momjian 已提交
1008
					 node->path.pathtype,
1009 1010
					 node->path.startup_cost,
					 node->path.total_cost);
1011
	_outNode(str, node->path.pathkeys);
1012

1013
	appendStringInfo(str, " :indexid ");
1014 1015
	_outIntList(str, node->indexid);

1016
	appendStringInfo(str, " :indexqual ");
1017
	_outNode(str, node->indexqual);
1018

1019 1020
	appendStringInfo(str, " :indexscandir %d :joinrelids ",
					 (int) node->indexscandir);
1021
	_outIntList(str, node->joinrelids);
1022 1023
}

1024 1025 1026 1027 1028 1029 1030
/*
 *	TidPath is a subclass of Path.
 */
static void
_outTidPath(StringInfo str, TidPath *node)
{
	appendStringInfo(str,
1031
					 " TIDPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
1032
					 node->path.pathtype,
1033 1034
					 node->path.startup_cost,
					 node->path.total_cost);
1035 1036 1037 1038 1039 1040 1041 1042 1043
	_outNode(str, node->path.pathkeys);

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

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

1044
/*
1045
 *	NestPath is a subclass of Path
1046 1047
 */
static void
1048
_outNestPath(StringInfo str, NestPath *node)
1049
{
B
Bruce Momjian 已提交
1050
	appendStringInfo(str,
1051
					 " NESTPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
B
Bruce Momjian 已提交
1052
					 node->path.pathtype,
1053 1054
					 node->path.startup_cost,
					 node->path.total_cost);
1055
	_outNode(str, node->path.pathkeys);
1056 1057 1058 1059 1060 1061
	appendStringInfo(str, " :outerjoinpath ");
	_outNode(str, node->outerjoinpath);
	appendStringInfo(str, " :innerjoinpath ");
	_outNode(str, node->innerjoinpath);
	appendStringInfo(str, " :joinrestrictinfo ");
	_outNode(str, node->joinrestrictinfo);
1062 1063 1064
}

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

1083
	appendStringInfo(str, " :path_mergeclauses ");
1084 1085
	_outNode(str, node->path_mergeclauses);

1086
	appendStringInfo(str, " :outersortkeys ");
1087 1088
	_outNode(str, node->outersortkeys);

1089
	appendStringInfo(str, " :innersortkeys ");
1090
	_outNode(str, node->innersortkeys);
1091 1092 1093
}

/*
1094
 *	HashPath is a subclass of NestPath.
1095 1096
 */
static void
1097
_outHashPath(StringInfo str, HashPath *node)
1098
{
B
Bruce Momjian 已提交
1099
	appendStringInfo(str,
1100
					 " HASHPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
B
Bruce Momjian 已提交
1101
					 node->jpath.path.pathtype,
1102 1103
					 node->jpath.path.startup_cost,
					 node->jpath.path.total_cost);
1104
	_outNode(str, node->jpath.path.pathkeys);
1105 1106 1107 1108 1109 1110
	appendStringInfo(str, " :outerjoinpath ");
	_outNode(str, node->jpath.outerjoinpath);
	appendStringInfo(str, " :innerjoinpath ");
	_outNode(str, node->jpath.innerjoinpath);
	appendStringInfo(str, " :joinrestrictinfo ");
	_outNode(str, node->jpath.joinrestrictinfo);
1111

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

/*
1117
 *	PathKeyItem is a subclass of Node.
1118 1119
 */
static void
1120
_outPathKeyItem(StringInfo str, PathKeyItem *node)
1121
{
1122 1123 1124
	appendStringInfo(str, " PATHKEYITEM :sortop %u :key ",
					 node->sortop);
	_outNode(str, node->key);
1125 1126 1127
}

/*
1128
 *	RestrictInfo is a subclass of Node.
1129 1130
 */
static void
1131
_outRestrictInfo(StringInfo str, RestrictInfo *node)
1132
{
B
Bruce Momjian 已提交
1133
	appendStringInfo(str, " RESTRICTINFO :clause ");
1134 1135
	_outNode(str, node->clause);

1136
	appendStringInfo(str, " :subclauseindices ");
1137
	_outNode(str, node->subclauseindices);
1138

1139 1140 1141
	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 已提交
1142
	appendStringInfo(str, " :hashjoinoperator %u ", node->hashjoinoperator);
1143 1144 1145
}

/*
1146
 *	JoinInfo is a subclass of Node.
1147 1148
 */
static void
1149
_outJoinInfo(StringInfo str, JoinInfo *node)
1150
{
B
Bruce Momjian 已提交
1151 1152
	appendStringInfo(str, " JINFO :unjoined_relids ");
	_outIntList(str, node->unjoined_relids);
1153

1154 1155
	appendStringInfo(str, " :jinfo_restrictinfo ");
	_outNode(str, node->jinfo_restrictinfo);
1156 1157 1158 1159 1160 1161 1162 1163
}

/*
 * Print the value of a Datum given its type.
 */
static void
_outDatum(StringInfo str, Datum value, Oid type)
{
B
Bruce Momjian 已提交
1164
	char	   *s;
1165
	Size		length,
B
Bruce Momjian 已提交
1166
				typeLength;
1167 1168
	bool		byValue;
	int			i;
1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180

	/*
	 * 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 已提交
1181
		appendStringInfo(str, " %d [ ", length);
1182
		for (i = 0; i < sizeof(Datum); i++)
1183
			appendStringInfo(str, "%d ", (int) (s[i]));
M
 
Marc G. Fournier 已提交
1184
		appendStringInfo(str, "] ");
1185
	}
1186 1187 1188 1189
	else
	{							/* !byValue */
		s = (char *) DatumGetPointer(value);
		if (!PointerIsValid(s))
M
 
Marc G. Fournier 已提交
1190
			appendStringInfo(str, " 0 [ ] ");
1191 1192
		else
		{
B
Bruce Momjian 已提交
1193

1194 1195 1196 1197 1198 1199
			/*
			 * 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 已提交
1200
			appendStringInfo(str, " %d [ ", length);
1201
			for (i = 0; i < length; i++)
1202
				appendStringInfo(str, "%d ", (int) (s[i]));
M
 
Marc G. Fournier 已提交
1203
			appendStringInfo(str, "] ");
1204
		}
1205 1206 1207 1208
	}
}

static void
1209
_outIter(StringInfo str, Iter *node)
1210
{
M
 
Marc G. Fournier 已提交
1211
	appendStringInfo(str, " ITER :iterexpr ");
1212
	_outNode(str, node->iterexpr);
1213 1214 1215
}

static void
1216
_outStream(StringInfo str, Stream *node)
1217
{
B
Bruce Momjian 已提交
1218 1219 1220 1221 1222 1223
	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);
1224

B
Bruce Momjian 已提交
1225 1226 1227 1228 1229 1230
	appendStringInfo(str,
		   " :downstream @ 0x%x :groupup %d :groupcost %f :groupsel %f ",
					 (int) node->downstream,
					 node->groupup,
					 node->groupcost,
					 node->groupsel);
1231
}
1232

1233 1234 1235
static void
_outAExpr(StringInfo str, A_Expr *node)
{
1236
	appendStringInfo(str, "EXPR ");
1237 1238 1239
	switch (node->oper)
	{
		case AND:
1240
			appendStringInfo(str, "AND ");
1241 1242
			break;
		case OR:
1243
			appendStringInfo(str, "OR ");
1244 1245
			break;
		case NOT:
1246
			appendStringInfo(str, "NOT ");
1247 1248
			break;
		case ISNULL:
1249
			appendStringInfo(str, "ISNULL ");
1250 1251
			break;
		case NOTNULL:
1252
			appendStringInfo(str, "NOTNULL ");
1253 1254
			break;
		default:
1255 1256
			_outToken(str, node->opname);
			appendStringInfo(str, " ");
1257 1258
			break;
	}
1259 1260 1261 1262
	_outNode(str, node->lexpr);
	_outNode(str, node->rexpr);
}

1263
static void
1264
_outValue(StringInfo str, Value *value)
1265
{
1266 1267
	switch (value->type)
	{
1268 1269 1270 1271
		case T_String:
			appendStringInfo(str, " \"");
			_outToken(str, value->val.str);
			appendStringInfo(str, "\" ");
1272 1273
			break;
		case T_Integer:
1274
			appendStringInfo(str, " %ld ", value->val.ival);
1275 1276
			break;
		case T_Float:
1277
			appendStringInfo(str, " %.17g ", value->val.dval);
1278 1279
			break;
		default:
1280 1281
			elog(NOTICE, "_outValue: don't know how to print type %d ",
				 value->type);
1282
			break;
1283
	}
1284 1285
}

1286 1287 1288
static void
_outIdent(StringInfo str, Ident *node)
{
1289 1290
	appendStringInfo(str, " IDENT ");
	_outToken(str, node->name);
1291 1292
}

1293 1294 1295
static void
_outAttr(StringInfo str, Attr *node)
{
1296
	appendStringInfo(str, " ATTR :relname ");
1297
	_outToken(str, node->relname);
1298 1299
	appendStringInfo(str, " :attrs ");
	_outNode(str, node->attrs);
1300 1301
}

1302 1303 1304
static void
_outAConst(StringInfo str, A_Const *node)
{
1305
	appendStringInfo(str, "CONST ");
1306
	_outValue(str, &(node->val));
1307 1308
	appendStringInfo(str, " :typename ");
	_outNode(str, node->typename);
1309 1310
}

T
Thomas G. Lockhart 已提交
1311 1312 1313
static void
_outConstraint(StringInfo str, Constraint *node)
{
1314 1315 1316
	appendStringInfo(str, " ");
	_outToken(str, node->name);
	appendStringInfo(str, " :type ");
T
Thomas G. Lockhart 已提交
1317 1318 1319 1320

	switch (node->contype)
	{
		case CONSTR_PRIMARY:
1321
			appendStringInfo(str, "PRIMARY KEY ");
T
Thomas G. Lockhart 已提交
1322 1323 1324 1325
			_outNode(str, node->keys);
			break;

		case CONSTR_CHECK:
1326
			appendStringInfo(str, "CHECK :raw ");
1327
			_outNode(str, node->raw_expr);
1328 1329
			appendStringInfo(str, " :cooked ");
			_outToken(str, node->cooked_expr);
T
Thomas G. Lockhart 已提交
1330 1331 1332
			break;

		case CONSTR_DEFAULT:
1333
			appendStringInfo(str, "DEFAULT :raw ");
1334
			_outNode(str, node->raw_expr);
1335 1336
			appendStringInfo(str, " :cooked ");
			_outToken(str, node->cooked_expr);
T
Thomas G. Lockhart 已提交
1337 1338 1339
			break;

		case CONSTR_NOTNULL:
1340
			appendStringInfo(str, "NOT NULL");
T
Thomas G. Lockhart 已提交
1341 1342 1343
			break;

		case CONSTR_UNIQUE:
1344
			appendStringInfo(str, "UNIQUE ");
T
Thomas G. Lockhart 已提交
1345 1346 1347 1348
			_outNode(str, node->keys);
			break;

		default:
1349
			appendStringInfo(str, "<unrecognized_constraint>");
T
Thomas G. Lockhart 已提交
1350 1351 1352 1353 1354
			break;
	}
}

static void
1355
_outCaseExpr(StringInfo str, CaseExpr *node)
T
Thomas G. Lockhart 已提交
1356
{
1357
	appendStringInfo(str, "CASE ");
T
Thomas G. Lockhart 已提交
1358
	_outNode(str, node->args);
M
 
Marc G. Fournier 已提交
1359

1360
	appendStringInfo(str, " :default ");
T
Thomas G. Lockhart 已提交
1361 1362 1363 1364
	_outNode(str, node->defresult);
}

static void
1365
_outCaseWhen(StringInfo str, CaseWhen *node)
T
Thomas G. Lockhart 已提交
1366
{
1367
	appendStringInfo(str, " WHEN ");
T
Thomas G. Lockhart 已提交
1368
	_outNode(str, node->expr);
M
 
Marc G. Fournier 已提交
1369

1370
	appendStringInfo(str, " :then ");
T
Thomas G. Lockhart 已提交
1371 1372 1373
	_outNode(str, node->result);
}

1374 1375
/*
 * _outNode -
1376
 *	  converts a Node into ascii string and append it to 'str'
1377 1378 1379 1380
 */
static void
_outNode(StringInfo str, void *obj)
{
1381 1382
	if (obj == NULL)
	{
B
Bruce Momjian 已提交
1383
		appendStringInfo(str, "<>");
1384 1385
		return;
	}
1386

1387
	if (IsA(obj, List))
1388
	{
1389
		List	   *l;
1390

1391
		appendStringInfoChar(str, '(');
1392 1393 1394 1395
		foreach(l, (List *) obj)
		{
			_outNode(str, lfirst(l));
			if (lnext(l))
1396
				appendStringInfoChar(str, ' ');
1397
		}
1398
		appendStringInfoChar(str, ')');
1399
	}
1400 1401 1402 1403 1404
	else if (IsA_Value(obj))
	{
		/* nodeRead does not want to see { } around these! */
		_outValue(str, obj);
	}
1405 1406
	else
	{
1407
		appendStringInfoChar(str, '{');
1408 1409
		switch (nodeTag(obj))
		{
1410 1411 1412 1413 1414 1415 1416 1417 1418
			case T_CreateStmt:
				_outCreateStmt(str, obj);
				break;
			case T_IndexStmt:
				_outIndexStmt(str, obj);
				break;
			case T_ColumnDef:
				_outColumnDef(str, obj);
				break;
1419 1420 1421
			case T_TypeName:
				_outTypeName(str, obj);
				break;
1422 1423 1424
			case T_TypeCast:
				_outTypeCast(str, obj);
				break;
1425 1426 1427
			case T_IndexElem:
				_outIndexElem(str, obj);
				break;
1428 1429 1430
			case T_Query:
				_outQuery(str, obj);
				break;
1431 1432 1433 1434 1435
			case T_SortClause:
				_outSortClause(str, obj);
				break;
			case T_GroupClause:
				_outGroupClause(str, obj);
1436
				break;
1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466
			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;
1467 1468 1469
			case T_TidScan:
				_outTidScan(str, obj);
				break;
1470 1471
			case T_Noname:
				_outNoname(str, obj);
1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487
				break;
			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 已提交
1488 1489 1490
			case T_SubPlan:
				_outSubPlan(str, obj);
				break;
1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505
			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 已提交
1506 1507
			case T_Aggref:
				_outAggref(str, obj);
1508
				break;
1509 1510 1511
			case T_SubLink:
				_outSubLink(str, obj);
				break;
1512 1513 1514
			case T_RelabelType:
				_outRelabelType(str, obj);
				break;
1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532
			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 已提交
1533
			case T_RelOptInfo:
B
Bruce Momjian 已提交
1534
				_outRelOptInfo(str, obj);
1535
				break;
1536 1537 1538
			case T_IndexOptInfo:
				_outIndexOptInfo(str, obj);
				break;
1539 1540 1541 1542 1543 1544
			case T_TargetEntry:
				_outTargetEntry(str, obj);
				break;
			case T_RangeTblEntry:
				_outRangeTblEntry(str, obj);
				break;
1545 1546 1547
			case T_RowMark:
				_outRowMark(str, obj);
				break;
1548 1549 1550 1551 1552 1553
			case T_Path:
				_outPath(str, obj);
				break;
			case T_IndexPath:
				_outIndexPath(str, obj);
				break;
1554 1555 1556
			case T_TidPath:
				_outTidPath(str, obj);
				break;
1557 1558
			case T_NestPath:
				_outNestPath(str, obj);
1559 1560 1561 1562 1563 1564 1565
				break;
			case T_MergePath:
				_outMergePath(str, obj);
				break;
			case T_HashPath:
				_outHashPath(str, obj);
				break;
1566 1567
			case T_PathKeyItem:
				_outPathKeyItem(str, obj);
1568
				break;
1569 1570
			case T_RestrictInfo:
				_outRestrictInfo(str, obj);
1571
				break;
1572 1573
			case T_JoinInfo:
				_outJoinInfo(str, obj);
1574 1575 1576 1577 1578 1579 1580
				break;
			case T_Iter:
				_outIter(str, obj);
				break;
			case T_Stream:
				_outStream(str, obj);
				break;
1581 1582 1583 1584 1585 1586 1587 1588 1589
			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 已提交
1590 1591 1592 1593 1594 1595 1596 1597 1598
			case T_Constraint:
				_outConstraint(str, obj);
				break;
			case T_CaseExpr:
				_outCaseExpr(str, obj);
				break;
			case T_CaseWhen:
				_outCaseWhen(str, obj);
				break;
1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611

			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;

1612
			default:
B
Bruce Momjian 已提交
1613
				elog(NOTICE, "_outNode: don't know how to print type %d ",
1614 1615
					 nodeTag(obj));
				break;
1616
		}
1617
		appendStringInfoChar(str, '}');
1618 1619 1620 1621 1622
	}
}

/*
 * nodeToString -
1623
 *	   returns the ascii representation of the Node as a palloc'd string
1624
 */
1625
char *
1626 1627
nodeToString(void *obj)
{
B
Bruce Momjian 已提交
1628
	StringInfoData str;
1629

1630 1631 1632 1633
	/* see stringinfo.h for an explanation of this maneuver */
	initStringInfo(&str);
	_outNode(&str, obj);
	return str.data;
1634
}