mirror of
https://github.com/postgres/postgres.git
synced 2025-05-25 00:04:05 -04:00
so that all executable expression nodes inherit from a common supertype Expr. This is somewhat of an exercise in code purity rather than any real functional advance, but getting rid of the extra Oper or Func node formerly used in each operator or function call should provide at least a little space and speed improvement. initdb forced by changes in stored-rules representation.
1015 lines
20 KiB
C
1015 lines
20 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* readfuncs.c
|
|
* Reader functions for Postgres tree nodes.
|
|
*
|
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
*
|
|
* IDENTIFICATION
|
|
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.141 2002/12/12 15:49:28 tgl Exp $
|
|
*
|
|
* NOTES
|
|
* Path and Plan nodes do not have any readfuncs support, because we
|
|
* never have occasion to read them in. (There was once code here that
|
|
* claimed to read them, but it was broken as well as unused.)
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
#include "postgres.h"
|
|
|
|
#include <math.h>
|
|
|
|
#include "nodes/parsenodes.h"
|
|
#include "nodes/readfuncs.h"
|
|
|
|
|
|
/*
|
|
* Macros to simplify reading of different kinds of fields. Use these
|
|
* wherever possible to reduce the chance for silly typos. Note that these
|
|
* hard-wire conventions about the names of the local variables in a Read
|
|
* routine.
|
|
*/
|
|
|
|
/* Declare appropriate local variables */
|
|
#define READ_LOCALS(nodeTypeName) \
|
|
nodeTypeName *local_node = makeNode(nodeTypeName); \
|
|
char *token; \
|
|
int length
|
|
|
|
/* A few guys need only local_node */
|
|
#define READ_LOCALS_NO_FIELDS(nodeTypeName) \
|
|
nodeTypeName *local_node = makeNode(nodeTypeName)
|
|
|
|
/* And a few guys need only the pg_strtok support fields */
|
|
#define READ_TEMP_LOCALS() \
|
|
char *token; \
|
|
int length
|
|
|
|
/* Read an integer field (anything written as ":fldname %d") */
|
|
#define READ_INT_FIELD(fldname) \
|
|
token = pg_strtok(&length); /* skip :fldname */ \
|
|
token = pg_strtok(&length); /* get field value */ \
|
|
local_node->fldname = atoi(token)
|
|
|
|
/* Read an unsigned integer field (anything written as ":fldname %u") */
|
|
#define READ_UINT_FIELD(fldname) \
|
|
token = pg_strtok(&length); /* skip :fldname */ \
|
|
token = pg_strtok(&length); /* get field value */ \
|
|
local_node->fldname = atoui(token)
|
|
|
|
/* Read an OID field (don't hard-wire assumption that OID is same as uint) */
|
|
#define READ_OID_FIELD(fldname) \
|
|
token = pg_strtok(&length); /* skip :fldname */ \
|
|
token = pg_strtok(&length); /* get field value */ \
|
|
local_node->fldname = atooid(token)
|
|
|
|
/* Read a char field (ie, one ascii character) */
|
|
#define READ_CHAR_FIELD(fldname) \
|
|
token = pg_strtok(&length); /* skip :fldname */ \
|
|
token = pg_strtok(&length); /* get field value */ \
|
|
local_node->fldname = token[0]
|
|
|
|
/* Read an enumerated-type field that was written as an integer code */
|
|
#define READ_ENUM_FIELD(fldname, enumtype) \
|
|
token = pg_strtok(&length); /* skip :fldname */ \
|
|
token = pg_strtok(&length); /* get field value */ \
|
|
local_node->fldname = (enumtype) atoi(token)
|
|
|
|
/* Read a float field */
|
|
#define READ_FLOAT_FIELD(fldname) \
|
|
token = pg_strtok(&length); /* skip :fldname */ \
|
|
token = pg_strtok(&length); /* get field value */ \
|
|
local_node->fldname = atof(token)
|
|
|
|
/* Read a boolean field */
|
|
#define READ_BOOL_FIELD(fldname) \
|
|
token = pg_strtok(&length); /* skip :fldname */ \
|
|
token = pg_strtok(&length); /* get field value */ \
|
|
local_node->fldname = strtobool(token)
|
|
|
|
/* Read a character-string field */
|
|
#define READ_STRING_FIELD(fldname) \
|
|
token = pg_strtok(&length); /* skip :fldname */ \
|
|
token = pg_strtok(&length); /* get field value */ \
|
|
local_node->fldname = nullable_string(token, length)
|
|
|
|
/* Read a Node field */
|
|
#define READ_NODE_FIELD(fldname) \
|
|
token = pg_strtok(&length); /* skip :fldname */ \
|
|
local_node->fldname = nodeRead(true)
|
|
|
|
/* Read an integer-list field */
|
|
#define READ_INTLIST_FIELD(fldname) \
|
|
token = pg_strtok(&length); /* skip :fldname */ \
|
|
local_node->fldname = toIntList(nodeRead(true))
|
|
|
|
/* Read an OID-list field */
|
|
#define READ_OIDLIST_FIELD(fldname) \
|
|
token = pg_strtok(&length); /* skip :fldname */ \
|
|
local_node->fldname = toOidList(nodeRead(true))
|
|
|
|
/* Routine exit */
|
|
#define READ_DONE() \
|
|
return local_node
|
|
|
|
|
|
/*
|
|
* 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,
|
|
* for which use atooid(). (As of 7.1, outfuncs.c writes OIDs as %u,
|
|
* 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))
|
|
|
|
|
|
static Datum readDatum(bool typbyval);
|
|
|
|
|
|
/* Convert Value list returned by nodeRead into list of integers */
|
|
static List *
|
|
toIntList(List *list)
|
|
{
|
|
List *l;
|
|
|
|
foreach(l, list)
|
|
{
|
|
Value *v = (Value *) lfirst(l);
|
|
|
|
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)
|
|
{
|
|
Value *v = (Value *) lfirst(l);
|
|
|
|
/*
|
|
* This is a bit tricky because OID is unsigned, and so nodeRead
|
|
* might have concluded the value doesn't fit in an integer. Must
|
|
* cope with T_Float as well.
|
|
*/
|
|
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");
|
|
}
|
|
return list;
|
|
}
|
|
|
|
/*
|
|
* _readQuery
|
|
*/
|
|
static Query *
|
|
_readQuery(void)
|
|
{
|
|
READ_LOCALS(Query);
|
|
|
|
READ_ENUM_FIELD(commandType, CmdType);
|
|
READ_ENUM_FIELD(querySource, QuerySource);
|
|
READ_NODE_FIELD(utilityStmt);
|
|
READ_INT_FIELD(resultRelation);
|
|
READ_NODE_FIELD(into);
|
|
READ_BOOL_FIELD(isPortal);
|
|
READ_BOOL_FIELD(isBinary);
|
|
READ_BOOL_FIELD(hasAggs);
|
|
READ_BOOL_FIELD(hasSubLinks);
|
|
READ_NODE_FIELD(rtable);
|
|
READ_NODE_FIELD(jointree);
|
|
READ_INTLIST_FIELD(rowMarks);
|
|
READ_NODE_FIELD(targetList);
|
|
READ_NODE_FIELD(groupClause);
|
|
READ_NODE_FIELD(havingQual);
|
|
READ_NODE_FIELD(distinctClause);
|
|
READ_NODE_FIELD(sortClause);
|
|
READ_NODE_FIELD(limitOffset);
|
|
READ_NODE_FIELD(limitCount);
|
|
READ_NODE_FIELD(setOperations);
|
|
READ_INTLIST_FIELD(resultRelations);
|
|
|
|
/* planner-internal fields are left zero */
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
/*
|
|
* _readNotifyStmt
|
|
*/
|
|
static NotifyStmt *
|
|
_readNotifyStmt(void)
|
|
{
|
|
READ_LOCALS(NotifyStmt);
|
|
|
|
READ_NODE_FIELD(relation);
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
/*
|
|
* _readSortClause
|
|
*/
|
|
static SortClause *
|
|
_readSortClause(void)
|
|
{
|
|
READ_LOCALS(SortClause);
|
|
|
|
READ_UINT_FIELD(tleSortGroupRef);
|
|
READ_OID_FIELD(sortop);
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
/*
|
|
* _readGroupClause
|
|
*/
|
|
static GroupClause *
|
|
_readGroupClause(void)
|
|
{
|
|
READ_LOCALS(GroupClause);
|
|
|
|
READ_UINT_FIELD(tleSortGroupRef);
|
|
READ_OID_FIELD(sortop);
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
/*
|
|
* _readSetOperationStmt
|
|
*/
|
|
static SetOperationStmt *
|
|
_readSetOperationStmt(void)
|
|
{
|
|
READ_LOCALS(SetOperationStmt);
|
|
|
|
READ_ENUM_FIELD(op, SetOperation);
|
|
READ_BOOL_FIELD(all);
|
|
READ_NODE_FIELD(larg);
|
|
READ_NODE_FIELD(rarg);
|
|
READ_OIDLIST_FIELD(colTypes);
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
|
|
/*
|
|
* Stuff from primnodes.h.
|
|
*/
|
|
|
|
/*
|
|
* _readResdom
|
|
*/
|
|
static Resdom *
|
|
_readResdom(void)
|
|
{
|
|
READ_LOCALS(Resdom);
|
|
|
|
READ_INT_FIELD(resno);
|
|
READ_OID_FIELD(restype);
|
|
READ_INT_FIELD(restypmod);
|
|
READ_STRING_FIELD(resname);
|
|
READ_UINT_FIELD(ressortgroupref);
|
|
READ_UINT_FIELD(reskey);
|
|
READ_OID_FIELD(reskeyop);
|
|
READ_BOOL_FIELD(resjunk);
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
static Alias *
|
|
_readAlias(void)
|
|
{
|
|
READ_LOCALS(Alias);
|
|
|
|
READ_STRING_FIELD(aliasname);
|
|
READ_NODE_FIELD(colnames);
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
static RangeVar *
|
|
_readRangeVar(void)
|
|
{
|
|
READ_LOCALS(RangeVar);
|
|
|
|
local_node->catalogname = NULL; /* not currently saved in output
|
|
* format */
|
|
|
|
READ_STRING_FIELD(schemaname);
|
|
READ_STRING_FIELD(relname);
|
|
READ_ENUM_FIELD(inhOpt, InhOption);
|
|
READ_BOOL_FIELD(istemp);
|
|
READ_NODE_FIELD(alias);
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
/*
|
|
* _readVar
|
|
*/
|
|
static Var *
|
|
_readVar(void)
|
|
{
|
|
READ_LOCALS(Var);
|
|
|
|
READ_UINT_FIELD(varno);
|
|
READ_INT_FIELD(varattno);
|
|
READ_OID_FIELD(vartype);
|
|
READ_INT_FIELD(vartypmod);
|
|
READ_UINT_FIELD(varlevelsup);
|
|
READ_UINT_FIELD(varnoold);
|
|
READ_INT_FIELD(varoattno);
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
/*
|
|
* _readConst
|
|
*/
|
|
static Const *
|
|
_readConst(void)
|
|
{
|
|
READ_LOCALS(Const);
|
|
|
|
READ_OID_FIELD(consttype);
|
|
READ_INT_FIELD(constlen);
|
|
READ_BOOL_FIELD(constbyval);
|
|
READ_BOOL_FIELD(constisnull);
|
|
|
|
token = pg_strtok(&length); /* skip :constvalue */
|
|
if (local_node->constisnull)
|
|
token = pg_strtok(&length); /* skip "<>" */
|
|
else
|
|
local_node->constvalue = readDatum(local_node->constbyval);
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
/*
|
|
* _readParam
|
|
*/
|
|
static Param *
|
|
_readParam(void)
|
|
{
|
|
READ_LOCALS(Param);
|
|
|
|
READ_INT_FIELD(paramkind);
|
|
READ_INT_FIELD(paramid);
|
|
READ_STRING_FIELD(paramname);
|
|
READ_OID_FIELD(paramtype);
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
/*
|
|
* _readAggref
|
|
*/
|
|
static Aggref *
|
|
_readAggref(void)
|
|
{
|
|
READ_LOCALS(Aggref);
|
|
|
|
READ_OID_FIELD(aggfnoid);
|
|
READ_OID_FIELD(aggtype);
|
|
READ_NODE_FIELD(target);
|
|
READ_BOOL_FIELD(aggstar);
|
|
READ_BOOL_FIELD(aggdistinct);
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
/*
|
|
* _readArrayRef
|
|
*/
|
|
static ArrayRef *
|
|
_readArrayRef(void)
|
|
{
|
|
READ_LOCALS(ArrayRef);
|
|
|
|
READ_OID_FIELD(refrestype);
|
|
READ_INT_FIELD(refattrlength);
|
|
READ_INT_FIELD(refelemlength);
|
|
READ_BOOL_FIELD(refelembyval);
|
|
READ_CHAR_FIELD(refelemalign);
|
|
READ_NODE_FIELD(refupperindexpr);
|
|
READ_NODE_FIELD(reflowerindexpr);
|
|
READ_NODE_FIELD(refexpr);
|
|
READ_NODE_FIELD(refassgnexpr);
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
/*
|
|
* _readFuncExpr
|
|
*/
|
|
static FuncExpr *
|
|
_readFuncExpr(void)
|
|
{
|
|
READ_LOCALS(FuncExpr);
|
|
|
|
READ_OID_FIELD(funcid);
|
|
READ_OID_FIELD(funcresulttype);
|
|
READ_BOOL_FIELD(funcretset);
|
|
READ_ENUM_FIELD(funcformat, CoercionForm);
|
|
READ_NODE_FIELD(args);
|
|
|
|
local_node->func_fcache = NULL;
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
/*
|
|
* _readOpExpr
|
|
*/
|
|
static OpExpr *
|
|
_readOpExpr(void)
|
|
{
|
|
READ_LOCALS(OpExpr);
|
|
|
|
READ_OID_FIELD(opno);
|
|
READ_OID_FIELD(opfuncid);
|
|
/*
|
|
* The opfuncid is stored in the textual format primarily for debugging
|
|
* and documentation reasons. We want to always read it as zero to force
|
|
* it to be re-looked-up in the pg_operator entry. This ensures that
|
|
* stored rules don't have hidden dependencies on operators' functions.
|
|
* (We don't currently support an ALTER OPERATOR command, but might
|
|
* someday.)
|
|
*/
|
|
local_node->opfuncid = InvalidOid;
|
|
|
|
READ_OID_FIELD(opresulttype);
|
|
READ_BOOL_FIELD(opretset);
|
|
READ_NODE_FIELD(args);
|
|
|
|
local_node->op_fcache = NULL;
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
/*
|
|
* _readDistinctExpr
|
|
*/
|
|
static DistinctExpr *
|
|
_readDistinctExpr(void)
|
|
{
|
|
READ_LOCALS(DistinctExpr);
|
|
|
|
READ_OID_FIELD(opno);
|
|
READ_OID_FIELD(opfuncid);
|
|
/*
|
|
* The opfuncid is stored in the textual format primarily for debugging
|
|
* and documentation reasons. We want to always read it as zero to force
|
|
* it to be re-looked-up in the pg_operator entry. This ensures that
|
|
* stored rules don't have hidden dependencies on operators' functions.
|
|
* (We don't currently support an ALTER OPERATOR command, but might
|
|
* someday.)
|
|
*/
|
|
local_node->opfuncid = InvalidOid;
|
|
|
|
READ_OID_FIELD(opresulttype);
|
|
READ_BOOL_FIELD(opretset);
|
|
READ_NODE_FIELD(args);
|
|
|
|
local_node->op_fcache = NULL;
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
/*
|
|
* _readBoolExpr
|
|
*/
|
|
static BoolExpr *
|
|
_readBoolExpr(void)
|
|
{
|
|
READ_LOCALS(BoolExpr);
|
|
|
|
/* do-it-yourself enum representation */
|
|
token = pg_strtok(&length); /* skip :boolop */
|
|
token = pg_strtok(&length); /* get field value */
|
|
if (strncmp(token, "and", 3) == 0)
|
|
local_node->boolop = AND_EXPR;
|
|
else if (strncmp(token, "or", 2) == 0)
|
|
local_node->boolop = OR_EXPR;
|
|
else if (strncmp(token, "not", 3) == 0)
|
|
local_node->boolop = NOT_EXPR;
|
|
else
|
|
elog(ERROR, "_readBoolExpr: unknown boolop \"%.*s\"", length, token);
|
|
|
|
READ_NODE_FIELD(args);
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
/*
|
|
* _readSubLink
|
|
*/
|
|
static SubLink *
|
|
_readSubLink(void)
|
|
{
|
|
READ_LOCALS(SubLink);
|
|
|
|
READ_ENUM_FIELD(subLinkType, SubLinkType);
|
|
READ_BOOL_FIELD(useor);
|
|
READ_NODE_FIELD(lefthand);
|
|
READ_NODE_FIELD(oper);
|
|
READ_NODE_FIELD(subselect);
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
/*
|
|
* _readSubPlanExpr is not needed since it doesn't appear in stored rules.
|
|
*/
|
|
|
|
/*
|
|
* _readFieldSelect
|
|
*/
|
|
static FieldSelect *
|
|
_readFieldSelect(void)
|
|
{
|
|
READ_LOCALS(FieldSelect);
|
|
|
|
READ_NODE_FIELD(arg);
|
|
READ_INT_FIELD(fieldnum);
|
|
READ_OID_FIELD(resulttype);
|
|
READ_INT_FIELD(resulttypmod);
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
/*
|
|
* _readRelabelType
|
|
*/
|
|
static RelabelType *
|
|
_readRelabelType(void)
|
|
{
|
|
READ_LOCALS(RelabelType);
|
|
|
|
READ_NODE_FIELD(arg);
|
|
READ_OID_FIELD(resulttype);
|
|
READ_INT_FIELD(resulttypmod);
|
|
READ_ENUM_FIELD(relabelformat, CoercionForm);
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
/*
|
|
* _readCaseExpr
|
|
*/
|
|
static CaseExpr *
|
|
_readCaseExpr(void)
|
|
{
|
|
READ_LOCALS(CaseExpr);
|
|
|
|
READ_OID_FIELD(casetype);
|
|
READ_NODE_FIELD(arg);
|
|
READ_NODE_FIELD(args);
|
|
READ_NODE_FIELD(defresult);
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
/*
|
|
* _readCaseWhen
|
|
*/
|
|
static CaseWhen *
|
|
_readCaseWhen(void)
|
|
{
|
|
READ_LOCALS(CaseWhen);
|
|
|
|
READ_NODE_FIELD(expr);
|
|
READ_NODE_FIELD(result);
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
/*
|
|
* _readNullTest
|
|
*/
|
|
static NullTest *
|
|
_readNullTest(void)
|
|
{
|
|
READ_LOCALS(NullTest);
|
|
|
|
READ_NODE_FIELD(arg);
|
|
READ_ENUM_FIELD(nulltesttype, NullTestType);
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
/*
|
|
* _readBooleanTest
|
|
*/
|
|
static BooleanTest *
|
|
_readBooleanTest(void)
|
|
{
|
|
READ_LOCALS(BooleanTest);
|
|
|
|
READ_NODE_FIELD(arg);
|
|
READ_ENUM_FIELD(booltesttype, BoolTestType);
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
/*
|
|
* _readConstraintTest
|
|
*/
|
|
static ConstraintTest *
|
|
_readConstraintTest(void)
|
|
{
|
|
READ_LOCALS(ConstraintTest);
|
|
|
|
READ_NODE_FIELD(arg);
|
|
READ_ENUM_FIELD(testtype, ConstraintTestType);
|
|
READ_STRING_FIELD(name);
|
|
READ_STRING_FIELD(domname);
|
|
READ_NODE_FIELD(check_expr);
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
/*
|
|
* _readConstraintTestValue
|
|
*/
|
|
static ConstraintTestValue *
|
|
_readConstraintTestValue(void)
|
|
{
|
|
READ_LOCALS(ConstraintTestValue);
|
|
|
|
READ_OID_FIELD(typeId);
|
|
READ_INT_FIELD(typeMod);
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
/*
|
|
* _readTargetEntry
|
|
*/
|
|
static TargetEntry *
|
|
_readTargetEntry(void)
|
|
{
|
|
READ_LOCALS(TargetEntry);
|
|
|
|
READ_NODE_FIELD(resdom);
|
|
READ_NODE_FIELD(expr);
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
/*
|
|
* _readRangeTblRef
|
|
*/
|
|
static RangeTblRef *
|
|
_readRangeTblRef(void)
|
|
{
|
|
READ_LOCALS(RangeTblRef);
|
|
|
|
READ_INT_FIELD(rtindex);
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
/*
|
|
* _readJoinExpr
|
|
*/
|
|
static JoinExpr *
|
|
_readJoinExpr(void)
|
|
{
|
|
READ_LOCALS(JoinExpr);
|
|
|
|
READ_ENUM_FIELD(jointype, JoinType);
|
|
READ_BOOL_FIELD(isNatural);
|
|
READ_NODE_FIELD(larg);
|
|
READ_NODE_FIELD(rarg);
|
|
READ_NODE_FIELD(using);
|
|
READ_NODE_FIELD(quals);
|
|
READ_NODE_FIELD(alias);
|
|
READ_INT_FIELD(rtindex);
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
/*
|
|
* _readFromExpr
|
|
*/
|
|
static FromExpr *
|
|
_readFromExpr(void)
|
|
{
|
|
READ_LOCALS(FromExpr);
|
|
|
|
READ_NODE_FIELD(fromlist);
|
|
READ_NODE_FIELD(quals);
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
|
|
/*
|
|
* Stuff from parsenodes.h.
|
|
*/
|
|
|
|
static ColumnRef *
|
|
_readColumnRef(void)
|
|
{
|
|
READ_LOCALS(ColumnRef);
|
|
|
|
READ_NODE_FIELD(fields);
|
|
READ_NODE_FIELD(indirection);
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
static ColumnDef *
|
|
_readColumnDef(void)
|
|
{
|
|
READ_LOCALS(ColumnDef);
|
|
|
|
READ_STRING_FIELD(colname);
|
|
READ_NODE_FIELD(typename);
|
|
READ_INT_FIELD(inhcount);
|
|
READ_BOOL_FIELD(is_local);
|
|
READ_BOOL_FIELD(is_not_null);
|
|
READ_NODE_FIELD(raw_default);
|
|
READ_STRING_FIELD(cooked_default);
|
|
READ_NODE_FIELD(constraints);
|
|
READ_NODE_FIELD(support);
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
static TypeName *
|
|
_readTypeName(void)
|
|
{
|
|
READ_LOCALS(TypeName);
|
|
|
|
READ_NODE_FIELD(names);
|
|
READ_OID_FIELD(typeid);
|
|
READ_BOOL_FIELD(timezone);
|
|
READ_BOOL_FIELD(setof);
|
|
READ_BOOL_FIELD(pct_type);
|
|
READ_INT_FIELD(typmod);
|
|
READ_NODE_FIELD(arrayBounds);
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
static ExprFieldSelect *
|
|
_readExprFieldSelect(void)
|
|
{
|
|
READ_LOCALS(ExprFieldSelect);
|
|
|
|
READ_NODE_FIELD(arg);
|
|
READ_NODE_FIELD(fields);
|
|
READ_NODE_FIELD(indirection);
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
/*
|
|
* _readDomainConstraintValue
|
|
*/
|
|
static DomainConstraintValue *
|
|
_readDomainConstraintValue(void)
|
|
{
|
|
READ_LOCALS_NO_FIELDS(DomainConstraintValue);
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
/*
|
|
* _readRangeTblEntry
|
|
*/
|
|
static RangeTblEntry *
|
|
_readRangeTblEntry(void)
|
|
{
|
|
READ_LOCALS(RangeTblEntry);
|
|
|
|
/* put alias + eref first to make dump more legible */
|
|
READ_NODE_FIELD(alias);
|
|
READ_NODE_FIELD(eref);
|
|
READ_ENUM_FIELD(rtekind, RTEKind);
|
|
|
|
switch (local_node->rtekind)
|
|
{
|
|
case RTE_RELATION:
|
|
case RTE_SPECIAL:
|
|
READ_OID_FIELD(relid);
|
|
break;
|
|
case RTE_SUBQUERY:
|
|
READ_NODE_FIELD(subquery);
|
|
break;
|
|
case RTE_FUNCTION:
|
|
READ_NODE_FIELD(funcexpr);
|
|
READ_NODE_FIELD(coldeflist);
|
|
break;
|
|
case RTE_JOIN:
|
|
READ_ENUM_FIELD(jointype, JoinType);
|
|
READ_NODE_FIELD(joinaliasvars);
|
|
break;
|
|
default:
|
|
elog(ERROR, "bogus rte kind %d", (int) local_node->rtekind);
|
|
break;
|
|
}
|
|
|
|
READ_BOOL_FIELD(inh);
|
|
READ_BOOL_FIELD(inFromCl);
|
|
READ_BOOL_FIELD(checkForRead);
|
|
READ_BOOL_FIELD(checkForWrite);
|
|
READ_OID_FIELD(checkAsUser);
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
|
|
/*
|
|
* parseNodeString
|
|
*
|
|
* Given a character string representing a node tree, parseNodeString creates
|
|
* the internal node structure.
|
|
*
|
|
* The string to be read must already have been loaded into pg_strtok().
|
|
*/
|
|
Node *
|
|
parseNodeString(void)
|
|
{
|
|
void *return_value;
|
|
READ_TEMP_LOCALS();
|
|
|
|
token = pg_strtok(&length);
|
|
|
|
#define MATCH(tokname, namelen) \
|
|
(length == namelen && strncmp(token, tokname, namelen) == 0)
|
|
|
|
if (MATCH("QUERY", 5))
|
|
return_value = _readQuery();
|
|
else if (MATCH("NOTIFY", 6))
|
|
return_value = _readNotifyStmt();
|
|
else if (MATCH("SORTCLAUSE", 10))
|
|
return_value = _readSortClause();
|
|
else if (MATCH("GROUPCLAUSE", 11))
|
|
return_value = _readGroupClause();
|
|
else if (MATCH("SETOPERATIONSTMT", 16))
|
|
return_value = _readSetOperationStmt();
|
|
else if (MATCH("RESDOM", 6))
|
|
return_value = _readResdom();
|
|
else if (MATCH("ALIAS", 5))
|
|
return_value = _readAlias();
|
|
else if (MATCH("RANGEVAR", 8))
|
|
return_value = _readRangeVar();
|
|
else if (MATCH("VAR", 3))
|
|
return_value = _readVar();
|
|
else if (MATCH("CONST", 5))
|
|
return_value = _readConst();
|
|
else if (MATCH("PARAM", 5))
|
|
return_value = _readParam();
|
|
else if (MATCH("AGGREF", 6))
|
|
return_value = _readAggref();
|
|
else if (MATCH("ARRAYREF", 8))
|
|
return_value = _readArrayRef();
|
|
else if (MATCH("FUNCEXPR", 8))
|
|
return_value = _readFuncExpr();
|
|
else if (MATCH("OPEXPR", 6))
|
|
return_value = _readOpExpr();
|
|
else if (MATCH("DISTINCTEXPR", 12))
|
|
return_value = _readDistinctExpr();
|
|
else if (MATCH("BOOLEXPR", 8))
|
|
return_value = _readBoolExpr();
|
|
else if (MATCH("SUBLINK", 7))
|
|
return_value = _readSubLink();
|
|
else if (MATCH("FIELDSELECT", 11))
|
|
return_value = _readFieldSelect();
|
|
else if (MATCH("RELABELTYPE", 11))
|
|
return_value = _readRelabelType();
|
|
else if (MATCH("CASE", 4))
|
|
return_value = _readCaseExpr();
|
|
else if (MATCH("WHEN", 4))
|
|
return_value = _readCaseWhen();
|
|
else if (MATCH("NULLTEST", 8))
|
|
return_value = _readNullTest();
|
|
else if (MATCH("BOOLEANTEST", 11))
|
|
return_value = _readBooleanTest();
|
|
else if (MATCH("CONSTRAINTTEST", 14))
|
|
return_value = _readConstraintTest();
|
|
else if (MATCH("CONSTRAINTTESTVALUE", 19))
|
|
return_value = _readConstraintTestValue();
|
|
else if (MATCH("TARGETENTRY", 11))
|
|
return_value = _readTargetEntry();
|
|
else if (MATCH("RANGETBLREF", 11))
|
|
return_value = _readRangeTblRef();
|
|
else if (MATCH("JOINEXPR", 8))
|
|
return_value = _readJoinExpr();
|
|
else if (MATCH("FROMEXPR", 8))
|
|
return_value = _readFromExpr();
|
|
else if (MATCH("COLUMNREF", 9))
|
|
return_value = _readColumnRef();
|
|
else if (MATCH("COLUMNDEF", 9))
|
|
return_value = _readColumnDef();
|
|
else if (MATCH("TYPENAME", 8))
|
|
return_value = _readTypeName();
|
|
else if (MATCH("EXPRFIELDSELECT", 15))
|
|
return_value = _readExprFieldSelect();
|
|
else if (MATCH("DOMAINCONSTRAINTVALUE", 21))
|
|
return_value = _readDomainConstraintValue();
|
|
else if (MATCH("RTE", 3))
|
|
return_value = _readRangeTblEntry();
|
|
else
|
|
{
|
|
elog(ERROR, "badly formatted node string \"%.32s\"...", token);
|
|
return_value = NULL; /* keep compiler quiet */
|
|
}
|
|
|
|
return (Node *) return_value;
|
|
}
|
|
|
|
|
|
/*
|
|
* readDatum
|
|
*
|
|
* 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.
|
|
*/
|
|
static Datum
|
|
readDatum(bool typbyval)
|
|
{
|
|
Size length,
|
|
i;
|
|
int tokenLength;
|
|
char *token;
|
|
Datum res;
|
|
char *s;
|
|
|
|
/*
|
|
* read the actual length of the value
|
|
*/
|
|
token = pg_strtok(&tokenLength);
|
|
length = atoui(token);
|
|
|
|
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);
|
|
|
|
if (typbyval)
|
|
{
|
|
if (length > (Size) sizeof(Datum))
|
|
elog(ERROR, "readDatum: byval & length = %lu",
|
|
(unsigned long) length);
|
|
res = (Datum) 0;
|
|
s = (char *) (&res);
|
|
for (i = 0; i < (Size) sizeof(Datum); i++)
|
|
{
|
|
token = pg_strtok(&tokenLength);
|
|
s[i] = (char) atoi(token);
|
|
}
|
|
}
|
|
else if (length <= 0)
|
|
res = (Datum) NULL;
|
|
else
|
|
{
|
|
s = (char *) palloc(length);
|
|
for (i = 0; i < length; i++)
|
|
{
|
|
token = pg_strtok(&tokenLength);
|
|
s[i] = (char) atoi(token);
|
|
}
|
|
res = PointerGetDatum(s);
|
|
}
|
|
|
|
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);
|
|
|
|
return res;
|
|
}
|