OSDN Git Service

4d4001d21316e28a50520a4d48d201755cbe7191
[pg-rex/syncrep.git] / src / backend / nodes / readfuncs.c
1 /*-------------------------------------------------------------------------
2  *
3  * readfuncs.c
4  *        Reader functions for Postgres tree nodes.
5  *
6  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
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.131 2002/08/31 22:10:43 tgl Exp $
12  *
13  * NOTES
14  *        Most of the read functions for plan nodes are tested. (In fact, they
15  *        pass the regression test as of 11/8/94.) The rest (for path selection)
16  *        are probably never used. No effort has been made to get them to work.
17  *        The simplest way to test these functions is by doing the following in
18  *        ProcessQuery (before executing the plan):
19  *                              plan = stringToNode(nodeToString(plan));
20  *        Then, run the regression test. Let's just say you'll notice if either
21  *        of the above function are not properly done.
22  *                                                                                                              - ay 11/94
23  *
24  *-------------------------------------------------------------------------
25  */
26 #include "postgres.h"
27
28 #include <math.h>
29
30 #include "nodes/plannodes.h"
31 #include "nodes/readfuncs.h"
32 #include "nodes/relation.h"
33
34
35 /*
36  * NOTE: use atoi() to read values written with %d, or atoui() to read
37  * 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  * but this will probably change in the future.)
40  */
41 #define atoui(x)  ((unsigned int) strtoul((x), NULL, 10))
42
43 #define atooid(x)  ((Oid) strtoul((x), NULL, 10))
44
45 #define strtobool(x)  ((*(x) == 't') ? true : false)
46
47 #define nullable_string(token,length)  \
48         ((length) == 0 ? (char *) NULL : debackslash(token, length))
49
50
51 static Datum readDatum(bool typbyval);
52
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         foreach(l, list)
66         {
67                 Value      *v = (Value *) lfirst(l);
68
69                 if (!IsA(v, Integer))
70                         elog(ERROR, "toIntList: unexpected datatype");
71                 lfirsti(l) = intVal(v);
72                 pfree(v);
73         }
74         return list;
75 }
76
77 /* Convert Value list returned by nodeRead into list of OIDs */
78 static List *
79 toOidList(List *list)
80 {
81         List       *l;
82
83         foreach(l, list)
84         {
85                 Value      *v = (Value *) lfirst(l);
86
87                 /*
88                  * This is a bit tricky because OID is unsigned, and so nodeRead
89                  * might have concluded the value doesn't fit in an integer. Must
90                  * cope with T_Float as well.
91                  */
92                 if (IsA(v, Integer))
93                 {
94                         lfirsti(l) = (Oid) intVal(v);
95                         pfree(v);
96                 }
97                 else if (IsA(v, Float))
98                 {
99                         lfirsti(l) = atooid(strVal(v));
100                         pfree(strVal(v));
101                         pfree(v);
102                 }
103                 else
104                         elog(ERROR, "toOidList: unexpected datatype");
105         }
106         return list;
107 }
108
109 /* ----------------
110  *              _readQuery
111  * ----------------
112  */
113 static Query *
114 _readQuery(void)
115 {
116         Query      *local_node;
117         char       *token;
118         int                     length;
119
120         local_node = makeNode(Query);
121
122         token = pg_strtok(&length); /* skip :command */
123         token = pg_strtok(&length); /* get commandType */
124         local_node->commandType = atoi(token);
125
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         local_node->resultRelation = atoi(token);
132
133         token = pg_strtok(&length); /* skip :into */
134         local_node->into = nodeRead(true);
135
136         token = pg_strtok(&length); /* skip :isPortal */
137         token = pg_strtok(&length); /* get isPortal */
138         local_node->isPortal = strtobool(token);
139
140         token = pg_strtok(&length); /* skip :isBinary */
141         token = pg_strtok(&length); /* get isBinary */
142         local_node->isBinary = strtobool(token);
143
144         token = pg_strtok(&length); /* skip the :hasAggs */
145         token = pg_strtok(&length); /* get hasAggs */
146         local_node->hasAggs = strtobool(token);
147
148         token = pg_strtok(&length); /* skip the :hasSubLinks */
149         token = pg_strtok(&length); /* get hasSubLinks */
150         local_node->hasSubLinks = strtobool(token);
151
152         /* we always want originalQuery to be false in a read-in query */
153         local_node->originalQuery = false;
154
155         token = pg_strtok(&length); /* skip :rtable */
156         local_node->rtable = nodeRead(true);
157
158         token = pg_strtok(&length); /* skip :jointree */
159         local_node->jointree = nodeRead(true);
160
161         token = pg_strtok(&length); /* skip :rowMarks */
162         local_node->rowMarks = toIntList(nodeRead(true));
163
164         token = pg_strtok(&length); /* skip :targetlist */
165         local_node->targetList = nodeRead(true);
166
167         token = pg_strtok(&length); /* skip :groupClause */
168         local_node->groupClause = nodeRead(true);
169
170         token = pg_strtok(&length); /* skip :havingQual */
171         local_node->havingQual = nodeRead(true);
172
173         token = pg_strtok(&length); /* skip :distinctClause */
174         local_node->distinctClause = nodeRead(true);
175
176         token = pg_strtok(&length); /* skip :sortClause */
177         local_node->sortClause = nodeRead(true);
178
179         token = pg_strtok(&length); /* skip :limitOffset */
180         local_node->limitOffset = nodeRead(true);
181
182         token = pg_strtok(&length); /* skip :limitCount */
183         local_node->limitCount = nodeRead(true);
184
185         token = pg_strtok(&length); /* skip :setOperations */
186         local_node->setOperations = nodeRead(true);
187
188         token = pg_strtok(&length); /* skip :resultRelations */
189         local_node->resultRelations = toIntList(nodeRead(true));
190
191         return local_node;
192 }
193
194 /* ----------------
195  *              _readNotifyStmt
196  * ----------------
197  */
198 static NotifyStmt *
199 _readNotifyStmt(void)
200 {
201         NotifyStmt *local_node;
202         char       *token;
203         int                     length;
204
205         local_node = makeNode(NotifyStmt);
206
207         token = pg_strtok(&length); /* skip :relation */
208         local_node->relation = nodeRead(true);
209
210         return local_node;
211 }
212
213 /* ----------------
214  *              _readSortClause
215  * ----------------
216  */
217 static SortClause *
218 _readSortClause(void)
219 {
220         SortClause *local_node;
221         char       *token;
222         int                     length;
223
224         local_node = makeNode(SortClause);
225
226         token = pg_strtok(&length); /* skip :tleSortGroupRef */
227         token = pg_strtok(&length); /* get tleSortGroupRef */
228         local_node->tleSortGroupRef = atoui(token);
229
230         token = pg_strtok(&length); /* skip :sortop */
231         token = pg_strtok(&length); /* get sortop */
232         local_node->sortop = atooid(token);
233
234         return local_node;
235 }
236
237 /* ----------------
238  *              _readGroupClause
239  * ----------------
240  */
241 static GroupClause *
242 _readGroupClause(void)
243 {
244         GroupClause *local_node;
245         char       *token;
246         int                     length;
247
248         local_node = makeNode(GroupClause);
249
250         token = pg_strtok(&length); /* skip :tleSortGroupRef */
251         token = pg_strtok(&length); /* get tleSortGroupRef */
252         local_node->tleSortGroupRef = atoui(token);
253
254         token = pg_strtok(&length); /* skip :sortop */
255         token = pg_strtok(&length); /* get sortop */
256         local_node->sortop = atooid(token);
257
258         return local_node;
259 }
260
261 /* ----------------
262  *              _readSetOperationStmt
263  * ----------------
264  */
265 static SetOperationStmt *
266 _readSetOperationStmt(void)
267 {
268         SetOperationStmt *local_node;
269         char       *token;
270         int                     length;
271
272         local_node = makeNode(SetOperationStmt);
273
274         token = pg_strtok(&length); /* eat :op */
275         token = pg_strtok(&length); /* get op */
276         local_node->op = (SetOperation) atoi(token);
277
278         token = pg_strtok(&length); /* eat :all */
279         token = pg_strtok(&length); /* get all */
280         local_node->all = strtobool(token);
281
282         token = pg_strtok(&length); /* eat :larg */
283         local_node->larg = nodeRead(true);      /* get larg */
284
285         token = pg_strtok(&length); /* eat :rarg */
286         local_node->rarg = nodeRead(true);      /* get rarg */
287
288         token = pg_strtok(&length); /* eat :colTypes */
289         local_node->colTypes = toOidList(nodeRead(true));
290
291         return local_node;
292 }
293
294 /* ----------------
295  *              _getPlan
296  * ----------------
297  */
298 static void
299 _getPlan(Plan *node)
300 {
301         char       *token;
302         int                     length;
303
304         token = pg_strtok(&length); /* first token is :startup_cost */
305         token = pg_strtok(&length); /* next is the actual cost */
306         node->startup_cost = (Cost) atof(token);
307
308         token = pg_strtok(&length); /* skip the :total_cost */
309         token = pg_strtok(&length); /* next is the actual cost */
310         node->total_cost = (Cost) atof(token);
311
312         token = pg_strtok(&length); /* skip the :rows */
313         token = pg_strtok(&length); /* get the plan_rows */
314         node->plan_rows = atof(token);
315
316         token = pg_strtok(&length); /* skip the :width */
317         token = pg_strtok(&length); /* get the plan_width */
318         node->plan_width = atoi(token);
319
320         token = pg_strtok(&length); /* eat :qptargetlist */
321         node->targetlist = nodeRead(true);
322
323         token = pg_strtok(&length); /* eat :qpqual */
324         node->qual = nodeRead(true);
325
326         token = pg_strtok(&length); /* eat :lefttree */
327         node->lefttree = (Plan *) nodeRead(true);
328
329         token = pg_strtok(&length); /* eat :righttree */
330         node->righttree = (Plan *) nodeRead(true);
331
332         node->state = (EState *) NULL;          /* never read in */
333
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         local_node = makeNode(Plan);
351
352         _getPlan(local_node);
353
354         return local_node;
355 }
356
357 /* ----------------
358  *              _readResult
359  * ----------------
360  */
361 static Result *
362 _readResult(void)
363 {
364         Result     *local_node;
365         char       *token;
366         int                     length;
367
368         local_node = makeNode(Result);
369
370         _getPlan((Plan *) local_node);
371
372         token = pg_strtok(&length); /* eat :resconstantqual */
373         local_node->resconstantqual = nodeRead(true);           /* now read it */
374
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         Append     *local_node;
389         char       *token;
390         int                     length;
391
392         local_node = makeNode(Append);
393
394         _getPlan((Plan *) local_node);
395
396         token = pg_strtok(&length); /* eat :appendplans */
397         local_node->appendplans = nodeRead(true);       /* now read it */
398
399         token = pg_strtok(&length); /* eat :isTarget */
400         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         char       *token;
414         int                     length;
415
416         _getPlan((Plan *) node);
417
418         token = pg_strtok(&length); /* skip the :jointype */
419         token = pg_strtok(&length); /* get the jointype */
420         node->jointype = (JoinType) atoi(token);
421
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         local_node = makeNode(Join);
439
440         _getJoin(local_node);
441
442         return local_node;
443 }
444
445 /* ----------------
446  *              _readNestLoop
447  *
448  *      NestLoop is a subclass of Join
449  * ----------------
450  */
451
452 static NestLoop *
453 _readNestLoop(void)
454 {
455         NestLoop   *local_node;
456
457         local_node = makeNode(NestLoop);
458
459         _getJoin((Join *) local_node);
460
461         return local_node;
462 }
463
464 /* ----------------
465  *              _readMergeJoin
466  *
467  *      MergeJoin is a subclass of Join
468  * ----------------
469  */
470 static MergeJoin *
471 _readMergeJoin(void)
472 {
473         MergeJoin  *local_node;
474         char       *token;
475         int                     length;
476
477         local_node = makeNode(MergeJoin);
478
479         _getJoin((Join *) local_node);
480
481         token = pg_strtok(&length); /* eat :mergeclauses */
482         local_node->mergeclauses = nodeRead(true);      /* now read it */
483
484         return local_node;
485 }
486
487 /* ----------------
488  *              _readHashJoin
489  *
490  *      HashJoin is a subclass of Join.
491  * ----------------
492  */
493 static HashJoin *
494 _readHashJoin(void)
495 {
496         HashJoin   *local_node;
497         char       *token;
498         int                     length;
499
500         local_node = makeNode(HashJoin);
501
502         _getJoin((Join *) local_node);
503
504         token = pg_strtok(&length); /* eat :hashclauses */
505         local_node->hashclauses = nodeRead(true);       /* now read it */
506
507         token = pg_strtok(&length); /* eat :hashjoinop */
508         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         char       *token;
526         int                     length;
527
528         _getPlan((Plan *) node);
529
530         token = pg_strtok(&length); /* eat :scanrelid */
531         token = pg_strtok(&length); /* get scanrelid */
532         node->scanrelid = atoui(token);
533 }
534
535 /* ----------------
536  *              _readScan
537  *
538  * Scan is a subclass of Plan.
539  * ----------------
540  */
541 static Scan *
542 _readScan(void)
543 {
544         Scan       *local_node;
545
546         local_node = makeNode(Scan);
547
548         _getScan(local_node);
549
550         return local_node;
551 }
552
553 /* ----------------
554  *              _readSeqScan
555  *
556  *      SeqScan is a subclass of Scan
557  * ----------------
558  */
559 static SeqScan *
560 _readSeqScan(void)
561 {
562         SeqScan    *local_node;
563
564         local_node = makeNode(SeqScan);
565
566         _getScan((Scan *) local_node);
567
568         return local_node;
569 }
570
571 /* ----------------
572  *              _readIndexScan
573  *
574  *      IndexScan is a subclass of Scan
575  * ----------------
576  */
577 static IndexScan *
578 _readIndexScan(void)
579 {
580         IndexScan  *local_node;
581         char       *token;
582         int                     length;
583
584         local_node = makeNode(IndexScan);
585
586         _getScan((Scan *) local_node);
587
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         local_node->indxqual = nodeRead(true);          /* now read it */
593
594         token = pg_strtok(&length); /* eat :indxqualorig */
595         local_node->indxqualorig = nodeRead(true);      /* now read it */
596
597         token = pg_strtok(&length); /* eat :indxorderdir */
598         token = pg_strtok(&length); /* get indxorderdir */
599         local_node->indxorderdir = atoi(token);
600
601         return local_node;
602 }
603
604 /* ----------------
605  *              _readTidScan
606  *
607  *      TidScan is a subclass of Scan
608  * ----------------
609  */
610 static TidScan *
611 _readTidScan(void)
612 {
613         TidScan    *local_node;
614         char       *token;
615         int                     length;
616
617         local_node = makeNode(TidScan);
618
619         _getScan((Scan *) local_node);
620
621         token = pg_strtok(&length); /* eat :needrescan */
622         token = pg_strtok(&length); /* get needrescan */
623         local_node->needRescan = atoi(token);
624
625         token = pg_strtok(&length); /* eat :tideval */
626         local_node->tideval = nodeRead(true);           /* now read it */
627
628         return local_node;
629 }
630
631 /* ----------------
632  *              _readSubqueryScan
633  *
634  *      SubqueryScan is a subclass of Scan
635  * ----------------
636  */
637 static SubqueryScan *
638 _readSubqueryScan(void)
639 {
640         SubqueryScan *local_node;
641         char       *token;
642         int                     length;
643
644         local_node = makeNode(SubqueryScan);
645
646         _getScan((Scan *) local_node);
647
648         token = pg_strtok(&length); /* eat :subplan */
649         local_node->subplan = nodeRead(true);           /* now read it */
650
651         return local_node;
652 }
653
654 /* ----------------
655  *              _readFunctionScan
656  *
657  *      FunctionScan is a subclass of Scan
658  * ----------------
659  */
660 static FunctionScan *
661 _readFunctionScan(void)
662 {
663         FunctionScan *local_node;
664
665         local_node = makeNode(FunctionScan);
666
667         _getScan((Scan *) local_node);
668
669         return local_node;
670 }
671
672 /* ----------------
673  *              _readSort
674  *
675  *      Sort is a subclass of Plan
676  * ----------------
677  */
678 static Sort *
679 _readSort(void)
680 {
681         Sort       *local_node;
682         char       *token;
683         int                     length;
684
685         local_node = makeNode(Sort);
686
687         _getPlan((Plan *) local_node);
688
689         token = pg_strtok(&length); /* eat :keycount */
690         token = pg_strtok(&length); /* get keycount */
691         local_node->keycount = atoi(token);
692
693         return local_node;
694 }
695
696 static Agg *
697 _readAgg(void)
698 {
699         Agg                *local_node;
700
701         local_node = makeNode(Agg);
702         _getPlan((Plan *) local_node);
703
704         return local_node;
705 }
706
707 /* ----------------
708  *              _readHash
709  *
710  *      Hash is a subclass of Plan
711  * ----------------
712  */
713 static Hash *
714 _readHash(void)
715 {
716         Hash       *local_node;
717         char       *token;
718         int                     length;
719
720         local_node = makeNode(Hash);
721
722         _getPlan((Plan *) local_node);
723
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  *              _readResdom
736  *
737  *      Resdom is a subclass of Node
738  * ----------------
739  */
740 static Resdom *
741 _readResdom(void)
742 {
743         Resdom     *local_node;
744         char       *token;
745         int                     length;
746
747         local_node = makeNode(Resdom);
748
749         token = pg_strtok(&length); /* eat :resno */
750         token = pg_strtok(&length); /* get resno */
751         local_node->resno = atoi(token);
752
753         token = pg_strtok(&length); /* eat :restype */
754         token = pg_strtok(&length); /* get restype */
755         local_node->restype = atooid(token);
756
757         token = pg_strtok(&length); /* eat :restypmod */
758         token = pg_strtok(&length); /* get restypmod */
759         local_node->restypmod = atoi(token);
760
761         token = pg_strtok(&length); /* eat :resname */
762         token = pg_strtok(&length); /* get the name */
763         local_node->resname = nullable_string(token, length);
764
765         token = pg_strtok(&length); /* eat :reskey */
766         token = pg_strtok(&length); /* get reskey */
767         local_node->reskey = atoui(token);
768
769         token = pg_strtok(&length); /* eat :reskeyop */
770         token = pg_strtok(&length); /* get reskeyop */
771         local_node->reskeyop = atooid(token);
772
773         token = pg_strtok(&length); /* eat :ressortgroupref */
774         token = pg_strtok(&length); /* get ressortgroupref */
775         local_node->ressortgroupref = atoui(token);
776
777         token = pg_strtok(&length); /* eat :resjunk */
778         token = pg_strtok(&length); /* get resjunk */
779         local_node->resjunk = strtobool(token);
780
781         return local_node;
782 }
783
784 /* ----------------
785  *              _readExpr
786  *
787  *      Expr is a subclass of Node
788  * ----------------
789  */
790 static Expr *
791 _readExpr(void)
792 {
793         Expr       *local_node;
794         char       *token;
795         int                     length;
796
797         local_node = makeNode(Expr);
798
799         token = pg_strtok(&length); /* eat :typeOid */
800         token = pg_strtok(&length); /* get typeOid */
801         local_node->typeOid = atooid(token);
802
803         token = pg_strtok(&length); /* eat :opType */
804         token = pg_strtok(&length); /* get opType */
805         if (strncmp(token, "op", 2) == 0)
806                 local_node->opType = OP_EXPR;
807         else if (strncmp(token, "distinct", 8) == 0)
808                 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)
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         local_node->oper = nodeRead(true);
824
825         token = pg_strtok(&length); /* eat :args */
826         local_node->args = nodeRead(true);      /* now read it */
827
828         return local_node;
829 }
830
831 /* ----------------
832  *              _readCaseExpr
833  *
834  *      CaseExpr is a subclass of Node
835  * ----------------
836  */
837 static CaseExpr *
838 _readCaseExpr(void)
839 {
840         CaseExpr   *local_node;
841         char       *token;
842         int                     length;
843
844         local_node = makeNode(CaseExpr);
845
846         token = pg_strtok(&length); /* eat :casetype */
847         token = pg_strtok(&length); /* get casetype */
848         local_node->casetype = atooid(token);
849
850         token = pg_strtok(&length); /* eat :arg */
851         local_node->arg = nodeRead(true);
852
853         token = pg_strtok(&length); /* eat :args */
854         local_node->args = nodeRead(true);
855
856         token = pg_strtok(&length); /* eat :defresult */
857         local_node->defresult = nodeRead(true);
858
859         return local_node;
860 }
861
862 /* ----------------
863  *              _readCaseWhen
864  *
865  *      CaseWhen is a subclass of Node
866  * ----------------
867  */
868 static CaseWhen *
869 _readCaseWhen(void)
870 {
871         CaseWhen   *local_node;
872         char       *token;
873         int                     length;
874
875         local_node = makeNode(CaseWhen);
876
877         local_node->expr = nodeRead(true);
878         token = pg_strtok(&length); /* eat :then */
879         local_node->result = nodeRead(true);
880
881         return local_node;
882 }
883
884 /* ----------------
885  *              _readNullTest
886  *
887  *      NullTest is a subclass of Node
888  * ----------------
889  */
890 static NullTest *
891 _readNullTest(void)
892 {
893         NullTest   *local_node;
894         char       *token;
895         int                     length;
896
897         local_node = makeNode(NullTest);
898
899         token = pg_strtok(&length); /* eat :arg */
900         local_node->arg = nodeRead(true);       /* now read it */
901
902         token = pg_strtok(&length); /* eat :nulltesttype */
903         token = pg_strtok(&length); /* get nulltesttype */
904         local_node->nulltesttype = (NullTestType) atoi(token);
905
906         return local_node;
907 }
908
909 /* ----------------
910  *              _readBooleanTest
911  *
912  *      BooleanTest is a subclass of Node
913  * ----------------
914  */
915 static BooleanTest *
916 _readBooleanTest(void)
917 {
918         BooleanTest *local_node;
919         char       *token;
920         int                     length;
921
922         local_node = makeNode(BooleanTest);
923
924         token = pg_strtok(&length); /* eat :arg */
925         local_node->arg = nodeRead(true);       /* now read it */
926
927         token = pg_strtok(&length); /* eat :booltesttype */
928         token = pg_strtok(&length); /* get booltesttype */
929         local_node->booltesttype = (BoolTestType) atoi(token);
930
931         return local_node;
932 }
933
934 /* ----------------
935  *              _readConstraintTest
936  *
937  *      ConstraintTest is a subclass of Node
938  * ----------------
939  */
940 static ConstraintTest *
941 _readConstraintTest(void)
942 {
943         ConstraintTest *local_node;
944         char       *token;
945         int                     length;
946
947         local_node = makeNode(ConstraintTest);
948
949         token = pg_strtok(&length); /* eat :arg */
950         local_node->arg = nodeRead(true);       /* now read it */
951
952         token = pg_strtok(&length); /* eat :testtype */
953         token = pg_strtok(&length); /* get testtype */
954         local_node->testtype = (ConstraintTestType) atoi(token);
955
956         token = pg_strtok(&length); /* get :name */
957         token = pg_strtok(&length); /* now read it */
958         local_node->name = nullable_string(token, length);
959
960         token = pg_strtok(&length); /* eat :check_expr */
961         local_node->check_expr = nodeRead(true);        /* now read it */
962
963         return local_node;
964 }
965
966 /* ----------------
967  *              _readVar
968  *
969  *      Var is a subclass of Expr
970  * ----------------
971  */
972 static Var *
973 _readVar(void)
974 {
975         Var                *local_node;
976         char       *token;
977         int                     length;
978
979         local_node = makeNode(Var);
980
981         token = pg_strtok(&length); /* eat :varno */
982         token = pg_strtok(&length); /* get varno */
983         local_node->varno = atoui(token);
984
985         token = pg_strtok(&length); /* eat :varattno */
986         token = pg_strtok(&length); /* get varattno */
987         local_node->varattno = atoi(token);
988
989         token = pg_strtok(&length); /* eat :vartype */
990         token = pg_strtok(&length); /* get vartype */
991         local_node->vartype = atooid(token);
992
993         token = pg_strtok(&length); /* eat :vartypmod */
994         token = pg_strtok(&length); /* get vartypmod */
995         local_node->vartypmod = atoi(token);
996
997         token = pg_strtok(&length); /* eat :varlevelsup */
998         token = pg_strtok(&length); /* get varlevelsup */
999         local_node->varlevelsup = atoui(token);
1000
1001         token = pg_strtok(&length); /* eat :varnoold */
1002         token = pg_strtok(&length); /* get varnoold */
1003         local_node->varnoold = atoui(token);
1004
1005         token = pg_strtok(&length); /* eat :varoattno */
1006         token = pg_strtok(&length); /* eat :varoattno */
1007         local_node->varoattno = atoi(token);
1008
1009         return local_node;
1010 }
1011
1012 /* ----------------
1013  * _readArrayRef
1014  *
1015  * ArrayRef is a subclass of Expr
1016  * ----------------
1017  */
1018 static ArrayRef *
1019 _readArrayRef(void)
1020 {
1021         ArrayRef   *local_node;
1022         char       *token;
1023         int                     length;
1024
1025         local_node = makeNode(ArrayRef);
1026
1027         token = pg_strtok(&length); /* eat :refrestype */
1028         token = pg_strtok(&length); /* get refrestype */
1029         local_node->refrestype = atooid(token);
1030
1031         token = pg_strtok(&length); /* eat :refattrlength */
1032         token = pg_strtok(&length); /* get refattrlength */
1033         local_node->refattrlength = atoi(token);
1034
1035         token = pg_strtok(&length); /* eat :refelemlength */
1036         token = pg_strtok(&length); /* get refelemlength */
1037         local_node->refelemlength = atoi(token);
1038
1039         token = pg_strtok(&length); /* eat :refelembyval */
1040         token = pg_strtok(&length); /* get refelembyval */
1041         local_node->refelembyval = strtobool(token);
1042
1043         token = pg_strtok(&length); /* eat :refelemalign */
1044         token = pg_strtok(&length); /* get refelemalign */
1045         local_node->refelemalign = token[0];
1046
1047         token = pg_strtok(&length); /* eat :refupperindexpr */
1048         local_node->refupperindexpr = nodeRead(true);
1049
1050         token = pg_strtok(&length); /* eat :reflowerindexpr */
1051         local_node->reflowerindexpr = nodeRead(true);
1052
1053         token = pg_strtok(&length); /* eat :refexpr */
1054         local_node->refexpr = nodeRead(true);
1055
1056         token = pg_strtok(&length); /* eat :refassgnexpr */
1057         local_node->refassgnexpr = nodeRead(true);
1058
1059         return local_node;
1060 }
1061
1062 /* ----------------
1063  *              _readConst
1064  *
1065  *      Const is a subclass of Expr
1066  * ----------------
1067  */
1068 static Const *
1069 _readConst(void)
1070 {
1071         Const      *local_node;
1072         char       *token;
1073         int                     length;
1074
1075         local_node = makeNode(Const);
1076
1077         token = pg_strtok(&length); /* get :consttype */
1078         token = pg_strtok(&length); /* now read it */
1079         local_node->consttype = atooid(token);
1080
1081         token = pg_strtok(&length); /* get :constlen */
1082         token = pg_strtok(&length); /* now read it */
1083         local_node->constlen = atoi(token);
1084
1085         token = pg_strtok(&length); /* get :constbyval */
1086         token = pg_strtok(&length); /* now read it */
1087         local_node->constbyval = strtobool(token);
1088
1089         token = pg_strtok(&length); /* get :constisnull */
1090         token = pg_strtok(&length); /* now read it */
1091         local_node->constisnull = strtobool(token);
1092
1093         token = pg_strtok(&length); /* get :constvalue */
1094
1095         if (local_node->constisnull)
1096         {
1097                 token = pg_strtok(&length);             /* skip "NIL" */
1098         }
1099         else
1100                 local_node->constvalue = readDatum(local_node->constbyval);
1101
1102         return local_node;
1103 }
1104
1105 /* ----------------
1106  *              _readFunc
1107  *
1108  *      Func is a subclass of Expr
1109  * ----------------
1110  */
1111 static Func *
1112 _readFunc(void)
1113 {
1114         Func       *local_node;
1115         char       *token;
1116         int                     length;
1117
1118         local_node = makeNode(Func);
1119
1120         token = pg_strtok(&length); /* get :funcid */
1121         token = pg_strtok(&length); /* now read it */
1122         local_node->funcid = atooid(token);
1123
1124         token = pg_strtok(&length); /* get :funcresulttype */
1125         token = pg_strtok(&length); /* now read it */
1126         local_node->funcresulttype = atooid(token);
1127
1128         token = pg_strtok(&length); /* get :funcretset */
1129         token = pg_strtok(&length); /* now read it */
1130         local_node->funcretset = strtobool(token);
1131
1132         local_node->func_fcache = NULL;
1133
1134         return local_node;
1135 }
1136
1137 /* ----------------
1138  *              _readOper
1139  *
1140  *      Oper is a subclass of Expr
1141  * ----------------
1142  */
1143 static Oper *
1144 _readOper(void)
1145 {
1146         Oper       *local_node;
1147         char       *token;
1148         int                     length;
1149
1150         local_node = makeNode(Oper);
1151
1152         token = pg_strtok(&length); /* get :opno */
1153         token = pg_strtok(&length); /* now read it */
1154         local_node->opno = atooid(token);
1155
1156         token = pg_strtok(&length); /* get :opid */
1157         token = pg_strtok(&length); /* now read it */
1158         local_node->opid = atooid(token);
1159
1160         token = pg_strtok(&length); /* get :opresulttype */
1161         token = pg_strtok(&length); /* now read it */
1162         local_node->opresulttype = atooid(token);
1163
1164         token = pg_strtok(&length); /* get :opretset */
1165         token = pg_strtok(&length); /* now read it */
1166         local_node->opretset = strtobool(token);
1167
1168         local_node->op_fcache = NULL;
1169
1170         return local_node;
1171 }
1172
1173 /* ----------------
1174  *              _readParam
1175  *
1176  *      Param is a subclass of Expr
1177  * ----------------
1178  */
1179 static Param *
1180 _readParam(void)
1181 {
1182         Param      *local_node;
1183         char       *token;
1184         int                     length;
1185
1186         local_node = makeNode(Param);
1187
1188         token = pg_strtok(&length); /* get :paramkind */
1189         token = pg_strtok(&length); /* now read it */
1190         local_node->paramkind = atoi(token);
1191
1192         token = pg_strtok(&length); /* get :paramid */
1193         token = pg_strtok(&length); /* now read it */
1194         local_node->paramid = atoi(token);
1195
1196         token = pg_strtok(&length); /* get :paramname */
1197         token = pg_strtok(&length); /* now read it */
1198         local_node->paramname = nullable_string(token, length);
1199
1200         token = pg_strtok(&length); /* get :paramtype */
1201         token = pg_strtok(&length); /* now read it */
1202         local_node->paramtype = atooid(token);
1203
1204         return local_node;
1205 }
1206
1207 /* ----------------
1208  *              _readAggref
1209  *
1210  *      Aggref is a subclass of Node
1211  * ----------------
1212  */
1213 static Aggref *
1214 _readAggref(void)
1215 {
1216         Aggref     *local_node;
1217         char       *token;
1218         int                     length;
1219
1220         local_node = makeNode(Aggref);
1221
1222         token = pg_strtok(&length); /* eat :aggfnoid */
1223         token = pg_strtok(&length); /* get aggfnoid */
1224         local_node->aggfnoid = atooid(token);
1225
1226         token = pg_strtok(&length); /* eat :aggtype */
1227         token = pg_strtok(&length); /* get aggtype */
1228         local_node->aggtype = atooid(token);
1229
1230         token = pg_strtok(&length); /* eat :target */
1231         local_node->target = nodeRead(true);            /* now read it */
1232
1233         token = pg_strtok(&length); /* eat :aggstar */
1234         token = pg_strtok(&length); /* get aggstar */
1235         local_node->aggstar = strtobool(token);
1236
1237         token = pg_strtok(&length); /* eat :aggdistinct */
1238         token = pg_strtok(&length); /* get aggdistinct */
1239         local_node->aggdistinct = strtobool(token);
1240
1241         return local_node;
1242 }
1243
1244 /* ----------------
1245  *              _readSubLink
1246  *
1247  *      SubLink is a subclass of Node
1248  * ----------------
1249  */
1250 static SubLink *
1251 _readSubLink(void)
1252 {
1253         SubLink    *local_node;
1254         char       *token;
1255         int                     length;
1256
1257         local_node = makeNode(SubLink);
1258
1259         token = pg_strtok(&length); /* eat :subLinkType */
1260         token = pg_strtok(&length); /* get subLinkType */
1261         local_node->subLinkType = atoi(token);
1262
1263         token = pg_strtok(&length); /* eat :useor */
1264         token = pg_strtok(&length); /* get useor */
1265         local_node->useor = strtobool(token);
1266
1267         token = pg_strtok(&length); /* eat :lefthand */
1268         local_node->lefthand = nodeRead(true);          /* now read it */
1269
1270         token = pg_strtok(&length); /* eat :oper */
1271         local_node->oper = nodeRead(true);      /* now read it */
1272
1273         token = pg_strtok(&length); /* eat :subselect */
1274         local_node->subselect = nodeRead(true);         /* now read it */
1275
1276         return local_node;
1277 }
1278
1279 /* ----------------
1280  *              _readFieldSelect
1281  *
1282  *      FieldSelect is a subclass of Node
1283  * ----------------
1284  */
1285 static FieldSelect *
1286 _readFieldSelect(void)
1287 {
1288         FieldSelect *local_node;
1289         char       *token;
1290         int                     length;
1291
1292         local_node = makeNode(FieldSelect);
1293
1294         token = pg_strtok(&length); /* eat :arg */
1295         local_node->arg = nodeRead(true);       /* now read it */
1296
1297         token = pg_strtok(&length); /* eat :fieldnum */
1298         token = pg_strtok(&length); /* get fieldnum */
1299         local_node->fieldnum = (AttrNumber) atoi(token);
1300
1301         token = pg_strtok(&length); /* eat :resulttype */
1302         token = pg_strtok(&length); /* get resulttype */
1303         local_node->resulttype = atooid(token);
1304
1305         token = pg_strtok(&length); /* eat :resulttypmod */
1306         token = pg_strtok(&length); /* get resulttypmod */
1307         local_node->resulttypmod = atoi(token);
1308
1309         return local_node;
1310 }
1311
1312 /* ----------------
1313  *              _readRelabelType
1314  *
1315  *      RelabelType is a subclass of Node
1316  * ----------------
1317  */
1318 static RelabelType *
1319 _readRelabelType(void)
1320 {
1321         RelabelType *local_node;
1322         char       *token;
1323         int                     length;
1324
1325         local_node = makeNode(RelabelType);
1326
1327         token = pg_strtok(&length); /* eat :arg */
1328         local_node->arg = nodeRead(true);       /* now read it */
1329
1330         token = pg_strtok(&length); /* eat :resulttype */
1331         token = pg_strtok(&length); /* get resulttype */
1332         local_node->resulttype = atooid(token);
1333
1334         token = pg_strtok(&length); /* eat :resulttypmod */
1335         token = pg_strtok(&length); /* get resulttypmod */
1336         local_node->resulttypmod = atoi(token);
1337
1338         return local_node;
1339 }
1340
1341 /* ----------------
1342  *              _readRangeTblRef
1343  *
1344  *      RangeTblRef is a subclass of Node
1345  * ----------------
1346  */
1347 static RangeTblRef *
1348 _readRangeTblRef(void)
1349 {
1350         RangeTblRef *local_node;
1351         char       *token;
1352         int                     length;
1353
1354         local_node = makeNode(RangeTblRef);
1355
1356         token = pg_strtok(&length); /* get rtindex */
1357         local_node->rtindex = atoi(token);
1358
1359         return local_node;
1360 }
1361
1362 /* ----------------
1363  *              _readFromExpr
1364  *
1365  *      FromExpr is a subclass of Node
1366  * ----------------
1367  */
1368 static FromExpr *
1369 _readFromExpr(void)
1370 {
1371         FromExpr   *local_node;
1372         char       *token;
1373         int                     length;
1374
1375         local_node = makeNode(FromExpr);
1376
1377         token = pg_strtok(&length); /* eat :fromlist */
1378         local_node->fromlist = nodeRead(true);          /* now read it */
1379
1380         token = pg_strtok(&length); /* eat :quals */
1381         local_node->quals = nodeRead(true); /* now read it */
1382
1383         return local_node;
1384 }
1385
1386 /* ----------------
1387  *              _readJoinExpr
1388  *
1389  *      JoinExpr is a subclass of Node
1390  * ----------------
1391  */
1392 static JoinExpr *
1393 _readJoinExpr(void)
1394 {
1395         JoinExpr   *local_node;
1396         char       *token;
1397         int                     length;
1398
1399         local_node = makeNode(JoinExpr);
1400
1401         token = pg_strtok(&length); /* eat :jointype */
1402         token = pg_strtok(&length); /* get jointype */
1403         local_node->jointype = (JoinType) atoi(token);
1404
1405         token = pg_strtok(&length); /* eat :isNatural */
1406         token = pg_strtok(&length); /* get isNatural */
1407         local_node->isNatural = strtobool(token);
1408
1409         token = pg_strtok(&length); /* eat :larg */
1410         local_node->larg = nodeRead(true);      /* now read it */
1411
1412         token = pg_strtok(&length); /* eat :rarg */
1413         local_node->rarg = nodeRead(true);      /* now read it */
1414
1415         token = pg_strtok(&length); /* eat :using */
1416         local_node->using = nodeRead(true); /* now read it */
1417
1418         token = pg_strtok(&length); /* eat :quals */
1419         local_node->quals = nodeRead(true); /* now read it */
1420
1421         token = pg_strtok(&length); /* eat :alias */
1422         local_node->alias = nodeRead(true); /* now read it */
1423
1424         token = pg_strtok(&length); /* eat :rtindex */
1425         token = pg_strtok(&length); /* get rtindex */
1426         local_node->rtindex = atoi(token);
1427
1428         return local_node;
1429 }
1430
1431 /* ----------------
1432  *              _readTargetEntry
1433  * ----------------
1434  */
1435 static TargetEntry *
1436 _readTargetEntry(void)
1437 {
1438         TargetEntry *local_node;
1439         char       *token;
1440         int                     length;
1441
1442         local_node = makeNode(TargetEntry);
1443
1444         token = pg_strtok(&length); /* get :resdom */
1445         local_node->resdom = nodeRead(true);            /* now read it */
1446
1447         token = pg_strtok(&length); /* get :expr */
1448         local_node->expr = nodeRead(true);      /* now read it */
1449
1450         return local_node;
1451 }
1452
1453 static RangeVar *
1454 _readRangeVar(void)
1455 {
1456         RangeVar   *local_node;
1457         char       *token;
1458         int                     length;
1459
1460         local_node = makeNode(RangeVar);
1461
1462         local_node->catalogname = NULL; /* not currently saved in output format */
1463
1464         token = pg_strtok(&length); /* eat :relation */
1465         token = pg_strtok(&length); /* get schemaname */
1466         local_node->schemaname = nullable_string(token, length);
1467
1468         token = pg_strtok(&length); /* eat "." */
1469         token = pg_strtok(&length); /* get relname */
1470         local_node->relname = nullable_string(token, length);
1471         
1472         token = pg_strtok(&length); /* eat :inhopt */
1473         token = pg_strtok(&length); /* get inhopt */
1474         local_node->inhOpt = (InhOption) atoi(token);
1475         
1476         token = pg_strtok(&length); /* eat :istemp */
1477         token = pg_strtok(&length); /* get istemp */
1478         local_node->istemp = strtobool(token);
1479
1480         token = pg_strtok(&length); /* eat :alias */
1481         local_node->alias = nodeRead(true); /* now read it */
1482
1483         return local_node;
1484 }
1485
1486 static ColumnRef *
1487 _readColumnRef(void)
1488 {
1489         ColumnRef  *local_node;
1490         char       *token;
1491         int                     length;
1492
1493         local_node = makeNode(ColumnRef);
1494
1495         token = pg_strtok(&length); /* eat :fields */
1496         local_node->fields = nodeRead(true); /* now read it */
1497
1498         token = pg_strtok(&length); /* eat :indirection */
1499         local_node->indirection = nodeRead(true); /* now read it */
1500
1501         return local_node;
1502 }
1503
1504 static ColumnDef *
1505 _readColumnDef(void)
1506 {
1507         ColumnDef  *local_node;
1508         char       *token;
1509         int                     length;
1510
1511         local_node = makeNode(ColumnDef);
1512
1513         token = pg_strtok(&length); /* eat :colname */
1514         token = pg_strtok(&length); /* now read it */
1515         local_node->colname = nullable_string(token, length);
1516
1517         token = pg_strtok(&length); /* eat :typename */
1518         local_node->typename = nodeRead(true); /* now read it */
1519
1520         token = pg_strtok(&length); /* eat :is_inherited */
1521         token = pg_strtok(&length); /* get :is_inherited */
1522         local_node->is_inherited = strtobool(token);
1523
1524         token = pg_strtok(&length); /* eat :is_not_null */
1525         token = pg_strtok(&length); /* get :is_not_null */
1526         local_node->is_not_null = strtobool(token);
1527
1528         token = pg_strtok(&length); /* eat :raw_default */
1529         local_node->raw_default = nodeRead(true); /* now read it */
1530
1531         token = pg_strtok(&length); /* eat :cooked_default */
1532         token = pg_strtok(&length); /* now read it */
1533         local_node->cooked_default = nullable_string(token, length);
1534
1535         token = pg_strtok(&length); /* eat :constraints */
1536         local_node->constraints = nodeRead(true);       /* now read it */
1537
1538         token = pg_strtok(&length); /* eat :support */
1539         local_node->support = nodeRead(true); /* now read it */
1540
1541         return local_node;
1542 }
1543
1544 static TypeName *
1545 _readTypeName(void)
1546 {
1547         TypeName  *local_node;
1548         char       *token;
1549         int                     length;
1550
1551         local_node = makeNode(TypeName);
1552
1553         token = pg_strtok(&length); /* eat :names */
1554         local_node->names = nodeRead(true); /* now read it */
1555
1556         token = pg_strtok(&length); /* eat :typeid */
1557         token = pg_strtok(&length); /* get typeid */
1558         local_node->typeid = atooid(token);
1559
1560         token = pg_strtok(&length); /* eat :timezone */
1561         token = pg_strtok(&length); /* get timezone */
1562         local_node->timezone = strtobool(token);
1563
1564         token = pg_strtok(&length); /* eat :setof */
1565         token = pg_strtok(&length); /* get setof */
1566         local_node->setof = strtobool(token);
1567
1568         token = pg_strtok(&length); /* eat :pct_type */
1569         token = pg_strtok(&length); /* get pct_type */
1570         local_node->pct_type = strtobool(token);
1571
1572         token = pg_strtok(&length); /* eat :typmod */
1573         token = pg_strtok(&length); /* get typmod */
1574         local_node->typmod = atoi(token);
1575
1576         token = pg_strtok(&length); /* eat :arrayBounds */
1577         local_node->arrayBounds = nodeRead(true); /* now read it */
1578
1579         return local_node;
1580 }
1581
1582 static ExprFieldSelect *
1583 _readExprFieldSelect(void)
1584 {
1585         ExprFieldSelect  *local_node;
1586         char       *token;
1587         int                     length;
1588
1589         local_node = makeNode(ExprFieldSelect);
1590
1591         token = pg_strtok(&length); /* eat :arg */
1592         local_node->arg = nodeRead(true); /* now read it */
1593
1594         token = pg_strtok(&length); /* eat :fields */
1595         local_node->fields = nodeRead(true); /* now read it */
1596
1597         token = pg_strtok(&length); /* eat :indirection */
1598         local_node->indirection = nodeRead(true); /* now read it */
1599
1600         return local_node;
1601 }
1602
1603 static Alias *
1604 _readAlias(void)
1605 {
1606         Alias      *local_node;
1607         char       *token;
1608         int                     length;
1609
1610         local_node = makeNode(Alias);
1611
1612         token = pg_strtok(&length); /* eat :aliasname */
1613         token = pg_strtok(&length); /* get aliasname */
1614         local_node->aliasname = debackslash(token, length);
1615
1616         token = pg_strtok(&length); /* eat :colnames */
1617         local_node->colnames = nodeRead(true); /* now read it */
1618
1619         return local_node;
1620 }
1621
1622 /* ----------------
1623  *              _readRangeTblEntry
1624  * ----------------
1625  */
1626 static RangeTblEntry *
1627 _readRangeTblEntry(void)
1628 {
1629         RangeTblEntry *local_node;
1630         char       *token;
1631         int                     length;
1632
1633         local_node = makeNode(RangeTblEntry);
1634
1635         token = pg_strtok(&length); /* eat :alias */
1636         local_node->alias = nodeRead(true); /* now read it */
1637
1638         token = pg_strtok(&length); /* eat :eref */
1639         local_node->eref = nodeRead(true);      /* now read it */
1640
1641         token = pg_strtok(&length); /* eat :rtekind */
1642         token = pg_strtok(&length); /* get rtekind */
1643         local_node->rtekind = (RTEKind) atoi(token);
1644
1645         switch (local_node->rtekind)
1646         {
1647                 case RTE_RELATION:
1648                 case RTE_SPECIAL:
1649                         token = pg_strtok(&length); /* eat :relid */
1650                         token = pg_strtok(&length); /* get :relid */
1651                         local_node->relid = atooid(token);
1652                         break;
1653
1654                 case RTE_SUBQUERY:
1655                         token = pg_strtok(&length); /* eat :subquery */
1656                         local_node->subquery = nodeRead(true);          /* now read it */
1657                         break;
1658
1659                 case RTE_FUNCTION:
1660                         token = pg_strtok(&length); /* eat :funcexpr */
1661                         local_node->funcexpr = nodeRead(true);          /* now read it */
1662
1663                         token = pg_strtok(&length); /* eat :coldeflist */
1664                         local_node->coldeflist = nodeRead(true);        /* now read it */
1665
1666                         break;
1667
1668                 case RTE_JOIN:
1669                         token = pg_strtok(&length); /* eat :jointype */
1670                         token = pg_strtok(&length); /* get jointype */
1671                         local_node->jointype = (JoinType) atoi(token);
1672
1673                         token = pg_strtok(&length); /* eat :joinaliasvars */
1674                         local_node->joinaliasvars = nodeRead(true);     /* now read it */
1675                         break;
1676
1677                 default:
1678                         elog(ERROR, "bogus rte kind %d", (int) local_node->rtekind);
1679                         break;
1680         }
1681
1682         token = pg_strtok(&length); /* eat :inh */
1683         token = pg_strtok(&length); /* get :inh */
1684         local_node->inh = strtobool(token);
1685
1686         token = pg_strtok(&length); /* eat :inFromCl */
1687         token = pg_strtok(&length); /* get :inFromCl */
1688         local_node->inFromCl = strtobool(token);
1689
1690         token = pg_strtok(&length); /* eat :checkForRead */
1691         token = pg_strtok(&length); /* get :checkForRead */
1692         local_node->checkForRead = strtobool(token);
1693
1694         token = pg_strtok(&length); /* eat :checkForWrite */
1695         token = pg_strtok(&length); /* get :checkForWrite */
1696         local_node->checkForWrite = strtobool(token);
1697
1698         token = pg_strtok(&length); /* eat :checkAsUser */
1699         token = pg_strtok(&length); /* get :checkAsUser */
1700         local_node->checkAsUser = atooid(token);
1701
1702         return local_node;
1703 }
1704
1705 /* ----------------
1706  *              _readPath
1707  *
1708  *      Path is a subclass of Node.
1709  * ----------------
1710  */
1711 static Path *
1712 _readPath(void)
1713 {
1714         Path       *local_node;
1715         char       *token;
1716         int                     length;
1717
1718         local_node = makeNode(Path);
1719
1720         token = pg_strtok(&length); /* get :pathtype */
1721         token = pg_strtok(&length); /* now read it */
1722         local_node->pathtype = atoi(token);
1723
1724         token = pg_strtok(&length); /* get :startup_cost */
1725         token = pg_strtok(&length); /* now read it */
1726         local_node->startup_cost = (Cost) atof(token);
1727
1728         token = pg_strtok(&length); /* get :total_cost */
1729         token = pg_strtok(&length); /* now read it */
1730         local_node->total_cost = (Cost) atof(token);
1731
1732         token = pg_strtok(&length); /* get :pathkeys */
1733         local_node->pathkeys = nodeRead(true);          /* now read it */
1734
1735         return local_node;
1736 }
1737
1738 /* ----------------
1739  *              _readIndexPath
1740  *
1741  *      IndexPath is a subclass of Path.
1742  * ----------------
1743  */
1744 static IndexPath *
1745 _readIndexPath(void)
1746 {
1747         IndexPath  *local_node;
1748         char       *token;
1749         int                     length;
1750
1751         local_node = makeNode(IndexPath);
1752
1753         token = pg_strtok(&length); /* get :pathtype */
1754         token = pg_strtok(&length); /* now read it */
1755         local_node->path.pathtype = atoi(token);
1756
1757         token = pg_strtok(&length); /* get :startup_cost */
1758         token = pg_strtok(&length); /* now read it */
1759         local_node->path.startup_cost = (Cost) atof(token);
1760
1761         token = pg_strtok(&length); /* get :total_cost */
1762         token = pg_strtok(&length); /* now read it */
1763         local_node->path.total_cost = (Cost) atof(token);
1764
1765         token = pg_strtok(&length); /* get :pathkeys */
1766         local_node->path.pathkeys = nodeRead(true); /* now read it */
1767
1768         token = pg_strtok(&length); /* get :indexinfo */
1769         local_node->indexinfo = nodeRead(true);         /* now read it */
1770
1771         token = pg_strtok(&length); /* get :indexqual */
1772         local_node->indexqual = nodeRead(true);         /* now read it */
1773
1774         token = pg_strtok(&length); /* get :indexscandir */
1775         token = pg_strtok(&length); /* now read it */
1776         local_node->indexscandir = (ScanDirection) atoi(token);
1777
1778         token = pg_strtok(&length); /* get :joinrelids */
1779         local_node->joinrelids = toIntList(nodeRead(true));
1780
1781         token = pg_strtok(&length); /* get :alljoinquals */
1782         token = pg_strtok(&length); /* now read it */
1783         local_node->alljoinquals = strtobool(token);
1784
1785         token = pg_strtok(&length); /* get :rows */
1786         token = pg_strtok(&length); /* now read it */
1787         local_node->rows = atof(token);
1788
1789         return local_node;
1790 }
1791
1792 /* ----------------
1793  *              _readTidPath
1794  *
1795  *      TidPath is a subclass of Path.
1796  * ----------------
1797  */
1798 static TidPath *
1799 _readTidPath(void)
1800 {
1801         TidPath    *local_node;
1802         char       *token;
1803         int                     length;
1804
1805         local_node = makeNode(TidPath);
1806
1807         token = pg_strtok(&length); /* get :pathtype */
1808         token = pg_strtok(&length); /* now read it */
1809         local_node->path.pathtype = atoi(token);
1810
1811         token = pg_strtok(&length); /* get :startup_cost */
1812         token = pg_strtok(&length); /* now read it */
1813         local_node->path.startup_cost = (Cost) atof(token);
1814
1815         token = pg_strtok(&length); /* get :total_cost */
1816         token = pg_strtok(&length); /* now read it */
1817         local_node->path.total_cost = (Cost) atof(token);
1818
1819         token = pg_strtok(&length); /* get :pathkeys */
1820         local_node->path.pathkeys = nodeRead(true); /* now read it */
1821
1822         token = pg_strtok(&length); /* get :tideval */
1823         local_node->tideval = nodeRead(true);           /* now read it */
1824
1825         token = pg_strtok(&length); /* get :unjoined_relids */
1826         local_node->unjoined_relids = toIntList(nodeRead(true));
1827
1828         return local_node;
1829 }
1830
1831 /* ----------------
1832  *              _readAppendPath
1833  *
1834  *      AppendPath is a subclass of Path.
1835  * ----------------
1836  */
1837 static AppendPath *
1838 _readAppendPath(void)
1839 {
1840         AppendPath *local_node;
1841         char       *token;
1842         int                     length;
1843
1844         local_node = makeNode(AppendPath);
1845
1846         token = pg_strtok(&length); /* get :pathtype */
1847         token = pg_strtok(&length); /* now read it */
1848         local_node->path.pathtype = atoi(token);
1849
1850         token = pg_strtok(&length); /* get :startup_cost */
1851         token = pg_strtok(&length); /* now read it */
1852         local_node->path.startup_cost = (Cost) atof(token);
1853
1854         token = pg_strtok(&length); /* get :total_cost */
1855         token = pg_strtok(&length); /* now read it */
1856         local_node->path.total_cost = (Cost) atof(token);
1857
1858         token = pg_strtok(&length); /* get :pathkeys */
1859         local_node->path.pathkeys = nodeRead(true); /* now read it */
1860
1861         token = pg_strtok(&length); /* get :subpaths */
1862         local_node->subpaths = nodeRead(true);          /* now read it */
1863
1864         return local_node;
1865 }
1866
1867 /* ----------------
1868  *              _readNestPath
1869  *
1870  *      NestPath is a subclass of Path
1871  * ----------------
1872  */
1873 static NestPath *
1874 _readNestPath(void)
1875 {
1876         NestPath   *local_node;
1877         char       *token;
1878         int                     length;
1879
1880         local_node = makeNode(NestPath);
1881
1882         token = pg_strtok(&length); /* get :pathtype */
1883         token = pg_strtok(&length); /* now read it */
1884         local_node->path.pathtype = atoi(token);
1885
1886         token = pg_strtok(&length); /* get :startup_cost */
1887         token = pg_strtok(&length); /* now read it */
1888         local_node->path.startup_cost = (Cost) atof(token);
1889
1890         token = pg_strtok(&length); /* get :total_cost */
1891         token = pg_strtok(&length); /* now read it */
1892         local_node->path.total_cost = (Cost) atof(token);
1893
1894         token = pg_strtok(&length); /* get :pathkeys */
1895         local_node->path.pathkeys = nodeRead(true); /* now read it */
1896
1897         token = pg_strtok(&length); /* get :jointype */
1898         token = pg_strtok(&length); /* now read it */
1899         local_node->jointype = (JoinType) atoi(token);
1900
1901         token = pg_strtok(&length); /* get :outerjoinpath */
1902         local_node->outerjoinpath = nodeRead(true); /* now read it */
1903
1904         token = pg_strtok(&length); /* get :innerjoinpath */
1905         local_node->innerjoinpath = nodeRead(true); /* now read it */
1906
1907         token = pg_strtok(&length); /* get :joinrestrictinfo */
1908         local_node->joinrestrictinfo = nodeRead(true);          /* now read it */
1909
1910         return local_node;
1911 }
1912
1913 /* ----------------
1914  *              _readMergePath
1915  *
1916  *      MergePath is a subclass of NestPath.
1917  * ----------------
1918  */
1919 static MergePath *
1920 _readMergePath(void)
1921 {
1922         MergePath  *local_node;
1923         char       *token;
1924         int                     length;
1925
1926         local_node = makeNode(MergePath);
1927
1928         token = pg_strtok(&length); /* get :pathtype */
1929         token = pg_strtok(&length); /* now read it */
1930         local_node->jpath.path.pathtype = atoi(token);
1931
1932         token = pg_strtok(&length); /* get :startup_cost */
1933         token = pg_strtok(&length); /* now read it */
1934         local_node->jpath.path.startup_cost = (Cost) atof(token);
1935
1936         token = pg_strtok(&length); /* get :total_cost */
1937         token = pg_strtok(&length); /* now read it */
1938         local_node->jpath.path.total_cost = (Cost) atof(token);
1939
1940         token = pg_strtok(&length); /* get :pathkeys */
1941         local_node->jpath.path.pathkeys = nodeRead(true);       /* now read it */
1942
1943         token = pg_strtok(&length); /* get :jointype */
1944         token = pg_strtok(&length); /* now read it */
1945         local_node->jpath.jointype = (JoinType) atoi(token);
1946
1947         token = pg_strtok(&length); /* get :outerjoinpath */
1948         local_node->jpath.outerjoinpath = nodeRead(true);       /* now read it */
1949
1950         token = pg_strtok(&length); /* get :innerjoinpath */
1951         local_node->jpath.innerjoinpath = nodeRead(true);       /* now read it */
1952
1953         token = pg_strtok(&length); /* get :joinrestrictinfo */
1954         local_node->jpath.joinrestrictinfo = nodeRead(true);            /* now read it */
1955
1956         token = pg_strtok(&length); /* get :path_mergeclauses */
1957         local_node->path_mergeclauses = nodeRead(true);         /* now read it */
1958
1959         token = pg_strtok(&length); /* get :outersortkeys */
1960         local_node->outersortkeys = nodeRead(true); /* now read it */
1961
1962         token = pg_strtok(&length); /* get :innersortkeys */
1963         local_node->innersortkeys = nodeRead(true); /* now read it */
1964
1965         return local_node;
1966 }
1967
1968 /* ----------------
1969  *              _readHashPath
1970  *
1971  *      HashPath is a subclass of NestPath.
1972  * ----------------
1973  */
1974 static HashPath *
1975 _readHashPath(void)
1976 {
1977         HashPath   *local_node;
1978         char       *token;
1979         int                     length;
1980
1981         local_node = makeNode(HashPath);
1982
1983         token = pg_strtok(&length); /* get :pathtype */
1984         token = pg_strtok(&length); /* now read it */
1985         local_node->jpath.path.pathtype = atoi(token);
1986
1987         token = pg_strtok(&length); /* get :startup_cost */
1988         token = pg_strtok(&length); /* now read it */
1989         local_node->jpath.path.startup_cost = (Cost) atof(token);
1990
1991         token = pg_strtok(&length); /* get :total_cost */
1992         token = pg_strtok(&length); /* now read it */
1993         local_node->jpath.path.total_cost = (Cost) atof(token);
1994
1995         token = pg_strtok(&length); /* get :pathkeys */
1996         local_node->jpath.path.pathkeys = nodeRead(true);       /* now read it */
1997
1998         token = pg_strtok(&length); /* get :jointype */
1999         token = pg_strtok(&length); /* now read it */
2000         local_node->jpath.jointype = (JoinType) atoi(token);
2001
2002         token = pg_strtok(&length); /* get :outerjoinpath */
2003         local_node->jpath.outerjoinpath = nodeRead(true);       /* now read it */
2004
2005         token = pg_strtok(&length); /* get :innerjoinpath */
2006         local_node->jpath.innerjoinpath = nodeRead(true);       /* now read it */
2007
2008         token = pg_strtok(&length); /* get :joinrestrictinfo */
2009         local_node->jpath.joinrestrictinfo = nodeRead(true);            /* now read it */
2010
2011         token = pg_strtok(&length); /* get :path_hashclauses */
2012         local_node->path_hashclauses = nodeRead(true);          /* now read it */
2013
2014         return local_node;
2015 }
2016
2017 /* ----------------
2018  *              _readPathKeyItem
2019  *
2020  *      PathKeyItem is a subclass of Node.
2021  * ----------------
2022  */
2023 static PathKeyItem *
2024 _readPathKeyItem(void)
2025 {
2026         PathKeyItem *local_node;
2027         char       *token;
2028         int                     length;
2029
2030         local_node = makeNode(PathKeyItem);
2031
2032         token = pg_strtok(&length); /* get :sortop */
2033         token = pg_strtok(&length); /* now read it */
2034         local_node->sortop = atooid(token);
2035
2036         token = pg_strtok(&length); /* get :key */
2037         local_node->key = nodeRead(true);       /* now read it */
2038
2039         return local_node;
2040 }
2041
2042 /* ----------------
2043  *              _readRestrictInfo
2044  *
2045  *      RestrictInfo is a subclass of Node.
2046  * ----------------
2047  */
2048 static RestrictInfo *
2049 _readRestrictInfo(void)
2050 {
2051         RestrictInfo *local_node;
2052         char       *token;
2053         int                     length;
2054
2055         local_node = makeNode(RestrictInfo);
2056
2057         token = pg_strtok(&length); /* get :clause */
2058         local_node->clause = nodeRead(true);            /* now read it */
2059
2060         token = pg_strtok(&length); /* get :ispusheddown */
2061         token = pg_strtok(&length); /* now read it */
2062         local_node->ispusheddown = strtobool(token);
2063
2064         token = pg_strtok(&length); /* get :subclauseindices */
2065         local_node->subclauseindices = nodeRead(true);          /* now read it */
2066
2067         token = pg_strtok(&length); /* get :mergejoinoperator */
2068         token = pg_strtok(&length); /* now read it */
2069         local_node->mergejoinoperator = atooid(token);
2070
2071         token = pg_strtok(&length); /* get :left_sortop */
2072         token = pg_strtok(&length); /* now read it */
2073         local_node->left_sortop = atooid(token);
2074
2075         token = pg_strtok(&length); /* get :right_sortop */
2076         token = pg_strtok(&length); /* now read it */
2077         local_node->right_sortop = atooid(token);
2078
2079         token = pg_strtok(&length); /* get :hashjoinoperator */
2080         token = pg_strtok(&length); /* now read it */
2081         local_node->hashjoinoperator = atooid(token);
2082
2083         /* eval_cost is not part of saved representation; compute on first use */
2084         local_node->eval_cost = -1;
2085         /* ditto for this_selec */
2086         local_node->this_selec = -1;
2087         /* ditto for cached pathkeys, selectivity, bucketsize */
2088         local_node->left_pathkey = NIL;
2089         local_node->right_pathkey = NIL;
2090         local_node->left_mergescansel = -1;
2091         local_node->right_mergescansel = -1;
2092         local_node->left_bucketsize = -1;
2093         local_node->right_bucketsize = -1;
2094
2095         return local_node;
2096 }
2097
2098 /* ----------------
2099  *              _readJoinInfo()
2100  *
2101  *      JoinInfo is a subclass of Node.
2102  * ----------------
2103  */
2104 static JoinInfo *
2105 _readJoinInfo(void)
2106 {
2107         JoinInfo   *local_node;
2108         char       *token;
2109         int                     length;
2110
2111         local_node = makeNode(JoinInfo);
2112
2113         token = pg_strtok(&length); /* get :unjoined_relids */
2114         local_node->unjoined_relids = toIntList(nodeRead(true));        /* now read it */
2115
2116         token = pg_strtok(&length); /* get :jinfo_restrictinfo */
2117         local_node->jinfo_restrictinfo = nodeRead(true);        /* now read it */
2118
2119         return local_node;
2120 }
2121
2122
2123 /* ----------------
2124  *              parsePlanString
2125  *
2126  * Given a character string containing a plan, parsePlanString sets up the
2127  * plan structure representing that plan.
2128  *
2129  * The string to be read must already have been loaded into pg_strtok().
2130  * ----------------
2131  */
2132 Node *
2133 parsePlanString(void)
2134 {
2135         char       *token;
2136         int                     length;
2137         void       *return_value = NULL;
2138
2139         token = pg_strtok(&length);
2140
2141         if (length == 4 && strncmp(token, "PLAN", length) == 0)
2142                 return_value = _readPlan();
2143         else if (length == 6 && strncmp(token, "RESULT", length) == 0)
2144                 return_value = _readResult();
2145         else if (length == 6 && strncmp(token, "APPEND", length) == 0)
2146                 return_value = _readAppend();
2147         else if (length == 4 && strncmp(token, "JOIN", length) == 0)
2148                 return_value = _readJoin();
2149         else if (length == 8 && strncmp(token, "NESTLOOP", length) == 0)
2150                 return_value = _readNestLoop();
2151         else if (length == 9 && strncmp(token, "MERGEJOIN", length) == 0)
2152                 return_value = _readMergeJoin();
2153         else if (length == 8 && strncmp(token, "HASHJOIN", length) == 0)
2154                 return_value = _readHashJoin();
2155         else if (length == 4 && strncmp(token, "SCAN", length) == 0)
2156                 return_value = _readScan();
2157         else if (length == 7 && strncmp(token, "SEQSCAN", length) == 0)
2158                 return_value = _readSeqScan();
2159         else if (length == 9 && strncmp(token, "INDEXSCAN", length) == 0)
2160                 return_value = _readIndexScan();
2161         else if (length == 7 && strncmp(token, "TIDSCAN", length) == 0)
2162                 return_value = _readTidScan();
2163         else if (length == 12 && strncmp(token, "SUBQUERYSCAN", length) == 0)
2164                 return_value = _readSubqueryScan();
2165         else if (length == 12 && strncmp(token, "FUNCTIONSCAN", length) == 0)
2166                 return_value = _readFunctionScan();
2167         else if (length == 4 && strncmp(token, "SORT", length) == 0)
2168                 return_value = _readSort();
2169         else if (length == 6 && strncmp(token, "AGGREG", length) == 0)
2170                 return_value = _readAggref();
2171         else if (length == 7 && strncmp(token, "SUBLINK", length) == 0)
2172                 return_value = _readSubLink();
2173         else if (length == 11 && strncmp(token, "FIELDSELECT", length) == 0)
2174                 return_value = _readFieldSelect();
2175         else if (length == 11 && strncmp(token, "RELABELTYPE", length) == 0)
2176                 return_value = _readRelabelType();
2177         else if (length == 11 && strncmp(token, "RANGETBLREF", length) == 0)
2178                 return_value = _readRangeTblRef();
2179         else if (length == 8 && strncmp(token, "FROMEXPR", length) == 0)
2180                 return_value = _readFromExpr();
2181         else if (length == 8 && strncmp(token, "JOINEXPR", length) == 0)
2182                 return_value = _readJoinExpr();
2183         else if (length == 3 && strncmp(token, "AGG", length) == 0)
2184                 return_value = _readAgg();
2185         else if (length == 4 && strncmp(token, "HASH", length) == 0)
2186                 return_value = _readHash();
2187         else if (length == 6 && strncmp(token, "RESDOM", length) == 0)
2188                 return_value = _readResdom();
2189         else if (length == 4 && strncmp(token, "EXPR", length) == 0)
2190                 return_value = _readExpr();
2191         else if (length == 8 && strncmp(token, "ARRAYREF", length) == 0)
2192                 return_value = _readArrayRef();
2193         else if (length == 3 && strncmp(token, "VAR", length) == 0)
2194                 return_value = _readVar();
2195         else if (length == 5 && strncmp(token, "CONST", length) == 0)
2196                 return_value = _readConst();
2197         else if (length == 4 && strncmp(token, "FUNC", length) == 0)
2198                 return_value = _readFunc();
2199         else if (length == 4 && strncmp(token, "OPER", length) == 0)
2200                 return_value = _readOper();
2201         else if (length == 5 && strncmp(token, "PARAM", length) == 0)
2202                 return_value = _readParam();
2203         else if (length == 11 && strncmp(token, "TARGETENTRY", length) == 0)
2204                 return_value = _readTargetEntry();
2205         else if (length == 8 && strncmp(token, "RANGEVAR", length) == 0)
2206                 return_value = _readRangeVar();
2207         else if (length == 9 && strncmp(token, "COLUMNREF", length) == 0)
2208                 return_value = _readColumnRef();
2209         else if (length == 9 && strncmp(token, "COLUMNDEF", length) == 0)
2210                 return_value = _readColumnDef();
2211         else if (length == 8 && strncmp(token, "TYPENAME", length) == 0)
2212                 return_value = _readTypeName();
2213         else if (length == 15 && strncmp(token, "EXPRFIELDSELECT", length) == 0)
2214                 return_value = _readExprFieldSelect();
2215         else if (length == 5 && strncmp(token, "ALIAS", length) == 0)
2216                 return_value = _readAlias();
2217         else if (length == 3 && strncmp(token, "RTE", length) == 0)
2218                 return_value = _readRangeTblEntry();
2219         else if (length == 4 && strncmp(token, "PATH", length) == 0)
2220                 return_value = _readPath();
2221         else if (length == 9 && strncmp(token, "INDEXPATH", length) == 0)
2222                 return_value = _readIndexPath();
2223         else if (length == 7 && strncmp(token, "TIDPATH", length) == 0)
2224                 return_value = _readTidPath();
2225         else if (length == 10 && strncmp(token, "APPENDPATH", length) == 0)
2226                 return_value = _readAppendPath();
2227         else if (length == 8 && strncmp(token, "NESTPATH", length) == 0)
2228                 return_value = _readNestPath();
2229         else if (length == 9 && strncmp(token, "MERGEPATH", length) == 0)
2230                 return_value = _readMergePath();
2231         else if (length == 8 && strncmp(token, "HASHPATH", length) == 0)
2232                 return_value = _readHashPath();
2233         else if (length == 11 && strncmp(token, "PATHKEYITEM", length) == 0)
2234                 return_value = _readPathKeyItem();
2235         else if (length == 12 && strncmp(token, "RESTRICTINFO", length) == 0)
2236                 return_value = _readRestrictInfo();
2237         else if (length == 8 && strncmp(token, "JOININFO", length) == 0)
2238                 return_value = _readJoinInfo();
2239         else if (length == 5 && strncmp(token, "QUERY", length) == 0)
2240                 return_value = _readQuery();
2241         else if (length == 6 && strncmp(token, "NOTIFY", length) == 0)
2242                 return_value = _readNotifyStmt();
2243         else if (length == 10 && strncmp(token, "SORTCLAUSE", length) == 0)
2244                 return_value = _readSortClause();
2245         else if (length == 11 && strncmp(token, "GROUPCLAUSE", length) == 0)
2246                 return_value = _readGroupClause();
2247         else if (length == 16 && strncmp(token, "SETOPERATIONSTMT", length) == 0)
2248                 return_value = _readSetOperationStmt();
2249         else if (length == 4 && strncmp(token, "CASE", length) == 0)
2250                 return_value = _readCaseExpr();
2251         else if (length == 4 && strncmp(token, "WHEN", length) == 0)
2252                 return_value = _readCaseWhen();
2253         else if (length == 8 && strncmp(token, "NULLTEST", length) == 0)
2254                 return_value = _readNullTest();
2255         else if (length == 11 && strncmp(token, "BOOLEANTEST", length) == 0)
2256                 return_value = _readBooleanTest();
2257         else if (length == 14 && strncmp(token, "CONSTRAINTTEST", length) == 0)
2258                 return_value = _readConstraintTest();
2259         else
2260                 elog(ERROR, "badly formatted planstring \"%.10s\"...", token);
2261
2262         return (Node *) return_value;
2263 }
2264
2265 /*------------------------------------------------------------*/
2266
2267 /* ----------------
2268  *              readDatum
2269  *
2270  * Given a string representation of a constant, recreate the appropriate
2271  * Datum.  The string representation embeds length info, but not byValue,
2272  * so we must be told that.
2273  * ----------------
2274  */
2275 static Datum
2276 readDatum(bool typbyval)
2277 {
2278         Size            length,
2279                                 i;
2280         int                     tokenLength;
2281         char       *token;
2282         Datum           res;
2283         char       *s;
2284
2285         /*
2286          * read the actual length of the value
2287          */
2288         token = pg_strtok(&tokenLength);
2289         length = atoui(token);
2290
2291         token = pg_strtok(&tokenLength);        /* read the '[' */
2292         if (token == NULL || token[0] != '[')
2293                 elog(ERROR, "readDatum: expected '%s', got '%s'; length = %lu",
2294                          "[", token ? (const char *) token : "[NULL]",
2295                          (unsigned long) length);
2296
2297         if (typbyval)
2298         {
2299                 if (length > (Size) sizeof(Datum))
2300                         elog(ERROR, "readDatum: byval & length = %lu",
2301                                  (unsigned long) length);
2302                 res = (Datum) 0;
2303                 s = (char *) (&res);
2304                 for (i = 0; i < (Size) sizeof(Datum); i++)
2305                 {
2306                         token = pg_strtok(&tokenLength);
2307                         s[i] = (char) atoi(token);
2308                 }
2309         }
2310         else if (length <= 0)
2311                 res = (Datum) NULL;
2312         else
2313         {
2314                 s = (char *) palloc(length);
2315                 for (i = 0; i < length; i++)
2316                 {
2317                         token = pg_strtok(&tokenLength);
2318                         s[i] = (char) atoi(token);
2319                 }
2320                 res = PointerGetDatum(s);
2321         }
2322
2323         token = pg_strtok(&tokenLength);        /* read the ']' */
2324         if (token == NULL || token[0] != ']')
2325                 elog(ERROR, "readDatum: expected '%s', got '%s'; length = %lu",
2326                          "]", token ? (const char *) token : "[NULL]",
2327                          (unsigned long) length);
2328
2329         return res;
2330 }