readfuncs.c 53.8 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * readfuncs.c
4
 *	  Reader functions for Postgres tree nodes.
5
 *
Bruce Momjian's avatar
Bruce Momjian committed
6
 * Portions Copyright (c) 1996-2002, 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.127 2002/08/04 19:48:09 momjian 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 :command */
	token = pg_strtok(&length); /* get commandType */
124 125
	local_node->commandType = atoi(token);

126
	token = pg_strtok(&length); /* skip :utility */
127
	local_node->utilityStmt = nodeRead(true);
128

129
	token = pg_strtok(&length); /* skip :resultRelation */
130
	token = pg_strtok(&length); /* get the resultRelation */
131 132
	local_node->resultRelation = atoi(token);

133
	token = pg_strtok(&length); /* skip :into */
134
	local_node->into = nodeRead(true);
135

136 137
	token = pg_strtok(&length); /* skip :isPortal */
	token = pg_strtok(&length); /* get isPortal */
138
	local_node->isPortal = strtobool(token);
139

140 141
	token = pg_strtok(&length); /* skip :isBinary */
	token = pg_strtok(&length); /* get isBinary */
142
	local_node->isBinary = strtobool(token);
143

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

148 149
	token = pg_strtok(&length); /* skip the :hasSubLinks */
	token = pg_strtok(&length); /* get hasSubLinks */
150
	local_node->hasSubLinks = strtobool(token);
151

152 153 154
	/* we always want originalQuery to be false in a read-in query */
	local_node->originalQuery = false;

155
	token = pg_strtok(&length); /* skip :rtable */
156 157
	local_node->rtable = nodeRead(true);

158
	token = pg_strtok(&length); /* skip :jointree */
159 160
	local_node->jointree = nodeRead(true);

161
	token = pg_strtok(&length); /* skip :rowMarks */
162 163
	local_node->rowMarks = toIntList(nodeRead(true));

164
	token = pg_strtok(&length); /* skip :targetlist */
165
	local_node->targetList = nodeRead(true);
166

167
	token = pg_strtok(&length); /* skip :groupClause */
168 169
	local_node->groupClause = nodeRead(true);

170
	token = pg_strtok(&length); /* skip :havingQual */
171 172
	local_node->havingQual = nodeRead(true);

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

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

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

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

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

188
	token = pg_strtok(&length); /* skip :resultRelations */
189 190
	local_node->resultRelations = toIntList(nodeRead(true));

191
	return local_node;
192 193
}

194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
/* ----------------
 *		_readNotifyStmt
 * ----------------
 */
static NotifyStmt *
_readNotifyStmt(void)
{
	NotifyStmt *local_node;
	char	   *token;
	int			length;

	local_node = makeNode(NotifyStmt);

	token = pg_strtok(&length); /* skip :relation */
	local_node->relation = nodeRead(true);

	return local_node;
}

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

224
	local_node = makeNode(SortClause);
225

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

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

234
	return local_node;
235
}
236

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

	local_node = makeNode(GroupClause);

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

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

258
	return local_node;
259 260
}

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

	local_node = makeNode(SetOperationStmt);

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

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

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

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

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

	return local_node;
}

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

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

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

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

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

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

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

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

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

332 333
	node->state = (EState *) NULL;		/* never read in */

334
	return;
335 336 337
}

/*
338
 *	Stuff from plannodes.h
339 340 341
 */

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

	local_node = makeNode(Plan);

	_getPlan(local_node);

354
	return local_node;
355 356 357
}

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

	local_node = makeNode(Result);

	_getPlan((Plan *) local_node);

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

375
	return local_node;
376 377 378
}

/* ----------------
379
 *		_readAppend
380
 *
381
 *	Append is a subclass of Plan.
382 383 384
 * ----------------
 */

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

	local_node = makeNode(Append);

	_getPlan((Plan *) local_node);

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

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

403
	return local_node;
404 405 406
}

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

416
	_getPlan((Plan *) node);
417

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

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


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

	local_node = makeNode(Join);

	_getJoin(local_node);

442
	return local_node;
443 444 445
}

/* ----------------
446 447 448
 *		_readNestLoop
 *
 *	NestLoop is a subclass of Join
449 450 451 452
 * ----------------
 */

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

	local_node = makeNode(NestLoop);

	_getJoin((Join *) local_node);

461
	return local_node;
462 463 464
}

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

	local_node = makeNode(MergeJoin);

	_getJoin((Join *) local_node);
480

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

484
	return local_node;
485 486 487
}

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

	local_node = makeNode(HashJoin);

	_getJoin((Join *) local_node);

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

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

511
	return local_node;
512 513 514
}

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

	_getPlan((Plan *) node);

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

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

	local_node = makeNode(Scan);

	_getScan(local_node);

550
	return local_node;
551 552 553
}

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

	local_node = makeNode(SeqScan);

	_getScan((Scan *) local_node);

568
	return local_node;
569 570 571
}

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

	local_node = makeNode(IndexScan);

	_getScan((Scan *) local_node);

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

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

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

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

601
	return local_node;
602 603
}

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

	local_node = makeNode(TidScan);

	_getScan((Scan *) local_node);

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

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

	return local_node;
}

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

	local_node = makeNode(SubqueryScan);

	_getScan((Scan *) local_node);

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

	return local_node;
}

654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671
/* ----------------
 *		_readFunctionScan
 *
 *	FunctionScan is a subclass of Scan
 * ----------------
 */
static FunctionScan *
_readFunctionScan(void)
{
	FunctionScan *local_node;

	local_node = makeNode(FunctionScan);

	_getScan((Scan *) local_node);

	return local_node;
}

672
/* ----------------
673 674
 *		_readSort
 *
675
 *	Sort is a subclass of Plan
676 677
 * ----------------
 */
678
static Sort *
679
_readSort(void)
680
{
681 682 683
	Sort	   *local_node;
	char	   *token;
	int			length;
684 685 686 687 688

	local_node = makeNode(Sort);

	_getPlan((Plan *) local_node);

689 690
	token = pg_strtok(&length); /* eat :keycount */
	token = pg_strtok(&length); /* get keycount */
691 692
	local_node->keycount = atoi(token);

693
	return local_node;
694 695
}

696
static Agg *
697
_readAgg(void)
698
{
699
	Agg		   *local_node;
700 701 702 703

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

704
	return local_node;
705 706 707
}

/* ----------------
708 709
 *		_readHash
 *
710
 *	Hash is a subclass of Plan
711 712
 * ----------------
 */
713
static Hash *
714
_readHash(void)
715
{
716 717 718
	Hash	   *local_node;
	char	   *token;
	int			length;
719 720 721 722 723

	local_node = makeNode(Hash);

	_getPlan((Plan *) local_node);

724
	token = pg_strtok(&length); /* eat :hashkey */
725
	local_node->hashkey = nodeRead(true);
726

727
	return local_node;
728 729 730
}

/*
731
 *	Stuff from primnodes.h.
732 733 734
 */

/* ----------------
735 736 737
 *		_readResdom
 *
 *	Resdom is a subclass of Node
738 739
 * ----------------
 */
740
static Resdom *
741
_readResdom(void)
742
{
743 744 745
	Resdom	   *local_node;
	char	   *token;
	int			length;
746 747 748

	local_node = makeNode(Resdom);

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

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

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

761 762
	token = pg_strtok(&length); /* eat :resname */
	token = pg_strtok(&length); /* get the name */
763
	local_node->resname = nullable_string(token, length);
764

765 766
	token = pg_strtok(&length); /* eat :reskey */
	token = pg_strtok(&length); /* get reskey */
767
	local_node->reskey = atoui(token);
768

769 770
	token = pg_strtok(&length); /* eat :reskeyop */
	token = pg_strtok(&length); /* get reskeyop */
771
	local_node->reskeyop = atooid(token);
772

773 774
	token = pg_strtok(&length); /* eat :ressortgroupref */
	token = pg_strtok(&length); /* get ressortgroupref */
775
	local_node->ressortgroupref = atoui(token);
776

777 778
	token = pg_strtok(&length); /* eat :resjunk */
	token = pg_strtok(&length); /* get resjunk */
779
	local_node->resjunk = strtobool(token);
780

781
	return local_node;
782 783 784
}

/* ----------------
785 786 787
 *		_readExpr
 *
 *	Expr is a subclass of Node
788 789
 * ----------------
 */
790
static Expr *
791
_readExpr(void)
792
{
793 794 795
	Expr	   *local_node;
	char	   *token;
	int			length;
796 797 798

	local_node = makeNode(Expr);

799 800
	token = pg_strtok(&length); /* eat :typeOid */
	token = pg_strtok(&length); /* get typeOid */
801
	local_node->typeOid = atooid(token);
802

803 804
	token = pg_strtok(&length); /* eat :opType */
	token = pg_strtok(&length); /* get opType */
805
	if (strncmp(token, "op", 2) == 0)
806
		local_node->opType = OP_EXPR;
807 808
	else if (strncmp(token, "distinct", 8) == 0)
		local_node->opType = DISTINCT_EXPR;
809
	else if (strncmp(token, "func", 4) == 0)
810
		local_node->opType = FUNC_EXPR;
811
	else if (strncmp(token, "or", 2) == 0)
812
		local_node->opType = OR_EXPR;
813
	else if (strncmp(token, "and", 3) == 0)
814
		local_node->opType = AND_EXPR;
815
	else if (strncmp(token, "not", 3) == 0)
816
		local_node->opType = NOT_EXPR;
817
	else if (strncmp(token, "subp", 4) == 0)
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
818
		local_node->opType = SUBPLAN_EXPR;
819
	else
820
		elog(ERROR, "_readExpr: unknown opType \"%.*s\"", length, token);
821

822
	token = pg_strtok(&length); /* eat :oper */
823 824
	local_node->oper = nodeRead(true);

825
	token = pg_strtok(&length); /* eat :args */
826 827
	local_node->args = nodeRead(true);	/* now read it */

828
	return local_node;
829 830
}

831 832 833 834 835 836 837
/* ----------------
 *		_readCaseExpr
 *
 *	CaseExpr is a subclass of Node
 * ----------------
 */
static CaseExpr *
838
_readCaseExpr(void)
839 840 841 842 843 844 845
{
	CaseExpr   *local_node;
	char	   *token;
	int			length;

	local_node = makeNode(CaseExpr);

846 847
	token = pg_strtok(&length); /* eat :casetype */
	token = pg_strtok(&length); /* get casetype */
848
	local_node->casetype = atooid(token);
849

850
	token = pg_strtok(&length); /* eat :arg */
851 852
	local_node->arg = nodeRead(true);

853
	token = pg_strtok(&length); /* eat :args */
854
	local_node->args = nodeRead(true);
855

856
	token = pg_strtok(&length); /* eat :defresult */
857 858 859 860 861 862 863 864 865 866 867 868
	local_node->defresult = nodeRead(true);

	return local_node;
}

/* ----------------
 *		_readCaseWhen
 *
 *	CaseWhen is a subclass of Node
 * ----------------
 */
static CaseWhen *
869
_readCaseWhen(void)
870 871 872 873 874 875 876 877
{
	CaseWhen   *local_node;
	char	   *token;
	int			length;

	local_node = makeNode(CaseWhen);

	local_node->expr = nodeRead(true);
878
	token = pg_strtok(&length); /* eat :then */
879 880 881 882 883
	local_node->result = nodeRead(true);

	return local_node;
}

884 885 886 887 888 889 890 891 892
/* ----------------
 *		_readNullTest
 *
 *	NullTest is a subclass of Node
 * ----------------
 */
static NullTest *
_readNullTest(void)
{
893 894
	NullTest   *local_node;
	char	   *token;
895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917
	int			length;

	local_node = makeNode(NullTest);

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

	token = pg_strtok(&length); /* eat :nulltesttype */
	token = pg_strtok(&length); /* get nulltesttype */
	local_node->nulltesttype = (NullTestType) atoi(token);

	return local_node;
}

/* ----------------
 *		_readBooleanTest
 *
 *	BooleanTest is a subclass of Node
 * ----------------
 */
static BooleanTest *
_readBooleanTest(void)
{
918 919
	BooleanTest *local_node;
	char	   *token;
920 921 922 923 924 925 926 927 928 929 930 931 932 933
	int			length;

	local_node = makeNode(BooleanTest);

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

	token = pg_strtok(&length); /* eat :booltesttype */
	token = pg_strtok(&length); /* get booltesttype */
	local_node->booltesttype = (BoolTestType) atoi(token);

	return local_node;
}

934
/* ----------------
935 936 937
 *		_readVar
 *
 *	Var is a subclass of Expr
938 939
 * ----------------
 */
940
static Var *
941
_readVar(void)
942
{
943 944 945
	Var		   *local_node;
	char	   *token;
	int			length;
946 947 948

	local_node = makeNode(Var);

949 950
	token = pg_strtok(&length); /* eat :varno */
	token = pg_strtok(&length); /* get varno */
951
	local_node->varno = atoui(token);
952

953 954
	token = pg_strtok(&length); /* eat :varattno */
	token = pg_strtok(&length); /* get varattno */
955 956
	local_node->varattno = atoi(token);

957 958
	token = pg_strtok(&length); /* eat :vartype */
	token = pg_strtok(&length); /* get vartype */
959
	local_node->vartype = atooid(token);
960

961 962
	token = pg_strtok(&length); /* eat :vartypmod */
	token = pg_strtok(&length); /* get vartypmod */
Bruce Momjian's avatar
Bruce Momjian committed
963
	local_node->vartypmod = atoi(token);
964

965 966
	token = pg_strtok(&length); /* eat :varlevelsup */
	token = pg_strtok(&length); /* get varlevelsup */
967
	local_node->varlevelsup = atoui(token);
968

969 970
	token = pg_strtok(&length); /* eat :varnoold */
	token = pg_strtok(&length); /* get varnoold */
971
	local_node->varnoold = atoui(token);
972

973 974
	token = pg_strtok(&length); /* eat :varoattno */
	token = pg_strtok(&length); /* eat :varoattno */
975
	local_node->varoattno = atoi(token);
976

977
	return local_node;
978 979 980 981 982 983 984 985 986
}

/* ----------------
 * _readArrayRef
 *
 * ArrayRef is a subclass of Expr
 * ----------------
 */
static ArrayRef *
987
_readArrayRef(void)
988
{
989 990 991
	ArrayRef   *local_node;
	char	   *token;
	int			length;
992 993 994

	local_node = makeNode(ArrayRef);

995 996
	token = pg_strtok(&length); /* eat :refelemtype */
	token = pg_strtok(&length); /* get refelemtype */
997
	local_node->refelemtype = atooid(token);
998

999 1000
	token = pg_strtok(&length); /* eat :refattrlength */
	token = pg_strtok(&length); /* get refattrlength */
1001 1002
	local_node->refattrlength = atoi(token);

1003 1004
	token = pg_strtok(&length); /* eat :refelemlength */
	token = pg_strtok(&length); /* get refelemlength */
1005 1006
	local_node->refelemlength = atoi(token);

1007 1008
	token = pg_strtok(&length); /* eat :refelembyval */
	token = pg_strtok(&length); /* get refelembyval */
1009
	local_node->refelembyval = strtobool(token);
1010

1011
	token = pg_strtok(&length); /* eat :refupperindex */
1012 1013
	local_node->refupperindexpr = nodeRead(true);

1014
	token = pg_strtok(&length); /* eat :reflowerindex */
1015 1016
	local_node->reflowerindexpr = nodeRead(true);

1017
	token = pg_strtok(&length); /* eat :refexpr */
1018 1019
	local_node->refexpr = nodeRead(true);

1020
	token = pg_strtok(&length); /* eat :refassgnexpr */
1021 1022
	local_node->refassgnexpr = nodeRead(true);

1023
	return local_node;
1024 1025 1026
}

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

	local_node = makeNode(Const);

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

1045 1046
	token = pg_strtok(&length); /* get :constlen */
	token = pg_strtok(&length); /* now read it */
1047
	local_node->constlen = atoi(token);
1048

1049 1050
	token = pg_strtok(&length); /* get :constbyval */
	token = pg_strtok(&length); /* now read it */
1051
	local_node->constbyval = strtobool(token);
1052

1053 1054
	token = pg_strtok(&length); /* get :constisnull */
	token = pg_strtok(&length); /* now read it */
1055
	local_node->constisnull = strtobool(token);
1056

1057
	token = pg_strtok(&length); /* get :constvalue */
1058 1059 1060

	if (local_node->constisnull)
	{
1061
		token = pg_strtok(&length);		/* skip "NIL" */
1062 1063
	}
	else
1064
		local_node->constvalue = readDatum(local_node->constbyval);
1065

1066
	return local_node;
1067 1068 1069
}

/* ----------------
1070 1071 1072
 *		_readFunc
 *
 *	Func is a subclass of Expr
1073 1074
 * ----------------
 */
1075
static Func *
1076
_readFunc(void)
1077
{
1078 1079 1080
	Func	   *local_node;
	char	   *token;
	int			length;
1081 1082 1083

	local_node = makeNode(Func);

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

1088
	token = pg_strtok(&length); /* get :funcresulttype */
1089
	token = pg_strtok(&length); /* now read it */
1090 1091 1092 1093 1094
	local_node->funcresulttype = atooid(token);

	token = pg_strtok(&length); /* get :funcretset */
	token = pg_strtok(&length); /* now read it */
	local_node->funcretset = strtobool(token);
1095

1096
	local_node->func_fcache = NULL;
1097

1098
	return local_node;
1099 1100 1101
}

/* ----------------
1102 1103 1104
 *		_readOper
 *
 *	Oper is a subclass of Expr
1105 1106
 * ----------------
 */
1107
static Oper *
1108
_readOper(void)
1109
{
1110 1111 1112
	Oper	   *local_node;
	char	   *token;
	int			length;
1113 1114 1115

	local_node = makeNode(Oper);

1116 1117
	token = pg_strtok(&length); /* get :opno */
	token = pg_strtok(&length); /* now read it */
1118
	local_node->opno = atooid(token);
1119

1120 1121
	token = pg_strtok(&length); /* get :opid */
	token = pg_strtok(&length); /* now read it */
1122
	local_node->opid = atooid(token);
1123

1124 1125
	token = pg_strtok(&length); /* get :opresulttype */
	token = pg_strtok(&length); /* now read it */
1126
	local_node->opresulttype = atooid(token);
1127

1128 1129 1130 1131
	token = pg_strtok(&length); /* get :opretset */
	token = pg_strtok(&length); /* now read it */
	local_node->opretset = strtobool(token);

1132
	local_node->op_fcache = NULL;
1133

1134
	return local_node;
1135 1136 1137
}

/* ----------------
1138 1139 1140
 *		_readParam
 *
 *	Param is a subclass of Expr
1141 1142
 * ----------------
 */
1143
static Param *
1144
_readParam(void)
1145
{
1146 1147 1148
	Param	   *local_node;
	char	   *token;
	int			length;
1149 1150 1151

	local_node = makeNode(Param);

1152 1153
	token = pg_strtok(&length); /* get :paramkind */
	token = pg_strtok(&length); /* now read it */
1154 1155
	local_node->paramkind = atoi(token);

1156 1157
	token = pg_strtok(&length); /* get :paramid */
	token = pg_strtok(&length); /* now read it */
1158
	local_node->paramid = atoi(token);
1159

1160 1161
	token = pg_strtok(&length); /* get :paramname */
	token = pg_strtok(&length); /* now read it */
1162
	local_node->paramname = nullable_string(token, length);
1163

1164 1165
	token = pg_strtok(&length); /* get :paramtype */
	token = pg_strtok(&length); /* now read it */
1166
	local_node->paramtype = atooid(token);
1167

1168
	return local_node;
1169 1170
}

1171
/* ----------------
Bruce Momjian's avatar
Bruce Momjian committed
1172
 *		_readAggref
1173
 *
Bruce Momjian's avatar
Bruce Momjian committed
1174
 *	Aggref is a subclass of Node
1175 1176
 * ----------------
 */
Bruce Momjian's avatar
Bruce Momjian committed
1177
static Aggref *
1178
_readAggref(void)
1179
{
Bruce Momjian's avatar
Bruce Momjian committed
1180
	Aggref	   *local_node;
1181 1182
	char	   *token;
	int			length;
1183

Bruce Momjian's avatar
Bruce Momjian committed
1184
	local_node = makeNode(Aggref);
1185

1186 1187 1188
	token = pg_strtok(&length); /* eat :aggfnoid */
	token = pg_strtok(&length); /* get aggfnoid */
	local_node->aggfnoid = atooid(token);
1189

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

1194
	token = pg_strtok(&length); /* eat :target */
1195 1196
	local_node->target = nodeRead(true);		/* now read it */

1197 1198
	token = pg_strtok(&length); /* eat :aggstar */
	token = pg_strtok(&length); /* get aggstar */
1199
	local_node->aggstar = strtobool(token);
1200

1201 1202
	token = pg_strtok(&length); /* eat :aggdistinct */
	token = pg_strtok(&length); /* get aggdistinct */
1203
	local_node->aggdistinct = strtobool(token);
1204

1205
	return local_node;
1206 1207
}

1208 1209 1210 1211 1212 1213 1214
/* ----------------
 *		_readSubLink
 *
 *	SubLink is a subclass of Node
 * ----------------
 */
static SubLink *
1215
_readSubLink(void)
1216
{
1217
	SubLink    *local_node;
1218 1219 1220 1221 1222
	char	   *token;
	int			length;

	local_node = makeNode(SubLink);

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

1227 1228
	token = pg_strtok(&length); /* eat :useor */
	token = pg_strtok(&length); /* get useor */
1229
	local_node->useor = strtobool(token);
1230

1231
	token = pg_strtok(&length); /* eat :lefthand */
1232 1233
	local_node->lefthand = nodeRead(true);		/* now read it */

1234
	token = pg_strtok(&length); /* eat :oper */
1235
	local_node->oper = nodeRead(true);	/* now read it */
1236

1237
	token = pg_strtok(&length); /* eat :subselect */
1238 1239
	local_node->subselect = nodeRead(true);		/* now read it */

1240
	return local_node;
1241 1242
}

1243 1244 1245 1246 1247 1248 1249
/* ----------------
 *		_readFieldSelect
 *
 *	FieldSelect is a subclass of Node
 * ----------------
 */
static FieldSelect *
1250
_readFieldSelect(void)
1251 1252 1253 1254 1255 1256 1257
{
	FieldSelect *local_node;
	char	   *token;
	int			length;

	local_node = makeNode(FieldSelect);

1258
	token = pg_strtok(&length); /* eat :arg */
1259 1260
	local_node->arg = nodeRead(true);	/* now read it */

1261 1262
	token = pg_strtok(&length); /* eat :fieldnum */
	token = pg_strtok(&length); /* get fieldnum */
1263 1264
	local_node->fieldnum = (AttrNumber) atoi(token);

1265 1266
	token = pg_strtok(&length); /* eat :resulttype */
	token = pg_strtok(&length); /* get resulttype */
1267
	local_node->resulttype = atooid(token);
1268

1269 1270
	token = pg_strtok(&length); /* eat :resulttypmod */
	token = pg_strtok(&length); /* get resulttypmod */
1271 1272 1273 1274 1275
	local_node->resulttypmod = atoi(token);

	return local_node;
}

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

	local_node = makeNode(RelabelType);

1291
	token = pg_strtok(&length); /* eat :arg */
1292 1293
	local_node->arg = nodeRead(true);	/* now read it */

1294 1295
	token = pg_strtok(&length); /* eat :resulttype */
	token = pg_strtok(&length); /* get resulttype */
1296
	local_node->resulttype = atooid(token);
1297

1298 1299
	token = pg_strtok(&length); /* eat :resulttypmod */
	token = pg_strtok(&length); /* get resulttypmod */
1300 1301 1302 1303 1304
	local_node->resulttypmod = atoi(token);

	return local_node;
}

1305 1306 1307 1308 1309 1310 1311
/* ----------------
 *		_readRangeTblRef
 *
 *	RangeTblRef is a subclass of Node
 * ----------------
 */
static RangeTblRef *
1312
_readRangeTblRef(void)
1313 1314 1315 1316 1317 1318 1319
{
	RangeTblRef *local_node;
	char	   *token;
	int			length;

	local_node = makeNode(RangeTblRef);

1320
	token = pg_strtok(&length); /* get rtindex */
1321 1322 1323 1324 1325
	local_node->rtindex = atoi(token);

	return local_node;
}

1326 1327 1328 1329 1330 1331 1332
/* ----------------
 *		_readFromExpr
 *
 *	FromExpr is a subclass of Node
 * ----------------
 */
static FromExpr *
1333
_readFromExpr(void)
1334 1335 1336 1337 1338 1339 1340
{
	FromExpr   *local_node;
	char	   *token;
	int			length;

	local_node = makeNode(FromExpr);

1341 1342
	token = pg_strtok(&length); /* eat :fromlist */
	local_node->fromlist = nodeRead(true);		/* now read it */
1343

1344 1345
	token = pg_strtok(&length); /* eat :quals */
	local_node->quals = nodeRead(true); /* now read it */
1346 1347 1348 1349

	return local_node;
}

1350 1351 1352 1353 1354 1355 1356
/* ----------------
 *		_readJoinExpr
 *
 *	JoinExpr is a subclass of Node
 * ----------------
 */
static JoinExpr *
1357
_readJoinExpr(void)
1358 1359 1360 1361 1362 1363 1364
{
	JoinExpr   *local_node;
	char	   *token;
	int			length;

	local_node = makeNode(JoinExpr);

1365 1366
	token = pg_strtok(&length); /* eat :jointype */
	token = pg_strtok(&length); /* get jointype */
1367 1368
	local_node->jointype = (JoinType) atoi(token);

1369
	token = pg_strtok(&length); /* eat :isNatural */
1370
	token = pg_strtok(&length); /* get isNatural */
1371
	local_node->isNatural = strtobool(token);
1372

1373
	token = pg_strtok(&length); /* eat :larg */
1374 1375
	local_node->larg = nodeRead(true);	/* now read it */

1376
	token = pg_strtok(&length); /* eat :rarg */
1377 1378
	local_node->rarg = nodeRead(true);	/* now read it */

1379 1380
	token = pg_strtok(&length); /* eat :using */
	local_node->using = nodeRead(true); /* now read it */
1381

1382 1383
	token = pg_strtok(&length); /* eat :quals */
	local_node->quals = nodeRead(true); /* now read it */
1384

1385 1386
	token = pg_strtok(&length); /* eat :alias */
	local_node->alias = nodeRead(true); /* now read it */
1387

1388 1389 1390
	token = pg_strtok(&length); /* eat :rtindex */
	token = pg_strtok(&length); /* get rtindex */
	local_node->rtindex = atoi(token);
1391 1392 1393 1394

	return local_node;
}

1395
/* ----------------
1396
 *		_readTargetEntry
1397 1398 1399
 * ----------------
 */
static TargetEntry *
1400
_readTargetEntry(void)
1401
{
1402 1403 1404
	TargetEntry *local_node;
	char	   *token;
	int			length;
1405

1406
	local_node = makeNode(TargetEntry);
1407

1408
	token = pg_strtok(&length); /* get :resdom */
1409
	local_node->resdom = nodeRead(true);		/* now read it */
1410

1411
	token = pg_strtok(&length); /* get :expr */
1412
	local_node->expr = nodeRead(true);	/* now read it */
1413

1414
	return local_node;
1415 1416
}

1417 1418
static RangeVar *
_readRangeVar(void)
1419
{
1420
	RangeVar   *local_node;
1421 1422 1423
	char	   *token;
	int			length;

1424
	local_node = makeNode(RangeVar);
1425

1426 1427 1428 1429 1430 1431 1432
	local_node->catalogname = NULL;	/* not currently saved in output format */

	token = pg_strtok(&length); /* eat :relation */
	token = pg_strtok(&length); /* get schemaname */
	local_node->schemaname = nullable_string(token, length);

	token = pg_strtok(&length); /* eat "." */
1433
	token = pg_strtok(&length); /* get relname */
1434 1435 1436 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 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500
	local_node->relname = nullable_string(token, length);
	
	token = pg_strtok(&length); /* eat :inhopt */
	token = pg_strtok(&length); /* get inhopt */
	local_node->inhOpt = (InhOption) atoi(token);
	
	token = pg_strtok(&length); /* eat :istemp */
	token = pg_strtok(&length); /* get istemp */
	local_node->istemp = strtobool(token);

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

	return local_node;
}

static ColumnRef *
_readColumnRef(void)
{
	ColumnRef  *local_node;
	char	   *token;
	int			length;

	local_node = makeNode(ColumnRef);

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

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

	return local_node;
}

static ExprFieldSelect *
_readExprFieldSelect(void)
{
	ExprFieldSelect  *local_node;
	char	   *token;
	int			length;

	local_node = makeNode(ExprFieldSelect);

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

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

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

	return local_node;
}

static Alias *
_readAlias(void)
{
	Alias	   *local_node;
	char	   *token;
	int			length;

	local_node = makeNode(Alias);

	token = pg_strtok(&length); /* eat :aliasname */
	token = pg_strtok(&length); /* get aliasname */
	local_node->aliasname = debackslash(token, length);
1501

1502 1503
	token = pg_strtok(&length); /* eat :colnames */
	local_node->colnames = nodeRead(true); /* now read it */
1504 1505 1506 1507

	return local_node;
}

1508
/* ----------------
1509
 *		_readRangeTblEntry
1510 1511 1512
 * ----------------
 */
static RangeTblEntry *
1513
_readRangeTblEntry(void)
1514
{
1515 1516 1517
	RangeTblEntry *local_node;
	char	   *token;
	int			length;
1518

1519
	local_node = makeNode(RangeTblEntry);
1520

1521 1522
	token = pg_strtok(&length); /* eat :alias */
	local_node->alias = nodeRead(true); /* now read it */
1523

1524
	token = pg_strtok(&length); /* eat :eref */
1525 1526
	local_node->eref = nodeRead(true);	/* now read it */

1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544
	token = pg_strtok(&length); /* eat :rtekind */
	token = pg_strtok(&length); /* get rtekind */
	local_node->rtekind = (RTEKind) atoi(token);

	switch (local_node->rtekind)
	{
		case RTE_RELATION:
		case RTE_SPECIAL:
			token = pg_strtok(&length); /* eat :relid */
			token = pg_strtok(&length); /* get :relid */
			local_node->relid = atooid(token);
			break;

		case RTE_SUBQUERY:
			token = pg_strtok(&length); /* eat :subquery */
			local_node->subquery = nodeRead(true);		/* now read it */
			break;

1545 1546 1547
		case RTE_FUNCTION:
			token = pg_strtok(&length); /* eat :funcexpr */
			local_node->funcexpr = nodeRead(true);		/* now read it */
1548 1549 1550 1551

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

1552 1553
			break;

1554 1555 1556 1557 1558
		case RTE_JOIN:
			token = pg_strtok(&length); /* eat :jointype */
			token = pg_strtok(&length); /* get jointype */
			local_node->jointype = (JoinType) atoi(token);

1559 1560
			token = pg_strtok(&length); /* eat :joinaliasvars */
			local_node->joinaliasvars = nodeRead(true);	/* now read it */
1561 1562 1563 1564 1565 1566 1567
			break;

		default:
			elog(ERROR, "bogus rte kind %d", (int) local_node->rtekind);
			break;
	}

1568 1569
	token = pg_strtok(&length); /* eat :inh */
	token = pg_strtok(&length); /* get :inh */
1570
	local_node->inh = strtobool(token);
1571

1572 1573
	token = pg_strtok(&length); /* eat :inFromCl */
	token = pg_strtok(&length); /* get :inFromCl */
1574
	local_node->inFromCl = strtobool(token);
1575

1576 1577
	token = pg_strtok(&length); /* eat :checkForRead */
	token = pg_strtok(&length); /* get :checkForRead */
1578
	local_node->checkForRead = strtobool(token);
1579

1580 1581
	token = pg_strtok(&length); /* eat :checkForWrite */
	token = pg_strtok(&length); /* get :checkForWrite */
1582
	local_node->checkForWrite = strtobool(token);
1583

1584 1585
	token = pg_strtok(&length); /* eat :checkAsUser */
	token = pg_strtok(&length); /* get :checkAsUser */
1586
	local_node->checkAsUser = atooid(token);
1587 1588 1589 1590

	return local_node;
}

1591
/* ----------------
1592 1593 1594
 *		_readPath
 *
 *	Path is a subclass of Node.
1595 1596
 * ----------------
 */
1597
static Path *
1598
_readPath(void)
1599
{
1600 1601 1602
	Path	   *local_node;
	char	   *token;
	int			length;
1603 1604 1605

	local_node = makeNode(Path);

1606 1607
	token = pg_strtok(&length); /* get :pathtype */
	token = pg_strtok(&length); /* now read it */
1608
	local_node->pathtype = atoi(token);
1609

1610 1611
	token = pg_strtok(&length); /* get :startup_cost */
	token = pg_strtok(&length); /* now read it */
1612 1613
	local_node->startup_cost = (Cost) atof(token);

1614 1615
	token = pg_strtok(&length); /* get :total_cost */
	token = pg_strtok(&length); /* now read it */
1616
	local_node->total_cost = (Cost) atof(token);
1617

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

1621
	return local_node;
1622 1623 1624
}

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

	local_node = makeNode(IndexPath);

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

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

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

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

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

1657
	token = pg_strtok(&length); /* get :indexqual */
1658 1659
	local_node->indexqual = nodeRead(true);		/* now read it */

1660 1661
	token = pg_strtok(&length); /* get :indexscandir */
	token = pg_strtok(&length); /* now read it */
1662 1663
	local_node->indexscandir = (ScanDirection) atoi(token);

1664
	token = pg_strtok(&length); /* get :joinrelids */
1665 1666
	local_node->joinrelids = toIntList(nodeRead(true));

1667 1668
	token = pg_strtok(&length); /* get :alljoinquals */
	token = pg_strtok(&length); /* now read it */
1669
	local_node->alljoinquals = strtobool(token);
1670

1671 1672
	token = pg_strtok(&length); /* get :rows */
	token = pg_strtok(&length); /* now read it */
1673 1674
	local_node->rows = atof(token);

1675
	return local_node;
1676 1677
}

1678 1679 1680 1681 1682 1683 1684
/* ----------------
 *		_readTidPath
 *
 *	TidPath is a subclass of Path.
 * ----------------
 */
static TidPath *
1685
_readTidPath(void)
1686
{
1687
	TidPath    *local_node;
1688 1689 1690 1691 1692
	char	   *token;
	int			length;

	local_node = makeNode(TidPath);

1693 1694
	token = pg_strtok(&length); /* get :pathtype */
	token = pg_strtok(&length); /* now read it */
1695
	local_node->path.pathtype = atoi(token);
1696

1697 1698
	token = pg_strtok(&length); /* get :startup_cost */
	token = pg_strtok(&length); /* now read it */
1699 1700
	local_node->path.startup_cost = (Cost) atof(token);

1701 1702
	token = pg_strtok(&length); /* get :total_cost */
	token = pg_strtok(&length); /* now read it */
1703
	local_node->path.total_cost = (Cost) atof(token);
1704

1705
	token = pg_strtok(&length); /* get :pathkeys */
1706 1707
	local_node->path.pathkeys = nodeRead(true); /* now read it */

1708
	token = pg_strtok(&length); /* get :tideval */
1709
	local_node->tideval = nodeRead(true);		/* now read it */
1710

1711
	token = pg_strtok(&length); /* get :unjoined_relids */
1712 1713 1714 1715 1716
	local_node->unjoined_relids = toIntList(nodeRead(true));

	return local_node;
}

1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731
/* ----------------
 *		_readAppendPath
 *
 *	AppendPath is a subclass of Path.
 * ----------------
 */
static AppendPath *
_readAppendPath(void)
{
	AppendPath *local_node;
	char	   *token;
	int			length;

	local_node = makeNode(AppendPath);

1732 1733
	token = pg_strtok(&length); /* get :pathtype */
	token = pg_strtok(&length); /* now read it */
1734
	local_node->path.pathtype = atoi(token);
1735

1736 1737
	token = pg_strtok(&length); /* get :startup_cost */
	token = pg_strtok(&length); /* now read it */
1738 1739
	local_node->path.startup_cost = (Cost) atof(token);

1740 1741
	token = pg_strtok(&length); /* get :total_cost */
	token = pg_strtok(&length); /* now read it */
1742 1743
	local_node->path.total_cost = (Cost) atof(token);

1744
	token = pg_strtok(&length); /* get :pathkeys */
1745 1746
	local_node->path.pathkeys = nodeRead(true); /* now read it */

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

	return local_node;
}

1753
/* ----------------
1754
 *		_readNestPath
1755
 *
1756
 *	NestPath is a subclass of Path
1757 1758
 * ----------------
 */
1759
static NestPath *
1760
_readNestPath(void)
1761
{
1762
	NestPath   *local_node;
1763 1764
	char	   *token;
	int			length;
1765

1766
	local_node = makeNode(NestPath);
1767

1768 1769
	token = pg_strtok(&length); /* get :pathtype */
	token = pg_strtok(&length); /* now read it */
1770
	local_node->path.pathtype = atoi(token);
1771

1772 1773
	token = pg_strtok(&length); /* get :startup_cost */
	token = pg_strtok(&length); /* now read it */
1774 1775
	local_node->path.startup_cost = (Cost) atof(token);

1776 1777
	token = pg_strtok(&length); /* get :total_cost */
	token = pg_strtok(&length); /* now read it */
1778
	local_node->path.total_cost = (Cost) atof(token);
1779

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

1783 1784
	token = pg_strtok(&length); /* get :jointype */
	token = pg_strtok(&length); /* now read it */
1785 1786
	local_node->jointype = (JoinType) atoi(token);

1787
	token = pg_strtok(&length); /* get :outerjoinpath */
1788
	local_node->outerjoinpath = nodeRead(true); /* now read it */
1789

1790
	token = pg_strtok(&length); /* get :innerjoinpath */
1791
	local_node->innerjoinpath = nodeRead(true); /* now read it */
1792

1793 1794
	token = pg_strtok(&length); /* get :joinrestrictinfo */
	local_node->joinrestrictinfo = nodeRead(true);		/* now read it */
1795

1796
	return local_node;
1797 1798 1799
}

/* ----------------
1800 1801
 *		_readMergePath
 *
1802
 *	MergePath is a subclass of NestPath.
1803 1804 1805
 * ----------------
 */
static MergePath *
1806
_readMergePath(void)
1807
{
1808 1809 1810
	MergePath  *local_node;
	char	   *token;
	int			length;
1811 1812 1813

	local_node = makeNode(MergePath);

1814 1815
	token = pg_strtok(&length); /* get :pathtype */
	token = pg_strtok(&length); /* now read it */
1816
	local_node->jpath.path.pathtype = atoi(token);
1817

1818 1819
	token = pg_strtok(&length); /* get :startup_cost */
	token = pg_strtok(&length); /* now read it */
1820
	local_node->jpath.path.startup_cost = (Cost) atof(token);
1821

1822 1823
	token = pg_strtok(&length); /* get :total_cost */
	token = pg_strtok(&length); /* now read it */
1824
	local_node->jpath.path.total_cost = (Cost) atof(token);
1825

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

1829 1830
	token = pg_strtok(&length); /* get :jointype */
	token = pg_strtok(&length); /* now read it */
1831 1832
	local_node->jpath.jointype = (JoinType) atoi(token);

1833
	token = pg_strtok(&length); /* get :outerjoinpath */
1834
	local_node->jpath.outerjoinpath = nodeRead(true);	/* now read it */
1835

1836
	token = pg_strtok(&length); /* get :innerjoinpath */
1837
	local_node->jpath.innerjoinpath = nodeRead(true);	/* now read it */
1838

1839 1840
	token = pg_strtok(&length); /* get :joinrestrictinfo */
	local_node->jpath.joinrestrictinfo = nodeRead(true);		/* now read it */
1841

1842
	token = pg_strtok(&length); /* get :path_mergeclauses */
1843 1844
	local_node->path_mergeclauses = nodeRead(true);		/* now read it */

1845
	token = pg_strtok(&length); /* get :outersortkeys */
1846 1847
	local_node->outersortkeys = nodeRead(true); /* now read it */

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

1851
	return local_node;
1852 1853 1854
}

/* ----------------
1855 1856
 *		_readHashPath
 *
1857
 *	HashPath is a subclass of NestPath.
1858 1859 1860
 * ----------------
 */
static HashPath *
1861
_readHashPath(void)
1862
{
1863 1864 1865
	HashPath   *local_node;
	char	   *token;
	int			length;
1866 1867 1868

	local_node = makeNode(HashPath);

1869 1870
	token = pg_strtok(&length); /* get :pathtype */
	token = pg_strtok(&length); /* now read it */
1871
	local_node->jpath.path.pathtype = atoi(token);
1872

1873 1874
	token = pg_strtok(&length); /* get :startup_cost */
	token = pg_strtok(&length); /* now read it */
1875
	local_node->jpath.path.startup_cost = (Cost) atof(token);
1876

1877 1878
	token = pg_strtok(&length); /* get :total_cost */
	token = pg_strtok(&length); /* now read it */
1879
	local_node->jpath.path.total_cost = (Cost) atof(token);
1880

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

1884 1885
	token = pg_strtok(&length); /* get :jointype */
	token = pg_strtok(&length); /* now read it */
1886 1887
	local_node->jpath.jointype = (JoinType) atoi(token);

1888
	token = pg_strtok(&length); /* get :outerjoinpath */
1889
	local_node->jpath.outerjoinpath = nodeRead(true);	/* now read it */
1890

1891
	token = pg_strtok(&length); /* get :innerjoinpath */
1892
	local_node->jpath.innerjoinpath = nodeRead(true);	/* now read it */
1893

1894 1895
	token = pg_strtok(&length); /* get :joinrestrictinfo */
	local_node->jpath.joinrestrictinfo = nodeRead(true);		/* now read it */
1896

1897
	token = pg_strtok(&length); /* get :path_hashclauses */
1898 1899
	local_node->path_hashclauses = nodeRead(true);		/* now read it */

1900
	return local_node;
1901 1902 1903
}

/* ----------------
1904
 *		_readPathKeyItem
1905
 *
1906
 *	PathKeyItem is a subclass of Node.
1907 1908
 * ----------------
 */
1909
static PathKeyItem *
1910
_readPathKeyItem(void)
1911
{
1912
	PathKeyItem *local_node;
1913 1914
	char	   *token;
	int			length;
1915

1916
	local_node = makeNode(PathKeyItem);
1917

1918 1919
	token = pg_strtok(&length); /* get :sortop */
	token = pg_strtok(&length); /* now read it */
1920
	local_node->sortop = atooid(token);
1921

1922
	token = pg_strtok(&length); /* get :key */
1923
	local_node->key = nodeRead(true);	/* now read it */
1924

1925
	return local_node;
1926 1927 1928
}

/* ----------------
1929
 *		_readRestrictInfo
1930
 *
1931
 *	RestrictInfo is a subclass of Node.
1932 1933
 * ----------------
 */
1934
static RestrictInfo *
1935
_readRestrictInfo(void)
1936
{
1937
	RestrictInfo *local_node;
1938 1939
	char	   *token;
	int			length;
1940

1941
	local_node = makeNode(RestrictInfo);
1942

1943
	token = pg_strtok(&length); /* get :clause */
1944 1945
	local_node->clause = nodeRead(true);		/* now read it */

1946 1947
	token = pg_strtok(&length); /* get :ispusheddown */
	token = pg_strtok(&length); /* now read it */
1948
	local_node->ispusheddown = strtobool(token);
1949

1950
	token = pg_strtok(&length); /* get :subclauseindices */
1951
	local_node->subclauseindices = nodeRead(true);		/* now read it */
1952

1953 1954
	token = pg_strtok(&length); /* get :mergejoinoperator */
	token = pg_strtok(&length); /* now read it */
1955
	local_node->mergejoinoperator = atooid(token);
1956

1957 1958
	token = pg_strtok(&length); /* get :left_sortop */
	token = pg_strtok(&length); /* now read it */
1959
	local_node->left_sortop = atooid(token);
1960

1961 1962
	token = pg_strtok(&length); /* get :right_sortop */
	token = pg_strtok(&length); /* now read it */
1963
	local_node->right_sortop = atooid(token);
1964

1965 1966
	token = pg_strtok(&length); /* get :hashjoinoperator */
	token = pg_strtok(&length); /* now read it */
1967
	local_node->hashjoinoperator = atooid(token);
1968

1969 1970
	/* eval_cost is not part of saved representation; compute on first use */
	local_node->eval_cost = -1;
1971 1972
	/* ditto for this_selec */
	local_node->this_selec = -1;
1973
	/* ditto for cached pathkeys, selectivity, bucketsize */
1974 1975
	local_node->left_pathkey = NIL;
	local_node->right_pathkey = NIL;
1976 1977
	local_node->left_mergescansel = -1;
	local_node->right_mergescansel = -1;
1978 1979
	local_node->left_bucketsize = -1;
	local_node->right_bucketsize = -1;
1980

1981
	return local_node;
1982 1983 1984
}

/* ----------------
1985
 *		_readJoinInfo()
1986
 *
1987
 *	JoinInfo is a subclass of Node.
1988 1989
 * ----------------
 */
1990
static JoinInfo *
1991
_readJoinInfo(void)
1992
{
1993
	JoinInfo   *local_node;
1994 1995
	char	   *token;
	int			length;
1996

1997
	local_node = makeNode(JoinInfo);
1998

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

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

2005
	return local_node;
2006 2007 2008 2009
}


/* ----------------
2010
 *		parsePlanString
2011 2012 2013 2014
 *
 * Given a character string containing a plan, parsePlanString sets up the
 * plan structure representing that plan.
 *
2015
 * The string to be read must already have been loaded into pg_strtok().
2016 2017
 * ----------------
 */
2018
Node *
2019
parsePlanString(void)
2020
{
2021 2022 2023
	char	   *token;
	int			length;
	void	   *return_value = NULL;
2024

2025
	token = pg_strtok(&length);
2026

2027
	if (length == 4 && strncmp(token, "PLAN", length) == 0)
2028
		return_value = _readPlan();
2029
	else if (length == 6 && strncmp(token, "RESULT", length) == 0)
2030
		return_value = _readResult();
2031
	else if (length == 6 && strncmp(token, "APPEND", length) == 0)
2032
		return_value = _readAppend();
2033
	else if (length == 4 && strncmp(token, "JOIN", length) == 0)
2034
		return_value = _readJoin();
2035
	else if (length == 8 && strncmp(token, "NESTLOOP", length) == 0)
2036
		return_value = _readNestLoop();
2037
	else if (length == 9 && strncmp(token, "MERGEJOIN", length) == 0)
2038
		return_value = _readMergeJoin();
2039
	else if (length == 8 && strncmp(token, "HASHJOIN", length) == 0)
2040
		return_value = _readHashJoin();
2041
	else if (length == 4 && strncmp(token, "SCAN", length) == 0)
2042
		return_value = _readScan();
2043
	else if (length == 7 && strncmp(token, "SEQSCAN", length) == 0)
2044
		return_value = _readSeqScan();
2045
	else if (length == 9 && strncmp(token, "INDEXSCAN", length) == 0)
2046
		return_value = _readIndexScan();
2047
	else if (length == 7 && strncmp(token, "TIDSCAN", length) == 0)
2048
		return_value = _readTidScan();
2049 2050
	else if (length == 12 && strncmp(token, "SUBQUERYSCAN", length) == 0)
		return_value = _readSubqueryScan();
2051 2052
	else if (length == 12 && strncmp(token, "FUNCTIONSCAN", length) == 0)
		return_value = _readFunctionScan();
2053
	else if (length == 4 && strncmp(token, "SORT", length) == 0)
2054
		return_value = _readSort();
2055
	else if (length == 6 && strncmp(token, "AGGREG", length) == 0)
Bruce Momjian's avatar
Bruce Momjian committed
2056
		return_value = _readAggref();
2057
	else if (length == 7 && strncmp(token, "SUBLINK", length) == 0)
2058
		return_value = _readSubLink();
2059 2060
	else if (length == 11 && strncmp(token, "FIELDSELECT", length) == 0)
		return_value = _readFieldSelect();
2061 2062
	else if (length == 11 && strncmp(token, "RELABELTYPE", length) == 0)
		return_value = _readRelabelType();
2063 2064
	else if (length == 11 && strncmp(token, "RANGETBLREF", length) == 0)
		return_value = _readRangeTblRef();
2065 2066
	else if (length == 8 && strncmp(token, "FROMEXPR", length) == 0)
		return_value = _readFromExpr();
2067 2068
	else if (length == 8 && strncmp(token, "JOINEXPR", length) == 0)
		return_value = _readJoinExpr();
2069
	else if (length == 3 && strncmp(token, "AGG", length) == 0)
2070
		return_value = _readAgg();
2071
	else if (length == 4 && strncmp(token, "HASH", length) == 0)
2072
		return_value = _readHash();
2073
	else if (length == 6 && strncmp(token, "RESDOM", length) == 0)
2074
		return_value = _readResdom();
2075
	else if (length == 4 && strncmp(token, "EXPR", length) == 0)
2076
		return_value = _readExpr();
2077
	else if (length == 8 && strncmp(token, "ARRAYREF", length) == 0)
2078
		return_value = _readArrayRef();
2079
	else if (length == 3 && strncmp(token, "VAR", length) == 0)
2080
		return_value = _readVar();
2081
	else if (length == 5 && strncmp(token, "CONST", length) == 0)
2082
		return_value = _readConst();
2083
	else if (length == 4 && strncmp(token, "FUNC", length) == 0)
2084
		return_value = _readFunc();
2085
	else if (length == 4 && strncmp(token, "OPER", length) == 0)
2086
		return_value = _readOper();
2087
	else if (length == 5 && strncmp(token, "PARAM", length) == 0)
2088
		return_value = _readParam();
2089
	else if (length == 11 && strncmp(token, "TARGETENTRY", length) == 0)
2090
		return_value = _readTargetEntry();
2091 2092 2093 2094 2095 2096 2097 2098
	else if (length == 8 && strncmp(token, "RANGEVAR", length) == 0)
		return_value = _readRangeVar();
	else if (length == 9 && strncmp(token, "COLUMNREF", length) == 0)
		return_value = _readColumnRef();
	else if (length == 15 && strncmp(token, "EXPRFIELDSELECT", length) == 0)
		return_value = _readExprFieldSelect();
	else if (length == 5 && strncmp(token, "ALIAS", length) == 0)
		return_value = _readAlias();
2099
	else if (length == 3 && strncmp(token, "RTE", length) == 0)
2100
		return_value = _readRangeTblEntry();
2101
	else if (length == 4 && strncmp(token, "PATH", length) == 0)
2102
		return_value = _readPath();
2103
	else if (length == 9 && strncmp(token, "INDEXPATH", length) == 0)
2104
		return_value = _readIndexPath();
2105
	else if (length == 7 && strncmp(token, "TIDPATH", length) == 0)
2106
		return_value = _readTidPath();
2107 2108
	else if (length == 10 && strncmp(token, "APPENDPATH", length) == 0)
		return_value = _readAppendPath();
2109
	else if (length == 8 && strncmp(token, "NESTPATH", length) == 0)
2110
		return_value = _readNestPath();
2111
	else if (length == 9 && strncmp(token, "MERGEPATH", length) == 0)
2112
		return_value = _readMergePath();
2113
	else if (length == 8 && strncmp(token, "HASHPATH", length) == 0)
2114
		return_value = _readHashPath();
2115
	else if (length == 11 && strncmp(token, "PATHKEYITEM", length) == 0)
2116
		return_value = _readPathKeyItem();
2117
	else if (length == 12 && strncmp(token, "RESTRICTINFO", length) == 0)
2118
		return_value = _readRestrictInfo();
2119
	else if (length == 8 && strncmp(token, "JOININFO", length) == 0)
2120
		return_value = _readJoinInfo();
2121
	else if (length == 5 && strncmp(token, "QUERY", length) == 0)
2122
		return_value = _readQuery();
2123 2124
	else if (length == 6 && strncmp(token, "NOTIFY", length) == 0)
		return_value = _readNotifyStmt();
2125
	else if (length == 10 && strncmp(token, "SORTCLAUSE", length) == 0)
2126
		return_value = _readSortClause();
2127
	else if (length == 11 && strncmp(token, "GROUPCLAUSE", length) == 0)
2128
		return_value = _readGroupClause();
2129 2130
	else if (length == 16 && strncmp(token, "SETOPERATIONSTMT", length) == 0)
		return_value = _readSetOperationStmt();
2131
	else if (length == 4 && strncmp(token, "CASE", length) == 0)
2132
		return_value = _readCaseExpr();
2133
	else if (length == 4 && strncmp(token, "WHEN", length) == 0)
2134
		return_value = _readCaseWhen();
2135 2136 2137 2138
	else if (length == 8 && strncmp(token, "NULLTEST", length) == 0)
		return_value = _readNullTest();
	else if (length == 11 && strncmp(token, "BOOLEANTEST", length) == 0)
		return_value = _readBooleanTest();
2139
	else
2140
		elog(ERROR, "badly formatted planstring \"%.10s\"...", token);
2141

2142
	return (Node *) return_value;
2143
}
2144

2145 2146 2147
/*------------------------------------------------------------*/

/* ----------------
2148
 *		readDatum
2149
 *
2150 2151 2152
 * 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.
2153 2154
 * ----------------
 */
2155
static Datum
2156
readDatum(bool typbyval)
2157
{
2158 2159
	Size		length,
				i;
2160 2161 2162 2163
	int			tokenLength;
	char	   *token;
	Datum		res;
	char	   *s;
2164 2165 2166 2167

	/*
	 * read the actual length of the value
	 */
2168
	token = pg_strtok(&tokenLength);
2169
	length = atoui(token);
2170

2171 2172 2173 2174 2175
	token = pg_strtok(&tokenLength);	/* read the '[' */
	if (token == NULL || token[0] != '[')
		elog(ERROR, "readDatum: expected '%s', got '%s'; length = %lu",
			 "[", token ? (const char *) token : "[NULL]",
			 (unsigned long) length);
2176 2177

	if (typbyval)
2178
	{
2179
		if (length > (Size) sizeof(Datum))
2180 2181
			elog(ERROR, "readDatum: byval & length = %lu",
				 (unsigned long) length);
2182
		res = (Datum) 0;
2183
		s = (char *) (&res);
2184
		for (i = 0; i < (Size) sizeof(Datum); i++)
2185
		{
2186
			token = pg_strtok(&tokenLength);
2187 2188 2189 2190
			s[i] = (char) atoi(token);
		}
	}
	else if (length <= 0)
2191 2192
		res = (Datum) NULL;
	else
2193 2194 2195 2196
	{
		s = (char *) palloc(length);
		for (i = 0; i < length; i++)
		{
2197
			token = pg_strtok(&tokenLength);
2198 2199 2200 2201 2202
			s[i] = (char) atoi(token);
		}
		res = PointerGetDatum(s);
	}

2203
	token = pg_strtok(&tokenLength);	/* read the ']' */
2204
	if (token == NULL || token[0] != ']')
2205 2206
		elog(ERROR, "readDatum: expected '%s', got '%s'; length = %lu",
			 "]", token ? (const char *) token : "[NULL]",
2207
			 (unsigned long) length);
2208

2209
	return res;
2210
}