readfuncs.c 51.8 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * readfuncs.c
4
 *	  Reader functions for Postgres tree nodes.
5
 *
6
 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
Bruce Momjian's avatar
Add:  
Bruce Momjian committed
7
 * Portions Copyright (c) 1994, Regents of the University of California
8 9 10
 *
 *
 * IDENTIFICATION
11
 *	  $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.108 2001/05/07 00:43:19 tgl Exp $
12 13
 *
 * NOTES
14 15 16 17 18 19 20 21 22 23
 *	  Most of the read functions for plan nodes are tested. (In fact, they
 *	  pass the regression test as of 11/8/94.) The rest (for path selection)
 *	  are probably never used. No effort has been made to get them to work.
 *	  The simplest way to test these functions is by doing the following in
 *	  ProcessQuery (before executing the plan):
 *				plan = stringToNode(nodeToString(plan));
 *	  Then, run the regression test. Let's just say you'll notice if either
 *	  of the above function are not properly done.
 *														- ay 11/94
 *
24 25 26 27
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

28 29
#include <math.h>

30 31
#include "nodes/plannodes.h"
#include "nodes/readfuncs.h"
Bruce Momjian's avatar
Bruce Momjian committed
32
#include "nodes/relation.h"
33 34


35 36 37
/*
 * NOTE: use atoi() to read values written with %d, or atoui() to read
 * values written with %u in outfuncs.c.  An exception is OID values,
38
 * for which use atooid().	(As of 7.1, outfuncs.c writes OIDs as %u,
39 40 41 42 43 44 45 46 47 48 49 50
 * but this will probably change in the future.)
 */
#define atoui(x)  ((unsigned int) strtoul((x), NULL, 10))

#define atooid(x)  ((Oid) strtoul((x), NULL, 10))

#define strtobool(x)  ((*(x) == 't') ? true : false)

#define nullable_string(token,length)  \
	((length) == 0 ? (char *) NULL : debackslash(token, length))


51 52
static Datum readDatum(bool typbyval);

53 54

/* ----------------
55
 *		node creator declarations
56 57 58
 * ----------------
 */

59
/* Convert Value list returned by nodeRead into list of integers */
60
static List *
61
toIntList(List *list)
62
{
63
	List	   *l;
64 65 66

	foreach(l, list)
	{
67
		Value	   *v = (Value *) lfirst(l);
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84

		if (!IsA(v, Integer))
			elog(ERROR, "toIntList: unexpected datatype");
		lfirsti(l) = intVal(v);
		pfree(v);
	}
	return list;
}

/* Convert Value list returned by nodeRead into list of OIDs */
static List *
toOidList(List *list)
{
	List	   *l;

	foreach(l, list)
	{
85
		Value	   *v = (Value *) lfirst(l);
86 87 88

		/*
		 * This is a bit tricky because OID is unsigned, and so nodeRead
89 90
		 * might have concluded the value doesn't fit in an integer. Must
		 * cope with T_Float as well.
91 92 93 94 95 96 97 98 99 100 101 102 103 104
		 */
		if (IsA(v, Integer))
		{
			lfirsti(l) = (Oid) intVal(v);
			pfree(v);
		}
		else if (IsA(v, Float))
		{
			lfirsti(l) = atooid(strVal(v));
			pfree(strVal(v));
			pfree(v);
		}
		else
			elog(ERROR, "toOidList: unexpected datatype");
105 106
	}
	return list;
107 108 109
}

/* ----------------
110
 *		_readQuery
111 112
 * ----------------
 */
113
static Query *
114
_readQuery(void)
115
{
116 117 118
	Query	   *local_node;
	char	   *token;
	int			length;
119

120 121
	local_node = makeNode(Query);

122 123
	token = pg_strtok(&length); /* skip the :command */
	token = pg_strtok(&length); /* get the commandType */
124 125
	local_node->commandType = atoi(token);

126
	token = pg_strtok(&length); /* skip :utility */
127
	token = pg_strtok(&length);
128
	if (length == 0)
129 130 131
		local_node->utilityStmt = NULL;
	else
	{
132

133 134 135 136 137
		/*
		 * Hack to make up for lack of readfuncs for utility-stmt nodes
		 *
		 * we can't get create or index here, can we?
		 */
138
		NotifyStmt *n = makeNode(NotifyStmt);
139

140
		n->relname = debackslash(token, length);
141 142 143
		local_node->utilityStmt = (Node *) n;
	}

144 145
	token = pg_strtok(&length); /* skip the :resultRelation */
	token = pg_strtok(&length); /* get the resultRelation */
146 147
	local_node->resultRelation = atoi(token);

148 149
	token = pg_strtok(&length); /* skip :into */
	token = pg_strtok(&length); /* get into */
150
	local_node->into = nullable_string(token, length);
151

152 153
	token = pg_strtok(&length); /* skip :isPortal */
	token = pg_strtok(&length); /* get isPortal */
154
	local_node->isPortal = strtobool(token);
155

156 157
	token = pg_strtok(&length); /* skip :isBinary */
	token = pg_strtok(&length); /* get isBinary */
158
	local_node->isBinary = strtobool(token);
159

160 161
	token = pg_strtok(&length); /* skip :isTemp */
	token = pg_strtok(&length); /* get isTemp */
162
	local_node->isTemp = strtobool(token);
163

164 165
	token = pg_strtok(&length); /* skip the :hasAggs */
	token = pg_strtok(&length); /* get hasAggs */
166
	local_node->hasAggs = strtobool(token);
167

168 169
	token = pg_strtok(&length); /* skip the :hasSubLinks */
	token = pg_strtok(&length); /* get hasSubLinks */
170
	local_node->hasSubLinks = strtobool(token);
171

172
	token = pg_strtok(&length); /* skip :rtable */
173 174
	local_node->rtable = nodeRead(true);

175
	token = pg_strtok(&length); /* skip :jointree */
176 177
	local_node->jointree = nodeRead(true);

178
	token = pg_strtok(&length); /* skip :rowMarks */
179 180
	local_node->rowMarks = toIntList(nodeRead(true));

181
	token = pg_strtok(&length); /* skip :targetlist */
182
	local_node->targetList = nodeRead(true);
183

184
	token = pg_strtok(&length); /* skip :groupClause */
185 186
	local_node->groupClause = nodeRead(true);

187
	token = pg_strtok(&length); /* skip :havingQual */
188 189
	local_node->havingQual = nodeRead(true);

190
	token = pg_strtok(&length); /* skip :distinctClause */
191
	local_node->distinctClause = nodeRead(true);
Bruce Momjian's avatar
Bruce Momjian committed
192

193
	token = pg_strtok(&length); /* skip :sortClause */
194
	local_node->sortClause = nodeRead(true);
Bruce Momjian's avatar
Hi!  
Bruce Momjian committed
195

196
	token = pg_strtok(&length); /* skip :limitOffset */
Bruce Momjian's avatar
Bruce Momjian committed
197 198
	local_node->limitOffset = nodeRead(true);

199
	token = pg_strtok(&length); /* skip :limitCount */
Bruce Momjian's avatar
Bruce Momjian committed
200 201
	local_node->limitCount = nodeRead(true);

202
	token = pg_strtok(&length); /* skip :setOperations */
203 204
	local_node->setOperations = nodeRead(true);

205
	token = pg_strtok(&length); /* skip :resultRelations */
206 207
	local_node->resultRelations = toIntList(nodeRead(true));

208
	return local_node;
209 210 211
}

/* ----------------
212
 *		_readSortClause
213 214
 * ----------------
 */
215
static SortClause *
216
_readSortClause(void)
217
{
218
	SortClause *local_node;
219 220 221
	char	   *token;
	int			length;

222
	local_node = makeNode(SortClause);
223

224 225
	token = pg_strtok(&length); /* skip :tleSortGroupRef */
	token = pg_strtok(&length); /* get tleSortGroupRef */
226
	local_node->tleSortGroupRef = atoui(token);
227

228 229
	token = pg_strtok(&length); /* skip :sortop */
	token = pg_strtok(&length); /* get sortop */
230
	local_node->sortop = atooid(token);
231

232
	return local_node;
233
}
234

235 236 237 238 239
/* ----------------
 *		_readGroupClause
 * ----------------
 */
static GroupClause *
240
_readGroupClause(void)
241 242 243 244 245 246 247
{
	GroupClause *local_node;
	char	   *token;
	int			length;

	local_node = makeNode(GroupClause);

248 249
	token = pg_strtok(&length); /* skip :tleSortGroupRef */
	token = pg_strtok(&length); /* get tleSortGroupRef */
250
	local_node->tleSortGroupRef = atoui(token);
251

252 253
	token = pg_strtok(&length); /* skip :sortop */
	token = pg_strtok(&length); /* get sortop */
254
	local_node->sortop = atooid(token);
255

256
	return local_node;
257 258
}

259 260 261 262 263
/* ----------------
 *		_readSetOperationStmt
 * ----------------
 */
static SetOperationStmt *
264
_readSetOperationStmt(void)
265 266 267 268 269 270 271
{
	SetOperationStmt *local_node;
	char	   *token;
	int			length;

	local_node = makeNode(SetOperationStmt);

272 273
	token = pg_strtok(&length); /* eat :op */
	token = pg_strtok(&length); /* get op */
274 275
	local_node->op = (SetOperation) atoi(token);

276 277
	token = pg_strtok(&length); /* eat :all */
	token = pg_strtok(&length); /* get all */
278
	local_node->all = strtobool(token);
279

280
	token = pg_strtok(&length); /* eat :larg */
281 282
	local_node->larg = nodeRead(true);	/* get larg */

283
	token = pg_strtok(&length); /* eat :rarg */
284 285
	local_node->rarg = nodeRead(true);	/* get rarg */

286
	token = pg_strtok(&length); /* eat :colTypes */
287
	local_node->colTypes = toOidList(nodeRead(true));
288 289 290 291

	return local_node;
}

292
/* ----------------
293
 *		_getPlan
294 295 296
 * ----------------
 */
static void
297
_getPlan(Plan *node)
298
{
299 300
	char	   *token;
	int			length;
301

302 303
	token = pg_strtok(&length); /* first token is :startup_cost */
	token = pg_strtok(&length); /* next is the actual cost */
304 305
	node->startup_cost = (Cost) atof(token);

306 307
	token = pg_strtok(&length); /* skip the :total_cost */
	token = pg_strtok(&length); /* next is the actual cost */
308
	node->total_cost = (Cost) atof(token);
309

310 311
	token = pg_strtok(&length); /* skip the :rows */
	token = pg_strtok(&length); /* get the plan_rows */
312
	node->plan_rows = atof(token);
313

314 315
	token = pg_strtok(&length); /* skip the :width */
	token = pg_strtok(&length); /* get the plan_width */
316 317
	node->plan_width = atoi(token);

318
	token = pg_strtok(&length); /* eat :qptargetlist */
319 320
	node->targetlist = nodeRead(true);

321
	token = pg_strtok(&length); /* eat :qpqual */
322 323
	node->qual = nodeRead(true);

324
	token = pg_strtok(&length); /* eat :lefttree */
325 326
	node->lefttree = (Plan *) nodeRead(true);

327
	token = pg_strtok(&length); /* eat :righttree */
328 329
	node->righttree = (Plan *) nodeRead(true);

330 331
	node->state = (EState *) NULL;		/* never read in */

332
	return;
333 334 335
}

/*
336
 *	Stuff from plannodes.h
337 338 339
 */

/* ----------------
340
 *		_readPlan
341 342
 * ----------------
 */
343
static Plan *
344
_readPlan(void)
345
{
346
	Plan	   *local_node;
347 348 349 350 351

	local_node = makeNode(Plan);

	_getPlan(local_node);

352
	return local_node;
353 354 355
}

/* ----------------
356
 *		_readResult
357 358
 * ----------------
 */
359
static Result *
360
_readResult(void)
361
{
362 363 364
	Result	   *local_node;
	char	   *token;
	int			length;
365 366 367 368 369

	local_node = makeNode(Result);

	_getPlan((Plan *) local_node);

370
	token = pg_strtok(&length); /* eat :resconstantqual */
371 372
	local_node->resconstantqual = nodeRead(true);		/* now read it */

373
	return local_node;
374 375 376
}

/* ----------------
377
 *		_readAppend
378
 *
379
 *	Append is a subclass of Plan.
380 381 382
 * ----------------
 */

383
static Append *
384
_readAppend(void)
385
{
386 387 388
	Append	   *local_node;
	char	   *token;
	int			length;
389 390 391 392 393

	local_node = makeNode(Append);

	_getPlan((Plan *) local_node);

394
	token = pg_strtok(&length); /* eat :appendplans */
395
	local_node->appendplans = nodeRead(true);	/* now read it */
396

397 398
	token = pg_strtok(&length); /* eat :isTarget */
	token = pg_strtok(&length); /* get isTarget */
399
	local_node->isTarget = strtobool(token);
400

401
	return local_node;
402 403 404
}

/* ----------------
405
 *		_getJoin
406 407 408
 * ----------------
 */
static void
409
_getJoin(Join *node)
410
{
411 412 413
	char	   *token;
	int			length;

414
	_getPlan((Plan *) node);
415

416 417
	token = pg_strtok(&length); /* skip the :jointype */
	token = pg_strtok(&length); /* get the jointype */
418 419
	node->jointype = (JoinType) atoi(token);

420
	token = pg_strtok(&length); /* skip the :joinqual */
421
	node->joinqual = nodeRead(true);	/* get the joinqual */
422 423 424 425
}


/* ----------------
426
 *		_readJoin
427
 *
428
 *	Join is a subclass of Plan
429 430
 * ----------------
 */
431
static Join *
432
_readJoin(void)
433
{
434
	Join	   *local_node;
435 436 437 438 439

	local_node = makeNode(Join);

	_getJoin(local_node);

440
	return local_node;
441 442 443
}

/* ----------------
444 445 446
 *		_readNestLoop
 *
 *	NestLoop is a subclass of Join
447 448 449 450
 * ----------------
 */

static NestLoop *
451
_readNestLoop(void)
452
{
453
	NestLoop   *local_node;
454 455 456 457 458

	local_node = makeNode(NestLoop);

	_getJoin((Join *) local_node);

459
	return local_node;
460 461 462
}

/* ----------------
463 464 465
 *		_readMergeJoin
 *
 *	MergeJoin is a subclass of Join
466 467 468
 * ----------------
 */
static MergeJoin *
469
_readMergeJoin(void)
470
{
471 472 473
	MergeJoin  *local_node;
	char	   *token;
	int			length;
474 475 476 477

	local_node = makeNode(MergeJoin);

	_getJoin((Join *) local_node);
478

479
	token = pg_strtok(&length); /* eat :mergeclauses */
480 481
	local_node->mergeclauses = nodeRead(true);	/* now read it */

482
	return local_node;
483 484 485
}

/* ----------------
486 487 488
 *		_readHashJoin
 *
 *	HashJoin is a subclass of Join.
489 490 491
 * ----------------
 */
static HashJoin *
492
_readHashJoin(void)
493
{
494 495 496
	HashJoin   *local_node;
	char	   *token;
	int			length;
497 498 499 500 501

	local_node = makeNode(HashJoin);

	_getJoin((Join *) local_node);

502
	token = pg_strtok(&length); /* eat :hashclauses */
503 504
	local_node->hashclauses = nodeRead(true);	/* now read it */

505 506
	token = pg_strtok(&length); /* eat :hashjoinop */
	token = pg_strtok(&length); /* get hashjoinop */
507
	local_node->hashjoinop = atooid(token);
508

509
	return local_node;
510 511 512
}

/* ----------------
513
 *		_getScan
514
 *
515
 *	Scan is a subclass of Plan.
516
 *
517
 *	Scan gets its own get function since stuff inherits it.
518 519
 * ----------------
 */
520
static void
521
_getScan(Scan *node)
522
{
523 524
	char	   *token;
	int			length;
525 526 527

	_getPlan((Plan *) node);

528 529
	token = pg_strtok(&length); /* eat :scanrelid */
	token = pg_strtok(&length); /* get scanrelid */
530
	node->scanrelid = atoui(token);
531 532 533
}

/* ----------------
534 535
 *		_readScan
 *
536
 * Scan is a subclass of Plan.
537 538
 * ----------------
 */
539
static Scan *
540
_readScan(void)
541
{
542
	Scan	   *local_node;
543 544 545 546 547

	local_node = makeNode(Scan);

	_getScan(local_node);

548
	return local_node;
549 550 551
}

/* ----------------
552 553 554
 *		_readSeqScan
 *
 *	SeqScan is a subclass of Scan
555 556 557
 * ----------------
 */
static SeqScan *
558
_readSeqScan(void)
559
{
560
	SeqScan    *local_node;
561 562 563 564 565

	local_node = makeNode(SeqScan);

	_getScan((Scan *) local_node);

566
	return local_node;
567 568 569
}

/* ----------------
570 571 572
 *		_readIndexScan
 *
 *	IndexScan is a subclass of Scan
573 574 575
 * ----------------
 */
static IndexScan *
576
_readIndexScan(void)
577
{
578 579 580
	IndexScan  *local_node;
	char	   *token;
	int			length;
581 582 583 584 585

	local_node = makeNode(IndexScan);

	_getScan((Scan *) local_node);

586
	token = pg_strtok(&length); /* eat :indxid */
587
	local_node->indxid = toOidList(nodeRead(true));		/* now read it */
588

589
	token = pg_strtok(&length); /* eat :indxqual */
590 591
	local_node->indxqual = nodeRead(true);		/* now read it */

592
	token = pg_strtok(&length); /* eat :indxqualorig */
Bruce Momjian's avatar
Bruce Momjian committed
593
	local_node->indxqualorig = nodeRead(true);	/* now read it */
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
594

595 596
	token = pg_strtok(&length); /* eat :indxorderdir */
	token = pg_strtok(&length); /* get indxorderdir */
597 598
	local_node->indxorderdir = atoi(token);

599
	return local_node;
600 601
}

602 603 604 605 606 607 608
/* ----------------
 *		_readTidScan
 *
 *	TidScan is a subclass of Scan
 * ----------------
 */
static TidScan *
609
_readTidScan(void)
610
{
611
	TidScan    *local_node;
612 613 614 615 616 617 618
	char	   *token;
	int			length;

	local_node = makeNode(TidScan);

	_getScan((Scan *) local_node);

619 620
	token = pg_strtok(&length); /* eat :needrescan */
	token = pg_strtok(&length); /* get needrescan */
621 622
	local_node->needRescan = atoi(token);

623
	token = pg_strtok(&length); /* eat :tideval */
624
	local_node->tideval = nodeRead(true);		/* now read it */
625 626 627 628

	return local_node;
}

629 630 631 632 633 634 635
/* ----------------
 *		_readSubqueryScan
 *
 *	SubqueryScan is a subclass of Scan
 * ----------------
 */
static SubqueryScan *
636
_readSubqueryScan(void)
637
{
638
	SubqueryScan *local_node;
639 640 641 642 643 644 645
	char	   *token;
	int			length;

	local_node = makeNode(SubqueryScan);

	_getScan((Scan *) local_node);

646 647
	token = pg_strtok(&length); /* eat :subplan */
	local_node->subplan = nodeRead(true);		/* now read it */
648 649 650 651

	return local_node;
}

652
/* ----------------
653 654
 *		_readSort
 *
655
 *	Sort is a subclass of Plan
656 657
 * ----------------
 */
658
static Sort *
659
_readSort(void)
660
{
661 662 663
	Sort	   *local_node;
	char	   *token;
	int			length;
664 665 666 667 668

	local_node = makeNode(Sort);

	_getPlan((Plan *) local_node);

669 670
	token = pg_strtok(&length); /* eat :keycount */
	token = pg_strtok(&length); /* get keycount */
671 672
	local_node->keycount = atoi(token);

673
	return local_node;
674 675
}

676
static Agg *
677
_readAgg(void)
678
{
679
	Agg		   *local_node;
680 681 682 683

	local_node = makeNode(Agg);
	_getPlan((Plan *) local_node);

684
	return local_node;
685 686 687
}

/* ----------------
688 689
 *		_readHash
 *
690
 *	Hash is a subclass of Plan
691 692
 * ----------------
 */
693
static Hash *
694
_readHash(void)
695
{
696 697 698
	Hash	   *local_node;
	char	   *token;
	int			length;
699 700 701 702 703

	local_node = makeNode(Hash);

	_getPlan((Plan *) local_node);

704
	token = pg_strtok(&length); /* eat :hashkey */
705
	local_node->hashkey = nodeRead(true);
706

707
	return local_node;
708 709 710
}

/*
711
 *	Stuff from primnodes.h.
712 713 714
 */

/* ----------------
715 716 717
 *		_readResdom
 *
 *	Resdom is a subclass of Node
718 719
 * ----------------
 */
720
static Resdom *
721
_readResdom(void)
722
{
723 724 725
	Resdom	   *local_node;
	char	   *token;
	int			length;
726 727 728

	local_node = makeNode(Resdom);

729 730
	token = pg_strtok(&length); /* eat :resno */
	token = pg_strtok(&length); /* get resno */
731 732
	local_node->resno = atoi(token);

733 734
	token = pg_strtok(&length); /* eat :restype */
	token = pg_strtok(&length); /* get restype */
735
	local_node->restype = atooid(token);
736

737 738
	token = pg_strtok(&length); /* eat :restypmod */
	token = pg_strtok(&length); /* get restypmod */
739
	local_node->restypmod = atoi(token);
740

741 742
	token = pg_strtok(&length); /* eat :resname */
	token = pg_strtok(&length); /* get the name */
743
	local_node->resname = nullable_string(token, length);
744

745 746
	token = pg_strtok(&length); /* eat :reskey */
	token = pg_strtok(&length); /* get reskey */
747
	local_node->reskey = atoui(token);
748

749 750
	token = pg_strtok(&length); /* eat :reskeyop */
	token = pg_strtok(&length); /* get reskeyop */
751
	local_node->reskeyop = atooid(token);
752

753 754
	token = pg_strtok(&length); /* eat :ressortgroupref */
	token = pg_strtok(&length); /* get ressortgroupref */
755
	local_node->ressortgroupref = atoui(token);
756

757 758
	token = pg_strtok(&length); /* eat :resjunk */
	token = pg_strtok(&length); /* get resjunk */
759
	local_node->resjunk = strtobool(token);
760

761
	return local_node;
762 763 764
}

/* ----------------
765 766 767
 *		_readExpr
 *
 *	Expr is a subclass of Node
768 769
 * ----------------
 */
770
static Expr *
771
_readExpr(void)
772
{
773 774 775
	Expr	   *local_node;
	char	   *token;
	int			length;
776 777 778

	local_node = makeNode(Expr);

779 780
	token = pg_strtok(&length); /* eat :typeOid */
	token = pg_strtok(&length); /* get typeOid */
781
	local_node->typeOid = atooid(token);
782

783 784
	token = pg_strtok(&length); /* eat :opType */
	token = pg_strtok(&length); /* get opType */
785
	if (strncmp(token, "op", 2) == 0)
786
		local_node->opType = OP_EXPR;
787
	else if (strncmp(token, "func", 4) == 0)
788
		local_node->opType = FUNC_EXPR;
789
	else if (strncmp(token, "or", 2) == 0)
790
		local_node->opType = OR_EXPR;
791
	else if (strncmp(token, "and", 3) == 0)
792
		local_node->opType = AND_EXPR;
793
	else if (strncmp(token, "not", 3) == 0)
794
		local_node->opType = NOT_EXPR;
795
	else if (strncmp(token, "subp", 4) == 0)
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
796
		local_node->opType = SUBPLAN_EXPR;
797
	else
798
		elog(ERROR, "_readExpr: unknown opType \"%.*s\"", length, token);
799

800
	token = pg_strtok(&length); /* eat :oper */
801 802
	local_node->oper = nodeRead(true);

803
	token = pg_strtok(&length); /* eat :args */
804 805
	local_node->args = nodeRead(true);	/* now read it */

806
	return local_node;
807 808
}

809 810 811 812 813 814 815
/* ----------------
 *		_readCaseExpr
 *
 *	CaseExpr is a subclass of Node
 * ----------------
 */
static CaseExpr *
816
_readCaseExpr(void)
817 818 819 820 821 822 823
{
	CaseExpr   *local_node;
	char	   *token;
	int			length;

	local_node = makeNode(CaseExpr);

824 825
	token = pg_strtok(&length); /* eat :casetype */
	token = pg_strtok(&length); /* get casetype */
826
	local_node->casetype = atooid(token);
827

828
	token = pg_strtok(&length); /* eat :arg */
829 830
	local_node->arg = nodeRead(true);

831
	token = pg_strtok(&length); /* eat :args */
832
	local_node->args = nodeRead(true);
833

834
	token = pg_strtok(&length); /* eat :defresult */
835 836 837 838 839 840 841 842 843 844 845 846
	local_node->defresult = nodeRead(true);

	return local_node;
}

/* ----------------
 *		_readCaseWhen
 *
 *	CaseWhen is a subclass of Node
 * ----------------
 */
static CaseWhen *
847
_readCaseWhen(void)
848 849 850 851 852 853 854 855
{
	CaseWhen   *local_node;
	char	   *token;
	int			length;

	local_node = makeNode(CaseWhen);

	local_node->expr = nodeRead(true);
856
	token = pg_strtok(&length); /* eat :then */
857 858 859 860 861
	local_node->result = nodeRead(true);

	return local_node;
}

862
/* ----------------
863 864 865
 *		_readVar
 *
 *	Var is a subclass of Expr
866 867
 * ----------------
 */
868
static Var *
869
_readVar(void)
870
{
871 872 873
	Var		   *local_node;
	char	   *token;
	int			length;
874 875 876

	local_node = makeNode(Var);

877 878
	token = pg_strtok(&length); /* eat :varno */
	token = pg_strtok(&length); /* get varno */
879
	local_node->varno = atoui(token);
880

881 882
	token = pg_strtok(&length); /* eat :varattno */
	token = pg_strtok(&length); /* get varattno */
883 884
	local_node->varattno = atoi(token);

885 886
	token = pg_strtok(&length); /* eat :vartype */
	token = pg_strtok(&length); /* get vartype */
887
	local_node->vartype = atooid(token);
888

889 890
	token = pg_strtok(&length); /* eat :vartypmod */
	token = pg_strtok(&length); /* get vartypmod */
Bruce Momjian's avatar
Bruce Momjian committed
891
	local_node->vartypmod = atoi(token);
892

893 894
	token = pg_strtok(&length); /* eat :varlevelsup */
	token = pg_strtok(&length); /* get varlevelsup */
895
	local_node->varlevelsup = atoui(token);
896

897 898
	token = pg_strtok(&length); /* eat :varnoold */
	token = pg_strtok(&length); /* get varnoold */
899
	local_node->varnoold = atoui(token);
900

901 902
	token = pg_strtok(&length); /* eat :varoattno */
	token = pg_strtok(&length); /* eat :varoattno */
903
	local_node->varoattno = atoi(token);
904

905
	return local_node;
906 907 908 909 910 911 912 913 914
}

/* ----------------
 * _readArrayRef
 *
 * ArrayRef is a subclass of Expr
 * ----------------
 */
static ArrayRef *
915
_readArrayRef(void)
916
{
917 918 919
	ArrayRef   *local_node;
	char	   *token;
	int			length;
920 921 922

	local_node = makeNode(ArrayRef);

923 924
	token = pg_strtok(&length); /* eat :refelemtype */
	token = pg_strtok(&length); /* get refelemtype */
925
	local_node->refelemtype = atooid(token);
926

927 928
	token = pg_strtok(&length); /* eat :refattrlength */
	token = pg_strtok(&length); /* get refattrlength */
929 930
	local_node->refattrlength = atoi(token);

931 932
	token = pg_strtok(&length); /* eat :refelemlength */
	token = pg_strtok(&length); /* get refelemlength */
933 934
	local_node->refelemlength = atoi(token);

935 936
	token = pg_strtok(&length); /* eat :refelembyval */
	token = pg_strtok(&length); /* get refelembyval */
937
	local_node->refelembyval = strtobool(token);
938

939
	token = pg_strtok(&length); /* eat :refupperindex */
940 941
	local_node->refupperindexpr = nodeRead(true);

942
	token = pg_strtok(&length); /* eat :reflowerindex */
943 944
	local_node->reflowerindexpr = nodeRead(true);

945
	token = pg_strtok(&length); /* eat :refexpr */
946 947
	local_node->refexpr = nodeRead(true);

948
	token = pg_strtok(&length); /* eat :refassgnexpr */
949 950
	local_node->refassgnexpr = nodeRead(true);

951
	return local_node;
952 953 954
}

/* ----------------
955 956 957
 *		_readConst
 *
 *	Const is a subclass of Expr
958 959
 * ----------------
 */
960
static Const *
961
_readConst(void)
962
{
963 964 965
	Const	   *local_node;
	char	   *token;
	int			length;
966 967 968

	local_node = makeNode(Const);

969 970
	token = pg_strtok(&length); /* get :consttype */
	token = pg_strtok(&length); /* now read it */
971
	local_node->consttype = atooid(token);
972

973 974
	token = pg_strtok(&length); /* get :constlen */
	token = pg_strtok(&length); /* now read it */
975
	local_node->constlen = atoi(token);
976

977 978
	token = pg_strtok(&length); /* get :constbyval */
	token = pg_strtok(&length); /* now read it */
979
	local_node->constbyval = strtobool(token);
980

981 982
	token = pg_strtok(&length); /* get :constisnull */
	token = pg_strtok(&length); /* now read it */
983
	local_node->constisnull = strtobool(token);
984

985
	token = pg_strtok(&length); /* get :constvalue */
986 987 988

	if (local_node->constisnull)
	{
989
		token = pg_strtok(&length);		/* skip "NIL" */
990 991
	}
	else
992
		local_node->constvalue = readDatum(local_node->constbyval);
993

994
	return local_node;
995 996 997
}

/* ----------------
998 999 1000
 *		_readFunc
 *
 *	Func is a subclass of Expr
1001 1002
 * ----------------
 */
1003
static Func *
1004
_readFunc(void)
1005
{
1006 1007 1008
	Func	   *local_node;
	char	   *token;
	int			length;
1009 1010 1011

	local_node = makeNode(Func);

1012 1013
	token = pg_strtok(&length); /* get :funcid */
	token = pg_strtok(&length); /* now read it */
1014
	local_node->funcid = atooid(token);
1015

1016 1017
	token = pg_strtok(&length); /* get :functype */
	token = pg_strtok(&length); /* now read it */
1018
	local_node->functype = atooid(token);
1019

1020
	local_node->func_fcache = NULL;
1021

1022
	return local_node;
1023 1024 1025
}

/* ----------------
1026 1027 1028
 *		_readOper
 *
 *	Oper is a subclass of Expr
1029 1030
 * ----------------
 */
1031
static Oper *
1032
_readOper(void)
1033
{
1034 1035 1036
	Oper	   *local_node;
	char	   *token;
	int			length;
1037 1038 1039

	local_node = makeNode(Oper);

1040 1041
	token = pg_strtok(&length); /* get :opno */
	token = pg_strtok(&length); /* now read it */
1042
	local_node->opno = atooid(token);
1043

1044 1045
	token = pg_strtok(&length); /* get :opid */
	token = pg_strtok(&length); /* now read it */
1046
	local_node->opid = atooid(token);
1047

1048 1049
	token = pg_strtok(&length); /* get :opresulttype */
	token = pg_strtok(&length); /* now read it */
1050
	local_node->opresulttype = atooid(token);
1051

1052
	local_node->op_fcache = NULL;
1053

1054
	return local_node;
1055 1056 1057
}

/* ----------------
1058 1059 1060
 *		_readParam
 *
 *	Param is a subclass of Expr
1061 1062
 * ----------------
 */
1063
static Param *
1064
_readParam(void)
1065
{
1066 1067 1068
	Param	   *local_node;
	char	   *token;
	int			length;
1069 1070 1071

	local_node = makeNode(Param);

1072 1073
	token = pg_strtok(&length); /* get :paramkind */
	token = pg_strtok(&length); /* now read it */
1074 1075
	local_node->paramkind = atoi(token);

1076 1077
	token = pg_strtok(&length); /* get :paramid */
	token = pg_strtok(&length); /* now read it */
1078
	local_node->paramid = atoi(token);
1079

1080 1081
	token = pg_strtok(&length); /* get :paramname */
	token = pg_strtok(&length); /* now read it */
1082
	local_node->paramname = nullable_string(token, length);
1083

1084 1085
	token = pg_strtok(&length); /* get :paramtype */
	token = pg_strtok(&length); /* now read it */
1086
	local_node->paramtype = atooid(token);
1087

1088
	return local_node;
1089 1090
}

1091
/* ----------------
Bruce Momjian's avatar
Bruce Momjian committed
1092
 *		_readAggref
1093
 *
Bruce Momjian's avatar
Bruce Momjian committed
1094
 *	Aggref is a subclass of Node
1095 1096
 * ----------------
 */
Bruce Momjian's avatar
Bruce Momjian committed
1097
static Aggref *
1098
_readAggref(void)
1099
{
Bruce Momjian's avatar
Bruce Momjian committed
1100
	Aggref	   *local_node;
1101 1102
	char	   *token;
	int			length;
1103

Bruce Momjian's avatar
Bruce Momjian committed
1104
	local_node = makeNode(Aggref);
1105

1106 1107
	token = pg_strtok(&length); /* eat :aggname */
	token = pg_strtok(&length); /* get aggname */
1108
	local_node->aggname = debackslash(token, length);
1109

1110 1111
	token = pg_strtok(&length); /* eat :basetype */
	token = pg_strtok(&length); /* get basetype */
1112
	local_node->basetype = atooid(token);
1113

1114 1115
	token = pg_strtok(&length); /* eat :aggtype */
	token = pg_strtok(&length); /* get aggtype */
1116
	local_node->aggtype = atooid(token);
1117

1118
	token = pg_strtok(&length); /* eat :target */
1119 1120
	local_node->target = nodeRead(true);		/* now read it */

1121 1122
	token = pg_strtok(&length); /* eat :aggstar */
	token = pg_strtok(&length); /* get aggstar */
1123
	local_node->aggstar = strtobool(token);
1124

1125 1126
	token = pg_strtok(&length); /* eat :aggdistinct */
	token = pg_strtok(&length); /* get aggdistinct */
1127
	local_node->aggdistinct = strtobool(token);
1128

1129
	return local_node;
1130 1131
}

1132 1133 1134 1135 1136 1137 1138
/* ----------------
 *		_readSubLink
 *
 *	SubLink is a subclass of Node
 * ----------------
 */
static SubLink *
1139
_readSubLink(void)
1140
{
1141
	SubLink    *local_node;
1142 1143 1144 1145 1146
	char	   *token;
	int			length;

	local_node = makeNode(SubLink);

1147 1148
	token = pg_strtok(&length); /* eat :subLinkType */
	token = pg_strtok(&length); /* get subLinkType */
1149 1150
	local_node->subLinkType = atoi(token);

1151 1152
	token = pg_strtok(&length); /* eat :useor */
	token = pg_strtok(&length); /* get useor */
1153
	local_node->useor = strtobool(token);
1154

1155
	token = pg_strtok(&length); /* eat :lefthand */
1156 1157
	local_node->lefthand = nodeRead(true);		/* now read it */

1158
	token = pg_strtok(&length); /* eat :oper */
1159
	local_node->oper = nodeRead(true);	/* now read it */
1160

1161
	token = pg_strtok(&length); /* eat :subselect */
1162 1163
	local_node->subselect = nodeRead(true);		/* now read it */

1164
	return local_node;
1165 1166
}

1167 1168 1169 1170 1171 1172 1173
/* ----------------
 *		_readFieldSelect
 *
 *	FieldSelect is a subclass of Node
 * ----------------
 */
static FieldSelect *
1174
_readFieldSelect(void)
1175 1176 1177 1178 1179 1180 1181
{
	FieldSelect *local_node;
	char	   *token;
	int			length;

	local_node = makeNode(FieldSelect);

1182
	token = pg_strtok(&length); /* eat :arg */
1183 1184
	local_node->arg = nodeRead(true);	/* now read it */

1185 1186
	token = pg_strtok(&length); /* eat :fieldnum */
	token = pg_strtok(&length); /* get fieldnum */
1187 1188
	local_node->fieldnum = (AttrNumber) atoi(token);

1189 1190
	token = pg_strtok(&length); /* eat :resulttype */
	token = pg_strtok(&length); /* get resulttype */
1191
	local_node->resulttype = atooid(token);
1192

1193 1194
	token = pg_strtok(&length); /* eat :resulttypmod */
	token = pg_strtok(&length); /* get resulttypmod */
1195 1196 1197 1198 1199
	local_node->resulttypmod = atoi(token);

	return local_node;
}

1200 1201 1202 1203 1204 1205 1206
/* ----------------
 *		_readRelabelType
 *
 *	RelabelType is a subclass of Node
 * ----------------
 */
static RelabelType *
1207
_readRelabelType(void)
1208 1209 1210 1211 1212 1213 1214
{
	RelabelType *local_node;
	char	   *token;
	int			length;

	local_node = makeNode(RelabelType);

1215
	token = pg_strtok(&length); /* eat :arg */
1216 1217
	local_node->arg = nodeRead(true);	/* now read it */

1218 1219
	token = pg_strtok(&length); /* eat :resulttype */
	token = pg_strtok(&length); /* get resulttype */
1220
	local_node->resulttype = atooid(token);
1221

1222 1223
	token = pg_strtok(&length); /* eat :resulttypmod */
	token = pg_strtok(&length); /* get resulttypmod */
1224 1225 1226 1227 1228
	local_node->resulttypmod = atoi(token);

	return local_node;
}

1229 1230 1231 1232 1233 1234 1235
/* ----------------
 *		_readRangeTblRef
 *
 *	RangeTblRef is a subclass of Node
 * ----------------
 */
static RangeTblRef *
1236
_readRangeTblRef(void)
1237 1238 1239 1240 1241 1242 1243
{
	RangeTblRef *local_node;
	char	   *token;
	int			length;

	local_node = makeNode(RangeTblRef);

1244
	token = pg_strtok(&length); /* get rtindex */
1245 1246 1247 1248 1249
	local_node->rtindex = atoi(token);

	return local_node;
}

1250 1251 1252 1253 1254 1255 1256
/* ----------------
 *		_readFromExpr
 *
 *	FromExpr is a subclass of Node
 * ----------------
 */
static FromExpr *
1257
_readFromExpr(void)
1258 1259 1260 1261 1262 1263 1264
{
	FromExpr   *local_node;
	char	   *token;
	int			length;

	local_node = makeNode(FromExpr);

1265 1266
	token = pg_strtok(&length); /* eat :fromlist */
	local_node->fromlist = nodeRead(true);		/* now read it */
1267

1268 1269
	token = pg_strtok(&length); /* eat :quals */
	local_node->quals = nodeRead(true); /* now read it */
1270 1271 1272 1273

	return local_node;
}

1274 1275 1276 1277 1278 1279 1280
/* ----------------
 *		_readJoinExpr
 *
 *	JoinExpr is a subclass of Node
 * ----------------
 */
static JoinExpr *
1281
_readJoinExpr(void)
1282 1283 1284 1285 1286 1287 1288
{
	JoinExpr   *local_node;
	char	   *token;
	int			length;

	local_node = makeNode(JoinExpr);

1289 1290
	token = pg_strtok(&length); /* eat :jointype */
	token = pg_strtok(&length); /* get jointype */
1291 1292
	local_node->jointype = (JoinType) atoi(token);

1293 1294
	token = pg_strtok(&length); /* eat :isNatural */
	token = pg_strtok(&length); /* get :isNatural */
1295
	local_node->isNatural = strtobool(token);
1296

1297
	token = pg_strtok(&length); /* eat :larg */
1298 1299
	local_node->larg = nodeRead(true);	/* now read it */

1300
	token = pg_strtok(&length); /* eat :rarg */
1301 1302
	local_node->rarg = nodeRead(true);	/* now read it */

1303 1304
	token = pg_strtok(&length); /* eat :using */
	local_node->using = nodeRead(true); /* now read it */
1305

1306 1307
	token = pg_strtok(&length); /* eat :quals */
	local_node->quals = nodeRead(true); /* now read it */
1308

1309 1310
	token = pg_strtok(&length); /* eat :alias */
	local_node->alias = nodeRead(true); /* now read it */
1311

1312 1313
	token = pg_strtok(&length); /* eat :colnames */
	local_node->colnames = nodeRead(true);		/* now read it */
1314

1315 1316
	token = pg_strtok(&length); /* eat :colvars */
	local_node->colvars = nodeRead(true);		/* now read it */
1317 1318 1319 1320

	return local_node;
}

1321
/*
1322
 *	Stuff from relation.h
1323 1324 1325
 */

/* ----------------
1326
 *		_readRelOptInfo
1327 1328
 * ----------------
 */
Bruce Momjian's avatar
Bruce Momjian committed
1329
static RelOptInfo *
1330
_readRelOptInfo(void)
1331
{
1332
	RelOptInfo *local_node;
1333 1334
	char	   *token;
	int			length;
1335

Bruce Momjian's avatar
Bruce Momjian committed
1336
	local_node = makeNode(RelOptInfo);
1337

1338
	token = pg_strtok(&length); /* get :relids */
1339
	local_node->relids = toIntList(nodeRead(true));		/* now read it */
1340

1341 1342
	token = pg_strtok(&length); /* get :rows */
	token = pg_strtok(&length); /* now read it */
1343 1344
	local_node->rows = atof(token);

1345 1346
	token = pg_strtok(&length); /* get :width */
	token = pg_strtok(&length); /* now read it */
1347 1348
	local_node->width = atoi(token);

1349
	token = pg_strtok(&length); /* get :targetlist */
1350 1351
	local_node->targetlist = nodeRead(true);	/* now read it */

1352
	token = pg_strtok(&length); /* get :pathlist */
1353 1354
	local_node->pathlist = nodeRead(true);		/* now read it */

1355
	token = pg_strtok(&length); /* get :cheapest_startup_path */
1356
	local_node->cheapest_startup_path = nodeRead(true); /* now read it */
1357

1358
	token = pg_strtok(&length); /* get :cheapest_total_path */
1359
	local_node->cheapest_total_path = nodeRead(true);	/* now read it */
1360

1361 1362
	token = pg_strtok(&length); /* eat :pruneable */
	token = pg_strtok(&length); /* get :pruneable */
1363
	local_node->pruneable = strtobool(token);
1364

1365 1366
	token = pg_strtok(&length); /* get :issubquery */
	token = pg_strtok(&length); /* now read it */
1367
	local_node->issubquery = strtobool(token);
1368

1369 1370
	token = pg_strtok(&length); /* get :indexed */
	token = pg_strtok(&length); /* now read it */
1371
	local_node->indexed = strtobool(token);
1372

1373 1374
	token = pg_strtok(&length); /* get :pages */
	token = pg_strtok(&length); /* now read it */
1375 1376
	local_node->pages = atol(token);

1377 1378
	token = pg_strtok(&length); /* get :tuples */
	token = pg_strtok(&length); /* now read it */
1379 1380
	local_node->tuples = atof(token);

1381 1382
	token = pg_strtok(&length); /* get :subplan */
	local_node->subplan = nodeRead(true);		/* now read it */
1383

1384 1385
	token = pg_strtok(&length); /* get :baserestrictinfo */
	local_node->baserestrictinfo = nodeRead(true);		/* now read it */
1386

1387 1388
	token = pg_strtok(&length); /* get :baserestrictcost */
	token = pg_strtok(&length); /* now read it */
1389 1390
	local_node->baserestrictcost = (Cost) atof(token);

1391 1392
	token = pg_strtok(&length); /* get :outerjoinset */
	local_node->outerjoinset = toIntList(nodeRead(true));		/* now read it */
1393

1394
	token = pg_strtok(&length); /* get :joininfo */
1395 1396
	local_node->joininfo = nodeRead(true);		/* now read it */

1397
	token = pg_strtok(&length); /* get :innerjoin */
1398 1399
	local_node->innerjoin = nodeRead(true);		/* now read it */

1400
	return local_node;
1401 1402 1403
}

/* ----------------
1404
 *		_readTargetEntry
1405 1406 1407
 * ----------------
 */
static TargetEntry *
1408
_readTargetEntry(void)
1409
{
1410 1411 1412
	TargetEntry *local_node;
	char	   *token;
	int			length;
1413

1414
	local_node = makeNode(TargetEntry);
1415

1416
	token = pg_strtok(&length); /* get :resdom */
1417
	local_node->resdom = nodeRead(true);		/* now read it */
1418

1419
	token = pg_strtok(&length); /* get :expr */
1420
	local_node->expr = nodeRead(true);	/* now read it */
1421

1422
	return local_node;
1423 1424
}

1425
static Attr *
1426
_readAttr(void)
1427 1428 1429 1430 1431 1432 1433
{
	Attr	   *local_node;
	char	   *token;
	int			length;

	local_node = makeNode(Attr);

1434 1435
	token = pg_strtok(&length); /* eat :relname */
	token = pg_strtok(&length); /* get relname */
1436
	local_node->relname = debackslash(token, length);
1437

1438
	token = pg_strtok(&length); /* eat :attrs */
1439
	local_node->attrs = nodeRead(true); /* now read it */
1440 1441 1442 1443

	return local_node;
}

1444
/* ----------------
1445
 *		_readRangeTblEntry
1446 1447 1448
 * ----------------
 */
static RangeTblEntry *
1449
_readRangeTblEntry(void)
1450
{
1451 1452 1453
	RangeTblEntry *local_node;
	char	   *token;
	int			length;
1454

1455
	local_node = makeNode(RangeTblEntry);
1456

1457 1458
	token = pg_strtok(&length); /* eat :relname */
	token = pg_strtok(&length); /* get :relname */
1459
	local_node->relname = nullable_string(token, length);
1460

1461 1462
	token = pg_strtok(&length); /* eat :relid */
	token = pg_strtok(&length); /* get :relid */
1463
	local_node->relid = atooid(token);
1464

1465 1466
	token = pg_strtok(&length); /* eat :subquery */
	local_node->subquery = nodeRead(true);		/* now read it */
1467

1468 1469
	token = pg_strtok(&length); /* eat :alias */
	local_node->alias = nodeRead(true); /* now read it */
1470

1471
	token = pg_strtok(&length); /* eat :eref */
1472 1473
	local_node->eref = nodeRead(true);	/* now read it */

1474 1475
	token = pg_strtok(&length); /* eat :inh */
	token = pg_strtok(&length); /* get :inh */
1476
	local_node->inh = strtobool(token);
1477

1478 1479
	token = pg_strtok(&length); /* eat :inFromCl */
	token = pg_strtok(&length); /* get :inFromCl */
1480
	local_node->inFromCl = strtobool(token);
1481

1482 1483
	token = pg_strtok(&length); /* eat :checkForRead */
	token = pg_strtok(&length); /* get :checkForRead */
1484
	local_node->checkForRead = strtobool(token);
1485

1486 1487
	token = pg_strtok(&length); /* eat :checkForWrite */
	token = pg_strtok(&length); /* get :checkForWrite */
1488
	local_node->checkForWrite = strtobool(token);
1489

1490 1491
	token = pg_strtok(&length); /* eat :checkAsUser */
	token = pg_strtok(&length); /* get :checkAsUser */
1492
	local_node->checkAsUser = atooid(token);
1493 1494 1495 1496

	return local_node;
}

1497
/* ----------------
1498 1499 1500
 *		_readPath
 *
 *	Path is a subclass of Node.
1501 1502
 * ----------------
 */
1503
static Path *
1504
_readPath(void)
1505
{
1506 1507 1508
	Path	   *local_node;
	char	   *token;
	int			length;
1509 1510 1511

	local_node = makeNode(Path);

1512 1513
	token = pg_strtok(&length); /* get :pathtype */
	token = pg_strtok(&length); /* now read it */
1514
	local_node->pathtype = atoi(token);
1515

1516 1517
	token = pg_strtok(&length); /* get :startup_cost */
	token = pg_strtok(&length); /* now read it */
1518 1519
	local_node->startup_cost = (Cost) atof(token);

1520 1521
	token = pg_strtok(&length); /* get :total_cost */
	token = pg_strtok(&length); /* now read it */
1522
	local_node->total_cost = (Cost) atof(token);
1523

1524
	token = pg_strtok(&length); /* get :pathkeys */
Bruce Momjian's avatar
Bruce Momjian committed
1525
	local_node->pathkeys = nodeRead(true);		/* now read it */
1526

1527
	return local_node;
1528 1529 1530
}

/* ----------------
1531 1532 1533
 *		_readIndexPath
 *
 *	IndexPath is a subclass of Path.
1534 1535 1536
 * ----------------
 */
static IndexPath *
1537
_readIndexPath(void)
1538
{
1539 1540 1541
	IndexPath  *local_node;
	char	   *token;
	int			length;
1542 1543 1544

	local_node = makeNode(IndexPath);

1545 1546
	token = pg_strtok(&length); /* get :pathtype */
	token = pg_strtok(&length); /* now read it */
1547
	local_node->path.pathtype = atoi(token);
1548

1549 1550
	token = pg_strtok(&length); /* get :startup_cost */
	token = pg_strtok(&length); /* now read it */
1551 1552
	local_node->path.startup_cost = (Cost) atof(token);

1553 1554
	token = pg_strtok(&length); /* get :total_cost */
	token = pg_strtok(&length); /* now read it */
1555
	local_node->path.total_cost = (Cost) atof(token);
1556

1557
	token = pg_strtok(&length); /* get :pathkeys */
Bruce Momjian's avatar
Bruce Momjian committed
1558
	local_node->path.pathkeys = nodeRead(true); /* now read it */
1559

1560
	token = pg_strtok(&length); /* get :indexid */
1561
	local_node->indexid = toOidList(nodeRead(true));
1562

1563
	token = pg_strtok(&length); /* get :indexqual */
1564 1565
	local_node->indexqual = nodeRead(true);		/* now read it */

1566 1567
	token = pg_strtok(&length); /* get :indexscandir */
	token = pg_strtok(&length); /* now read it */
1568 1569
	local_node->indexscandir = (ScanDirection) atoi(token);

1570
	token = pg_strtok(&length); /* get :joinrelids */
1571 1572
	local_node->joinrelids = toIntList(nodeRead(true));

1573 1574
	token = pg_strtok(&length); /* get :alljoinquals */
	token = pg_strtok(&length); /* now read it */
1575
	local_node->alljoinquals = strtobool(token);
1576

1577 1578
	token = pg_strtok(&length); /* get :rows */
	token = pg_strtok(&length); /* now read it */
1579 1580
	local_node->rows = atof(token);

1581
	return local_node;
1582 1583
}

1584 1585 1586 1587 1588 1589 1590
/* ----------------
 *		_readTidPath
 *
 *	TidPath is a subclass of Path.
 * ----------------
 */
static TidPath *
1591
_readTidPath(void)
1592
{
1593
	TidPath    *local_node;
1594 1595 1596 1597 1598
	char	   *token;
	int			length;

	local_node = makeNode(TidPath);

1599 1600
	token = pg_strtok(&length); /* get :pathtype */
	token = pg_strtok(&length); /* now read it */
1601
	local_node->path.pathtype = atoi(token);
1602

1603 1604
	token = pg_strtok(&length); /* get :startup_cost */
	token = pg_strtok(&length); /* now read it */
1605 1606
	local_node->path.startup_cost = (Cost) atof(token);

1607 1608
	token = pg_strtok(&length); /* get :total_cost */
	token = pg_strtok(&length); /* now read it */
1609
	local_node->path.total_cost = (Cost) atof(token);
1610

1611
	token = pg_strtok(&length); /* get :pathkeys */
1612 1613
	local_node->path.pathkeys = nodeRead(true); /* now read it */

1614
	token = pg_strtok(&length); /* get :tideval */
1615
	local_node->tideval = nodeRead(true);		/* now read it */
1616

1617
	token = pg_strtok(&length); /* get :unjoined_relids */
1618 1619 1620 1621 1622
	local_node->unjoined_relids = toIntList(nodeRead(true));

	return local_node;
}

1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637
/* ----------------
 *		_readAppendPath
 *
 *	AppendPath is a subclass of Path.
 * ----------------
 */
static AppendPath *
_readAppendPath(void)
{
	AppendPath *local_node;
	char	   *token;
	int			length;

	local_node = makeNode(AppendPath);

1638 1639
	token = pg_strtok(&length); /* get :pathtype */
	token = pg_strtok(&length); /* now read it */
1640
	local_node->path.pathtype = atoi(token);
1641

1642 1643
	token = pg_strtok(&length); /* get :startup_cost */
	token = pg_strtok(&length); /* now read it */
1644 1645
	local_node->path.startup_cost = (Cost) atof(token);

1646 1647
	token = pg_strtok(&length); /* get :total_cost */
	token = pg_strtok(&length); /* now read it */
1648 1649
	local_node->path.total_cost = (Cost) atof(token);

1650
	token = pg_strtok(&length); /* get :pathkeys */
1651 1652
	local_node->path.pathkeys = nodeRead(true); /* now read it */

1653
	token = pg_strtok(&length); /* get :subpaths */
1654 1655 1656 1657 1658
	local_node->subpaths = nodeRead(true);		/* now read it */

	return local_node;
}

1659
/* ----------------
1660
 *		_readNestPath
1661
 *
1662
 *	NestPath is a subclass of Path
1663 1664
 * ----------------
 */
1665
static NestPath *
1666
_readNestPath(void)
1667
{
1668
	NestPath   *local_node;
1669 1670
	char	   *token;
	int			length;
1671

1672
	local_node = makeNode(NestPath);
1673

1674 1675
	token = pg_strtok(&length); /* get :pathtype */
	token = pg_strtok(&length); /* now read it */
1676
	local_node->path.pathtype = atoi(token);
1677

1678 1679
	token = pg_strtok(&length); /* get :startup_cost */
	token = pg_strtok(&length); /* now read it */
1680 1681
	local_node->path.startup_cost = (Cost) atof(token);

1682 1683
	token = pg_strtok(&length); /* get :total_cost */
	token = pg_strtok(&length); /* now read it */
1684
	local_node->path.total_cost = (Cost) atof(token);
1685

1686
	token = pg_strtok(&length); /* get :pathkeys */
Bruce Momjian's avatar
Bruce Momjian committed
1687
	local_node->path.pathkeys = nodeRead(true); /* now read it */
1688

1689 1690
	token = pg_strtok(&length); /* get :jointype */
	token = pg_strtok(&length); /* now read it */
1691 1692
	local_node->jointype = (JoinType) atoi(token);

1693
	token = pg_strtok(&length); /* get :outerjoinpath */
1694
	local_node->outerjoinpath = nodeRead(true); /* now read it */
1695

1696
	token = pg_strtok(&length); /* get :innerjoinpath */
1697
	local_node->innerjoinpath = nodeRead(true); /* now read it */
1698

1699 1700
	token = pg_strtok(&length); /* get :joinrestrictinfo */
	local_node->joinrestrictinfo = nodeRead(true);		/* now read it */
1701

1702
	return local_node;
1703 1704 1705
}

/* ----------------
1706 1707
 *		_readMergePath
 *
1708
 *	MergePath is a subclass of NestPath.
1709 1710 1711
 * ----------------
 */
static MergePath *
1712
_readMergePath(void)
1713
{
1714 1715 1716
	MergePath  *local_node;
	char	   *token;
	int			length;
1717 1718 1719

	local_node = makeNode(MergePath);

1720 1721
	token = pg_strtok(&length); /* get :pathtype */
	token = pg_strtok(&length); /* now read it */
1722
	local_node->jpath.path.pathtype = atoi(token);
1723

1724 1725
	token = pg_strtok(&length); /* get :startup_cost */
	token = pg_strtok(&length); /* now read it */
1726
	local_node->jpath.path.startup_cost = (Cost) atof(token);
1727

1728 1729
	token = pg_strtok(&length); /* get :total_cost */
	token = pg_strtok(&length); /* now read it */
1730
	local_node->jpath.path.total_cost = (Cost) atof(token);
1731

1732
	token = pg_strtok(&length); /* get :pathkeys */
Bruce Momjian's avatar
Bruce Momjian committed
1733
	local_node->jpath.path.pathkeys = nodeRead(true);	/* now read it */
1734

1735 1736
	token = pg_strtok(&length); /* get :jointype */
	token = pg_strtok(&length); /* now read it */
1737 1738
	local_node->jpath.jointype = (JoinType) atoi(token);

1739
	token = pg_strtok(&length); /* get :outerjoinpath */
1740
	local_node->jpath.outerjoinpath = nodeRead(true);	/* now read it */
1741

1742
	token = pg_strtok(&length); /* get :innerjoinpath */
1743
	local_node->jpath.innerjoinpath = nodeRead(true);	/* now read it */
1744

1745 1746
	token = pg_strtok(&length); /* get :joinrestrictinfo */
	local_node->jpath.joinrestrictinfo = nodeRead(true);		/* now read it */
1747

1748
	token = pg_strtok(&length); /* get :path_mergeclauses */
1749 1750
	local_node->path_mergeclauses = nodeRead(true);		/* now read it */

1751
	token = pg_strtok(&length); /* get :outersortkeys */
1752 1753
	local_node->outersortkeys = nodeRead(true); /* now read it */

1754
	token = pg_strtok(&length); /* get :innersortkeys */
1755 1756
	local_node->innersortkeys = nodeRead(true); /* now read it */

1757
	return local_node;
1758 1759 1760
}

/* ----------------
1761 1762
 *		_readHashPath
 *
1763
 *	HashPath is a subclass of NestPath.
1764 1765 1766
 * ----------------
 */
static HashPath *
1767
_readHashPath(void)
1768
{
1769 1770 1771
	HashPath   *local_node;
	char	   *token;
	int			length;
1772 1773 1774

	local_node = makeNode(HashPath);

1775 1776
	token = pg_strtok(&length); /* get :pathtype */
	token = pg_strtok(&length); /* now read it */
1777
	local_node->jpath.path.pathtype = atoi(token);
1778

1779 1780
	token = pg_strtok(&length); /* get :startup_cost */
	token = pg_strtok(&length); /* now read it */
1781
	local_node->jpath.path.startup_cost = (Cost) atof(token);
1782

1783 1784
	token = pg_strtok(&length); /* get :total_cost */
	token = pg_strtok(&length); /* now read it */
1785
	local_node->jpath.path.total_cost = (Cost) atof(token);
1786

1787
	token = pg_strtok(&length); /* get :pathkeys */
Bruce Momjian's avatar
Bruce Momjian committed
1788
	local_node->jpath.path.pathkeys = nodeRead(true);	/* now read it */
1789

1790 1791
	token = pg_strtok(&length); /* get :jointype */
	token = pg_strtok(&length); /* now read it */
1792 1793
	local_node->jpath.jointype = (JoinType) atoi(token);

1794
	token = pg_strtok(&length); /* get :outerjoinpath */
1795
	local_node->jpath.outerjoinpath = nodeRead(true);	/* now read it */
1796

1797
	token = pg_strtok(&length); /* get :innerjoinpath */
1798
	local_node->jpath.innerjoinpath = nodeRead(true);	/* now read it */
1799

1800 1801
	token = pg_strtok(&length); /* get :joinrestrictinfo */
	local_node->jpath.joinrestrictinfo = nodeRead(true);		/* now read it */
1802

1803
	token = pg_strtok(&length); /* get :path_hashclauses */
1804 1805
	local_node->path_hashclauses = nodeRead(true);		/* now read it */

1806
	return local_node;
1807 1808 1809
}

/* ----------------
1810
 *		_readPathKeyItem
1811
 *
1812
 *	PathKeyItem is a subclass of Node.
1813 1814
 * ----------------
 */
1815
static PathKeyItem *
1816
_readPathKeyItem(void)
1817
{
1818
	PathKeyItem *local_node;
1819 1820
	char	   *token;
	int			length;
1821

1822
	local_node = makeNode(PathKeyItem);
1823

1824 1825
	token = pg_strtok(&length); /* get :sortop */
	token = pg_strtok(&length); /* now read it */
1826
	local_node->sortop = atooid(token);
1827

1828
	token = pg_strtok(&length); /* get :key */
1829
	local_node->key = nodeRead(true);	/* now read it */
1830

1831
	return local_node;
1832 1833 1834
}

/* ----------------
1835
 *		_readRestrictInfo
1836
 *
1837
 *	RestrictInfo is a subclass of Node.
1838 1839
 * ----------------
 */
1840
static RestrictInfo *
1841
_readRestrictInfo(void)
1842
{
1843
	RestrictInfo *local_node;
1844 1845
	char	   *token;
	int			length;
1846

1847
	local_node = makeNode(RestrictInfo);
1848

1849
	token = pg_strtok(&length); /* get :clause */
1850 1851
	local_node->clause = nodeRead(true);		/* now read it */

1852 1853
	token = pg_strtok(&length); /* get :ispusheddown */
	token = pg_strtok(&length); /* now read it */
1854
	local_node->ispusheddown = strtobool(token);
1855

1856
	token = pg_strtok(&length); /* get :subclauseindices */
1857
	local_node->subclauseindices = nodeRead(true);		/* now read it */
1858

1859 1860
	token = pg_strtok(&length); /* get :mergejoinoperator */
	token = pg_strtok(&length); /* now read it */
1861
	local_node->mergejoinoperator = atooid(token);
1862

1863 1864
	token = pg_strtok(&length); /* get :left_sortop */
	token = pg_strtok(&length); /* now read it */
1865
	local_node->left_sortop = atooid(token);
1866

1867 1868
	token = pg_strtok(&length); /* get :right_sortop */
	token = pg_strtok(&length); /* now read it */
1869
	local_node->right_sortop = atooid(token);
1870

1871 1872
	token = pg_strtok(&length); /* get :hashjoinoperator */
	token = pg_strtok(&length); /* now read it */
1873
	local_node->hashjoinoperator = atooid(token);
1874

1875 1876
	/* eval_cost is not part of saved representation; compute on first use */
	local_node->eval_cost = -1;
1877
	/* ditto for cached pathkeys and bucketsize */
1878 1879
	local_node->left_pathkey = NIL;
	local_node->right_pathkey = NIL;
1880 1881
	local_node->left_bucketsize = -1;
	local_node->right_bucketsize = -1;
1882

1883
	return local_node;
1884 1885 1886
}

/* ----------------
1887
 *		_readJoinInfo()
1888
 *
1889
 *	JoinInfo is a subclass of Node.
1890 1891
 * ----------------
 */
1892
static JoinInfo *
1893
_readJoinInfo(void)
1894
{
1895
	JoinInfo   *local_node;
1896 1897
	char	   *token;
	int			length;
1898

1899
	local_node = makeNode(JoinInfo);
1900

1901
	token = pg_strtok(&length); /* get :unjoined_relids */
Bruce Momjian's avatar
Bruce Momjian committed
1902
	local_node->unjoined_relids = toIntList(nodeRead(true));	/* now read it */
1903

1904
	token = pg_strtok(&length); /* get :jinfo_restrictinfo */
Bruce Momjian's avatar
Bruce Momjian committed
1905
	local_node->jinfo_restrictinfo = nodeRead(true);	/* now read it */
1906

1907
	return local_node;
1908 1909 1910
}

/* ----------------
1911
 *		_readIter()
1912 1913 1914
 *
 * ----------------
 */
1915
static Iter *
1916
_readIter(void)
1917
{
1918 1919 1920
	Iter	   *local_node;
	char	   *token;
	int			length;
1921 1922 1923

	local_node = makeNode(Iter);

1924
	token = pg_strtok(&length); /* eat :iterexpr */
1925 1926
	local_node->iterexpr = nodeRead(true);		/* now read it */

1927
	return local_node;
1928 1929 1930 1931
}


/* ----------------
1932
 *		parsePlanString
1933 1934 1935 1936
 *
 * Given a character string containing a plan, parsePlanString sets up the
 * plan structure representing that plan.
 *
1937
 * The string to be read must already have been loaded into pg_strtok().
1938 1939
 * ----------------
 */
1940
Node *
1941
parsePlanString(void)
1942
{
1943 1944 1945
	char	   *token;
	int			length;
	void	   *return_value = NULL;
1946

1947
	token = pg_strtok(&length);
1948

1949
	if (length == 4 && strncmp(token, "PLAN", length) == 0)
1950
		return_value = _readPlan();
1951
	else if (length == 6 && strncmp(token, "RESULT", length) == 0)
1952
		return_value = _readResult();
1953
	else if (length == 6 && strncmp(token, "APPEND", length) == 0)
1954
		return_value = _readAppend();
1955
	else if (length == 4 && strncmp(token, "JOIN", length) == 0)
1956
		return_value = _readJoin();
1957
	else if (length == 8 && strncmp(token, "NESTLOOP", length) == 0)
1958
		return_value = _readNestLoop();
1959
	else if (length == 9 && strncmp(token, "MERGEJOIN", length) == 0)
1960
		return_value = _readMergeJoin();
1961
	else if (length == 8 && strncmp(token, "HASHJOIN", length) == 0)
1962
		return_value = _readHashJoin();
1963
	else if (length == 4 && strncmp(token, "SCAN", length) == 0)
1964
		return_value = _readScan();
1965
	else if (length == 7 && strncmp(token, "SEQSCAN", length) == 0)
1966
		return_value = _readSeqScan();
1967
	else if (length == 9 && strncmp(token, "INDEXSCAN", length) == 0)
1968
		return_value = _readIndexScan();
1969
	else if (length == 7 && strncmp(token, "TIDSCAN", length) == 0)
1970
		return_value = _readTidScan();
1971 1972
	else if (length == 12 && strncmp(token, "SUBQUERYSCAN", length) == 0)
		return_value = _readSubqueryScan();
1973
	else if (length == 4 && strncmp(token, "SORT", length) == 0)
1974
		return_value = _readSort();
1975
	else if (length == 6 && strncmp(token, "AGGREG", length) == 0)
Bruce Momjian's avatar
Bruce Momjian committed
1976
		return_value = _readAggref();
1977
	else if (length == 7 && strncmp(token, "SUBLINK", length) == 0)
1978
		return_value = _readSubLink();
1979 1980
	else if (length == 11 && strncmp(token, "FIELDSELECT", length) == 0)
		return_value = _readFieldSelect();
1981 1982
	else if (length == 11 && strncmp(token, "RELABELTYPE", length) == 0)
		return_value = _readRelabelType();
1983 1984
	else if (length == 11 && strncmp(token, "RANGETBLREF", length) == 0)
		return_value = _readRangeTblRef();
1985 1986
	else if (length == 8 && strncmp(token, "FROMEXPR", length) == 0)
		return_value = _readFromExpr();
1987 1988
	else if (length == 8 && strncmp(token, "JOINEXPR", length) == 0)
		return_value = _readJoinExpr();
1989
	else if (length == 3 && strncmp(token, "AGG", length) == 0)
1990
		return_value = _readAgg();
1991
	else if (length == 4 && strncmp(token, "HASH", length) == 0)
1992
		return_value = _readHash();
1993
	else if (length == 6 && strncmp(token, "RESDOM", length) == 0)
1994
		return_value = _readResdom();
1995
	else if (length == 4 && strncmp(token, "EXPR", length) == 0)
1996
		return_value = _readExpr();
1997
	else if (length == 8 && strncmp(token, "ARRAYREF", length) == 0)
1998
		return_value = _readArrayRef();
1999
	else if (length == 3 && strncmp(token, "VAR", length) == 0)
2000
		return_value = _readVar();
2001 2002
	else if (length == 4 && strncmp(token, "ATTR", length) == 0)
		return_value = _readAttr();
2003
	else if (length == 5 && strncmp(token, "CONST", length) == 0)
2004
		return_value = _readConst();
2005
	else if (length == 4 && strncmp(token, "FUNC", length) == 0)
2006
		return_value = _readFunc();
2007
	else if (length == 4 && strncmp(token, "OPER", length) == 0)
2008
		return_value = _readOper();
2009
	else if (length == 5 && strncmp(token, "PARAM", length) == 0)
2010
		return_value = _readParam();
2011
	else if (length == 10 && strncmp(token, "RELOPTINFO", length) == 0)
2012
		return_value = _readRelOptInfo();
2013
	else if (length == 11 && strncmp(token, "TARGETENTRY", length) == 0)
2014
		return_value = _readTargetEntry();
2015
	else if (length == 3 && strncmp(token, "RTE", length) == 0)
2016
		return_value = _readRangeTblEntry();
2017
	else if (length == 4 && strncmp(token, "PATH", length) == 0)
2018
		return_value = _readPath();
2019
	else if (length == 9 && strncmp(token, "INDEXPATH", length) == 0)
2020
		return_value = _readIndexPath();
2021
	else if (length == 7 && strncmp(token, "TIDPATH", length) == 0)
2022
		return_value = _readTidPath();
2023 2024
	else if (length == 10 && strncmp(token, "APPENDPATH", length) == 0)
		return_value = _readAppendPath();
2025
	else if (length == 8 && strncmp(token, "NESTPATH", length) == 0)
2026
		return_value = _readNestPath();
2027
	else if (length == 9 && strncmp(token, "MERGEPATH", length) == 0)
2028
		return_value = _readMergePath();
2029
	else if (length == 8 && strncmp(token, "HASHPATH", length) == 0)
2030
		return_value = _readHashPath();
2031
	else if (length == 11 && strncmp(token, "PATHKEYITEM", length) == 0)
2032
		return_value = _readPathKeyItem();
2033
	else if (length == 12 && strncmp(token, "RESTRICTINFO", length) == 0)
2034
		return_value = _readRestrictInfo();
2035
	else if (length == 8 && strncmp(token, "JOININFO", length) == 0)
2036
		return_value = _readJoinInfo();
2037
	else if (length == 4 && strncmp(token, "ITER", length) == 0)
2038
		return_value = _readIter();
2039
	else if (length == 5 && strncmp(token, "QUERY", length) == 0)
2040
		return_value = _readQuery();
2041
	else if (length == 10 && strncmp(token, "SORTCLAUSE", length) == 0)
2042
		return_value = _readSortClause();
2043
	else if (length == 11 && strncmp(token, "GROUPCLAUSE", length) == 0)
2044
		return_value = _readGroupClause();
2045 2046
	else if (length == 16 && strncmp(token, "SETOPERATIONSTMT", length) == 0)
		return_value = _readSetOperationStmt();
2047
	else if (length == 4 && strncmp(token, "CASE", length) == 0)
2048
		return_value = _readCaseExpr();
2049
	else if (length == 4 && strncmp(token, "WHEN", length) == 0)
2050
		return_value = _readCaseWhen();
2051
	else
2052
		elog(ERROR, "badly formatted planstring \"%.10s\"...", token);
2053

2054
	return (Node *) return_value;
2055
}
2056

2057 2058 2059
/*------------------------------------------------------------*/

/* ----------------
2060
 *		readDatum
2061
 *
2062 2063 2064
 * Given a string representation of a constant, recreate the appropriate
 * Datum.  The string representation embeds length info, but not byValue,
 * so we must be told that.
2065 2066
 * ----------------
 */
2067
static Datum
2068
readDatum(bool typbyval)
2069
{
2070 2071
	Size		length,
				i;
2072 2073 2074 2075
	int			tokenLength;
	char	   *token;
	Datum		res;
	char	   *s;
2076 2077 2078 2079

	/*
	 * read the actual length of the value
	 */
2080
	token = pg_strtok(&tokenLength);
2081
	length = atoui(token);
2082

2083
	token = pg_strtok(&tokenLength);	/* skip the '[' */
2084 2085

	if (typbyval)
2086
	{
2087
		if (length > (Size) sizeof(Datum))
2088 2089
			elog(ERROR, "readDatum: byval & length = %lu",
				 (unsigned long) length);
2090
		res = (Datum) 0;
2091
		s = (char *) (&res);
2092
		for (i = 0; i < (Size) sizeof(Datum); i++)
2093
		{
2094
			token = pg_strtok(&tokenLength);
2095 2096 2097 2098
			s[i] = (char) atoi(token);
		}
	}
	else if (length <= 0)
2099 2100
		res = (Datum) NULL;
	else
2101 2102 2103 2104
	{
		s = (char *) palloc(length);
		for (i = 0; i < length; i++)
		{
2105
			token = pg_strtok(&tokenLength);
2106 2107 2108 2109 2110
			s[i] = (char) atoi(token);
		}
		res = PointerGetDatum(s);
	}

2111
	token = pg_strtok(&tokenLength);	/* skip the ']' */
2112
	if (token == NULL || token[0] != ']')
2113 2114
		elog(ERROR, "readDatum: ']' expected, length = %lu",
			 (unsigned long) length);
2115

2116
	return res;
2117
}