Commit 338fd40b authored by Tom Lane's avatar Tom Lane

Revise quoting conventions in outfuncs/readfuncs so that nodeRead doesn't

choke on relation or attribute names containing spaces, quotes, or other
special characters.  This fixes a TODO item.  It also forces initdb,
since stored rule strings change.
parent 46a28f1b
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: outfuncs.c,v 1.101 2000/01/09 00:26:23 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.102 2000/01/14 00:53:21 tgl Exp $
* *
* NOTES * NOTES
* Every (plan) node in POSTGRES has an associated "out" routine which * Every (plan) node in POSTGRES has an associated "out" routine which
...@@ -19,8 +19,10 @@ ...@@ -19,8 +19,10 @@
* representation plus some other information (string length, etc.) * representation plus some other information (string length, etc.)
* *
*/ */
#include <ctype.h>
#include "postgres.h" #include "postgres.h"
#include "access/heapam.h" #include "access/heapam.h"
#include "access/htup.h" #include "access/htup.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
...@@ -42,9 +44,43 @@ ...@@ -42,9 +44,43 @@
static void _outDatum(StringInfo str, Datum value, Oid type); static void _outDatum(StringInfo str, Datum value, Oid type);
static void _outNode(StringInfo str, void *obj); static void _outNode(StringInfo str, void *obj);
/* Convert a null string pointer into "<>" */ /*
#define stringStringInfo(s) (((s) == NULL) ? "<>" : (s)) * _outToken
* Convert an ordinary string (eg, an identifier) into a form that
* will be decoded back to a plain token by read.c's functions.
*
* If a null or empty string is given, it is encoded as "<>".
*/
static void
_outToken(StringInfo str, char *s)
{
if (s == NULL || *s == '\0')
{
appendStringInfo(str, "<>");
return;
}
/*
* Look for characters or patterns that are treated specially by
* read.c (either in lsptok() or in nodeRead()), and therefore need
* a protective backslash.
*/
/* These characters only need to be quoted at the start of the string */
if (*s == '<' ||
*s == '\"' ||
*s == '@' ||
isdigit(*s) ||
(*s == '-' && isdigit(s[1])))
appendStringInfoChar(str, '\\');
while (*s)
{
/* These chars must be backslashed anywhere in the string */
if (*s == ' ' || *s == '\n' || *s == '\t' ||
*s == '(' || *s == ')' || *s == '{' || *s == '}' ||
*s == '\\')
appendStringInfoChar(str, '\\');
appendStringInfoChar(str, *s++);
}
}
/* /*
* _outIntList - * _outIntList -
...@@ -55,17 +91,17 @@ _outIntList(StringInfo str, List *list) ...@@ -55,17 +91,17 @@ _outIntList(StringInfo str, List *list)
{ {
List *l; List *l;
appendStringInfo(str, "("); appendStringInfoChar(str, '(');
foreach(l, list) foreach(l, list)
appendStringInfo(str, " %d ", lfirsti(l)); appendStringInfo(str, " %d", lfirsti(l));
appendStringInfo(str, ")"); appendStringInfoChar(str, ')');
} }
static void static void
_outCreateStmt(StringInfo str, CreateStmt *node) _outCreateStmt(StringInfo str, CreateStmt *node)
{ {
appendStringInfo(str, " CREATE :relname %s ", appendStringInfo(str, " CREATE :relname ");
stringStringInfo(node->relname)); _outToken(str, node->relname);
appendStringInfo(str, " :istemp %s ", appendStringInfo(str, " :istemp %s ",
node->istemp ? "true" : "false"); node->istemp ? "true" : "false");
...@@ -83,11 +119,13 @@ _outCreateStmt(StringInfo str, CreateStmt *node) ...@@ -83,11 +119,13 @@ _outCreateStmt(StringInfo str, CreateStmt *node)
static void static void
_outIndexStmt(StringInfo str, IndexStmt *node) _outIndexStmt(StringInfo str, IndexStmt *node)
{ {
appendStringInfo(str, appendStringInfo(str, " INDEX :idxname ");
" INDEX :idxname %s :relname %s :accessMethod %s :indexParams ", _outToken(str, node->idxname);
stringStringInfo(node->idxname), appendStringInfo(str, " :relname ");
stringStringInfo(node->relname), _outToken(str, node->relname);
stringStringInfo(node->accessMethod)); appendStringInfo(str, " :accessMethod ");
_outToken(str, node->accessMethod);
appendStringInfo(str, " :indexParams ");
_outNode(str, node->indexParams); _outNode(str, node->indexParams);
appendStringInfo(str, " :withClause "); appendStringInfo(str, " :withClause ");
...@@ -114,8 +152,9 @@ _outSelectStmt(StringInfo str, SelectStmt *node) ...@@ -114,8 +152,9 @@ _outSelectStmt(StringInfo str, SelectStmt *node)
static void static void
_outFuncCall(StringInfo str, FuncCall *node) _outFuncCall(StringInfo str, FuncCall *node)
{ {
appendStringInfo(str, "FUNCTION %s :args ", appendStringInfo(str, "FUNCTION ");
stringStringInfo(node->funcname)); _outToken(str, node->funcname);
appendStringInfo(str, " :args ");
_outNode(str, node->args); _outNode(str, node->args);
appendStringInfo(str, " :agg_star %s :agg_distinct %s ", appendStringInfo(str, " :agg_star %s :agg_distinct %s ",
node->agg_star ? "true" : "false", node->agg_star ? "true" : "false",
...@@ -125,40 +164,42 @@ _outFuncCall(StringInfo str, FuncCall *node) ...@@ -125,40 +164,42 @@ _outFuncCall(StringInfo str, FuncCall *node)
static void static void
_outColumnDef(StringInfo str, ColumnDef *node) _outColumnDef(StringInfo str, ColumnDef *node)
{ {
appendStringInfo(str, " COLUMNDEF :colname %s :typename ", appendStringInfo(str, " COLUMNDEF :colname ");
stringStringInfo(node->colname)); _outToken(str, node->colname);
appendStringInfo(str, " :typename ");
_outNode(str, node->typename); _outNode(str, node->typename);
appendStringInfo(str, " :is_not_null %s :is_sequence %s :raw_default ", appendStringInfo(str, " :is_not_null %s :is_sequence %s :raw_default ",
node->is_not_null ? "true" : "false", node->is_not_null ? "true" : "false",
node->is_sequence ? "true" : "false"); node->is_sequence ? "true" : "false");
_outNode(str, node->raw_default); _outNode(str, node->raw_default);
appendStringInfo(str, " :cooked_default %s :constraints ", appendStringInfo(str, " :cooked_default ");
stringStringInfo(node->cooked_default)); _outToken(str, node->cooked_default);
appendStringInfo(str, " :constraints ");
_outNode(str, node->constraints); _outNode(str, node->constraints);
} }
static void static void
_outTypeName(StringInfo str, TypeName *node) _outTypeName(StringInfo str, TypeName *node)
{ {
appendStringInfo(str, appendStringInfo(str, " TYPENAME :name ");
" TYPENAME :name %s :timezone %s :setof %s typmod %d :arrayBounds ", _outToken(str, node->name);
stringStringInfo(node->name), appendStringInfo(str, " :timezone %s :setof %s typmod %d :arrayBounds ",
node->timezone ? "true" : "false", node->timezone ? "true" : "false",
node->setof ? "true" : "false", node->setof ? "true" : "false",
node->typmod); node->typmod);
appendStringInfo(str, " :arrayBounds ");
_outNode(str, node->arrayBounds); _outNode(str, node->arrayBounds);
} }
static void static void
_outIndexElem(StringInfo str, IndexElem *node) _outIndexElem(StringInfo str, IndexElem *node)
{ {
appendStringInfo(str, " INDEXELEM :name %s :args ", appendStringInfo(str, " INDEXELEM :name ");
stringStringInfo(node->name)); _outToken(str, node->name);
appendStringInfo(str, " :args ");
_outNode(str, node->args); _outNode(str, node->args);
appendStringInfo(str, " :class ");
appendStringInfo(str, " :class %s :typename ", stringStringInfo(node->class)); _outToken(str, node->class);
appendStringInfo(str, " :typename ");
_outNode(str, node->typename); _outNode(str, node->typename);
} }
...@@ -173,21 +214,24 @@ _outQuery(StringInfo str, Query *node) ...@@ -173,21 +214,24 @@ _outQuery(StringInfo str, Query *node)
switch (nodeTag(node->utilityStmt)) switch (nodeTag(node->utilityStmt))
{ {
case T_CreateStmt: case T_CreateStmt:
appendStringInfo(str, " :create %s ", appendStringInfo(str, " :create ");
stringStringInfo(((CreateStmt *) (node->utilityStmt))->relname)); _outToken(str, ((CreateStmt *) (node->utilityStmt))->relname);
appendStringInfo(str, " ");
_outNode(str, node->utilityStmt); _outNode(str, node->utilityStmt);
break; break;
case T_IndexStmt: case T_IndexStmt:
appendStringInfo(str, " :index %s on %s ", appendStringInfo(str, " :index ");
stringStringInfo(((IndexStmt *) (node->utilityStmt))->idxname), _outToken(str, ((IndexStmt *) (node->utilityStmt))->idxname);
stringStringInfo(((IndexStmt *) (node->utilityStmt))->relname)); appendStringInfo(str, " on ");
_outToken(str, ((IndexStmt *) (node->utilityStmt))->relname);
appendStringInfo(str, " ");
_outNode(str, node->utilityStmt); _outNode(str, node->utilityStmt);
break; break;
case T_NotifyStmt: case T_NotifyStmt:
appendStringInfo(str, " :utility %s ", appendStringInfo(str, " :utility ");
stringStringInfo(((NotifyStmt *) (node->utilityStmt))->relname)); _outToken(str, ((NotifyStmt *) (node->utilityStmt))->relname);
break; break;
default: default:
...@@ -197,17 +241,18 @@ _outQuery(StringInfo str, Query *node) ...@@ -197,17 +241,18 @@ _outQuery(StringInfo str, Query *node)
else else
appendStringInfo(str, " :utility <>"); appendStringInfo(str, " :utility <>");
appendStringInfo(str, " :resultRelation %u :into ",
node->resultRelation);
_outToken(str, node->into);
appendStringInfo(str, appendStringInfo(str,
" :resultRelation %u :into %s :isPortal %s :isBinary %s :isTemp %s :unionall %s ", " :isPortal %s :isBinary %s :isTemp %s :unionall %s :unique ",
node->resultRelation,
stringStringInfo(node->into),
node->isPortal ? "true" : "false", node->isPortal ? "true" : "false",
node->isBinary ? "true" : "false", node->isBinary ? "true" : "false",
node->isTemp ? "true" : "false", node->isTemp ? "true" : "false",
node->unionall ? "true" : "false"); node->unionall ? "true" : "false");
_outToken(str, node->uniqueFlag);
appendStringInfo(str, " :unique %s :sortClause ", appendStringInfo(str, " :sortClause ");
stringStringInfo(node->uniqueFlag));
_outNode(str, node->sortClause); _outNode(str, node->sortClause);
appendStringInfo(str, " :rtable "); appendStringInfo(str, " :rtable ");
...@@ -560,17 +605,15 @@ _outHash(StringInfo str, Hash *node) ...@@ -560,17 +605,15 @@ _outHash(StringInfo str, Hash *node)
static void static void
_outResdom(StringInfo str, Resdom *node) _outResdom(StringInfo str, Resdom *node)
{ {
appendStringInfo(str, " RESDOM :resno %d :restype %u :restypmod %d", appendStringInfo(str,
" RESDOM :resno %d :restype %u :restypmod %d :resname ",
node->resno, node->resno,
node->restype, node->restype,
node->restypmod); node->restypmod);
_outToken(str, node->resname);
appendStringInfo(str, " :resname \"%s\" :reskey %d :reskeyop %u", appendStringInfo(str, " :reskey %d :reskeyop %u :ressortgroupref %d :resjunk %s ",
stringStringInfo(node->resname),
node->reskey, node->reskey,
node->reskeyop); node->reskeyop,
appendStringInfo(str, " :ressortgroupref %d :resjunk %s ",
node->ressortgroupref, node->ressortgroupref,
node->resjunk ? "true" : "false"); node->resjunk ? "true" : "false");
} }
...@@ -626,7 +669,9 @@ _outExpr(StringInfo str, Expr *node) ...@@ -626,7 +669,9 @@ _outExpr(StringInfo str, Expr *node)
opstr = "subp"; opstr = "subp";
break; break;
} }
appendStringInfo(str, " :opType %s :oper ", stringStringInfo(opstr)); appendStringInfo(str, " :opType ");
_outToken(str, opstr);
appendStringInfo(str, " :oper ");
_outNode(str, node->oper); _outNode(str, node->oper);
appendStringInfo(str, " :args "); appendStringInfo(str, " :args ");
...@@ -679,9 +724,9 @@ _outConst(StringInfo str, Const *node) ...@@ -679,9 +724,9 @@ _outConst(StringInfo str, Const *node)
static void static void
_outAggref(StringInfo str, Aggref *node) _outAggref(StringInfo str, Aggref *node)
{ {
appendStringInfo(str, appendStringInfo(str, " AGGREG :aggname ");
" AGGREG :aggname %s :basetype %u :aggtype %u :target ", _outToken(str, node->aggname);
stringStringInfo(node->aggname), appendStringInfo(str, " :basetype %u :aggtype %u :target ",
node->basetype, node->basetype,
node->aggtype); node->aggtype);
_outNode(str, node->target); _outNode(str, node->target);
...@@ -801,14 +846,12 @@ _outOper(StringInfo str, Oper *node) ...@@ -801,14 +846,12 @@ _outOper(StringInfo str, Oper *node)
static void static void
_outParam(StringInfo str, Param *node) _outParam(StringInfo str, Param *node)
{ {
appendStringInfo(str, appendStringInfo(str, " PARAM :paramkind %d :paramid %d :paramname ",
" PARAM :paramkind %d :paramid %d :paramname %s :paramtype %u ",
node->paramkind, node->paramkind,
node->paramid, node->paramid);
stringStringInfo(node->paramname), _outToken(str, node->paramname);
appendStringInfo(str, " :paramtype %u :param_tlist ",
node->paramtype); node->paramtype);
appendStringInfo(str, " :param_tlist ");
_outNode(str, node->param_tlist); _outNode(str, node->param_tlist);
} }
...@@ -897,10 +940,12 @@ _outTargetEntry(StringInfo str, TargetEntry *node) ...@@ -897,10 +940,12 @@ _outTargetEntry(StringInfo str, TargetEntry *node)
static void static void
_outRangeTblEntry(StringInfo str, RangeTblEntry *node) _outRangeTblEntry(StringInfo str, RangeTblEntry *node)
{ {
appendStringInfo(str, " RTE :relname ");
_outToken(str, node->relname);
appendStringInfo(str, " :refname ");
_outToken(str, node->refname);
appendStringInfo(str, appendStringInfo(str,
" RTE :relname %s :refname %s :relid %u :inh %s :inFromCl %s :inJoinSet %s :skipAcl %s", " :relid %u :inh %s :inFromCl %s :inJoinSet %s :skipAcl %s",
stringStringInfo(node->relname),
stringStringInfo(node->refname),
node->relid, node->relid,
node->inh ? "true" : "false", node->inh ? "true" : "false",
node->inFromCl ? "true" : "false", node->inFromCl ? "true" : "false",
...@@ -1115,7 +1160,7 @@ _outDatum(StringInfo str, Datum value, Oid type) ...@@ -1115,7 +1160,7 @@ _outDatum(StringInfo str, Datum value, Oid type)
s = (char *) (&value); s = (char *) (&value);
appendStringInfo(str, " %d [ ", length); appendStringInfo(str, " %d [ ", length);
for (i = 0; i < sizeof(Datum); i++) for (i = 0; i < sizeof(Datum); i++)
appendStringInfo(str, " %d ", (int) (s[i])); appendStringInfo(str, "%d ", (int) (s[i]));
appendStringInfo(str, "] "); appendStringInfo(str, "] ");
} }
else else
...@@ -1134,7 +1179,7 @@ _outDatum(StringInfo str, Datum value, Oid type) ...@@ -1134,7 +1179,7 @@ _outDatum(StringInfo str, Datum value, Oid type)
length = VARSIZE(s); length = VARSIZE(s);
appendStringInfo(str, " %d [ ", length); appendStringInfo(str, " %d [ ", length);
for (i = 0; i < length; i++) for (i = 0; i < length; i++)
appendStringInfo(str, " %d ", (int) (s[i])); appendStringInfo(str, "%d ", (int) (s[i]));
appendStringInfo(str, "] "); appendStringInfo(str, "] ");
} }
} }
...@@ -1172,27 +1217,27 @@ _outAExpr(StringInfo str, A_Expr *node) ...@@ -1172,27 +1217,27 @@ _outAExpr(StringInfo str, A_Expr *node)
switch (node->oper) switch (node->oper)
{ {
case AND: case AND:
appendStringInfo(str, "AND"); appendStringInfo(str, "AND ");
break; break;
case OR: case OR:
appendStringInfo(str, "OR"); appendStringInfo(str, "OR ");
break; break;
case NOT: case NOT:
appendStringInfo(str, "NOT"); appendStringInfo(str, "NOT ");
break; break;
case ISNULL: case ISNULL:
appendStringInfo(str, "ISNULL"); appendStringInfo(str, "ISNULL ");
break; break;
case NOTNULL: case NOTNULL:
appendStringInfo(str, "NOTNULL"); appendStringInfo(str, "NOTNULL ");
break; break;
default: default:
appendStringInfo(str, stringStringInfo(node->opname)); _outToken(str, node->opname);
appendStringInfo(str, " ");
break; break;
} }
_outNode(str, node->lexpr); _outNode(str, node->lexpr);
_outNode(str, node->rexpr); _outNode(str, node->rexpr);
return;
} }
static void static void
...@@ -1200,26 +1245,29 @@ _outValue(StringInfo str, Value *value) ...@@ -1200,26 +1245,29 @@ _outValue(StringInfo str, Value *value)
{ {
switch (value->type) switch (value->type)
{ {
case T_String: case T_String:
appendStringInfo(str, " \"%s\" ", stringStringInfo(value->val.str)); appendStringInfo(str, " \"");
_outToken(str, value->val.str);
appendStringInfo(str, "\" ");
break; break;
case T_Integer: case T_Integer:
appendStringInfo(str, " %ld ", value->val.ival); appendStringInfo(str, " %ld ", value->val.ival);
break; break;
case T_Float: case T_Float:
appendStringInfo(str, " %f ", value->val.dval); appendStringInfo(str, " %.17g ", value->val.dval);
break; break;
default: default:
elog(NOTICE, "_outValue: don't know how to print type %d ",
value->type);
break; break;
} }
return;
} }
static void static void
_outIdent(StringInfo str, Ident *node) _outIdent(StringInfo str, Ident *node)
{ {
appendStringInfo(str, " IDENT \"%s\" ", stringStringInfo(node->name)); appendStringInfo(str, " IDENT ");
return; _outToken(str, node->name);
} }
static void static void
...@@ -1227,17 +1275,16 @@ _outAttr(StringInfo str, Attr *node) ...@@ -1227,17 +1275,16 @@ _outAttr(StringInfo str, Attr *node)
{ {
List *l; List *l;
appendStringInfo(str, " ATTR \"%s\" ", stringStringInfo(node->relname)); appendStringInfo(str, " ATTR ");
_outToken(str, node->relname);
appendStringInfo(str, "("); appendStringInfo(str, " (");
foreach(l, node->attrs) foreach(l, node->attrs)
{ {
_outNode(str, lfirst(l)); _outNode(str, lfirst(l));
if (lnext(l)) if (lnext(l))
appendStringInfo(str, ","); appendStringInfo(str, " ");
} }
appendStringInfo(str, ")"); appendStringInfo(str, ")");
return;
} }
static void static void
...@@ -1245,46 +1292,47 @@ _outAConst(StringInfo str, A_Const *node) ...@@ -1245,46 +1292,47 @@ _outAConst(StringInfo str, A_Const *node)
{ {
appendStringInfo(str, "CONST "); appendStringInfo(str, "CONST ");
_outValue(str, &(node->val)); _outValue(str, &(node->val));
return;
} }
static void static void
_outConstraint(StringInfo str, Constraint *node) _outConstraint(StringInfo str, Constraint *node)
{ {
appendStringInfo(str, " %s :type", stringStringInfo(node->name)); appendStringInfo(str, " ");
_outToken(str, node->name);
appendStringInfo(str, " :type ");
switch (node->contype) switch (node->contype)
{ {
case CONSTR_PRIMARY: case CONSTR_PRIMARY:
appendStringInfo(str, " PRIMARY KEY "); appendStringInfo(str, "PRIMARY KEY ");
_outNode(str, node->keys); _outNode(str, node->keys);
break; break;
case CONSTR_CHECK: case CONSTR_CHECK:
appendStringInfo(str, " CHECK :raw "); appendStringInfo(str, "CHECK :raw ");
_outNode(str, node->raw_expr); _outNode(str, node->raw_expr);
appendStringInfo(str, " :cooked %s ", appendStringInfo(str, " :cooked ");
stringStringInfo(node->cooked_expr)); _outToken(str, node->cooked_expr);
break; break;
case CONSTR_DEFAULT: case CONSTR_DEFAULT:
appendStringInfo(str, " DEFAULT :raw "); appendStringInfo(str, "DEFAULT :raw ");
_outNode(str, node->raw_expr); _outNode(str, node->raw_expr);
appendStringInfo(str, " :cooked %s ", appendStringInfo(str, " :cooked ");
stringStringInfo(node->cooked_expr)); _outToken(str, node->cooked_expr);
break; break;
case CONSTR_NOTNULL: case CONSTR_NOTNULL:
appendStringInfo(str, " NOT NULL "); appendStringInfo(str, "NOT NULL");
break; break;
case CONSTR_UNIQUE: case CONSTR_UNIQUE:
appendStringInfo(str, " UNIQUE "); appendStringInfo(str, "UNIQUE ");
_outNode(str, node->keys); _outNode(str, node->keys);
break; break;
default: default:
appendStringInfo(str, "<unrecognized constraint>"); appendStringInfo(str, "<unrecognized_constraint>");
break; break;
} }
} }
...@@ -1297,8 +1345,6 @@ _outCaseExpr(StringInfo str, CaseExpr *node) ...@@ -1297,8 +1345,6 @@ _outCaseExpr(StringInfo str, CaseExpr *node)
appendStringInfo(str, " :default "); appendStringInfo(str, " :default ");
_outNode(str, node->defresult); _outNode(str, node->defresult);
return;
} }
static void static void
...@@ -1309,8 +1355,6 @@ _outCaseWhen(StringInfo str, CaseWhen *node) ...@@ -1309,8 +1355,6 @@ _outCaseWhen(StringInfo str, CaseWhen *node)
appendStringInfo(str, " :then "); appendStringInfo(str, " :then ");
_outNode(str, node->result); _outNode(str, node->result);
return;
} }
/* /*
...@@ -1330,18 +1374,18 @@ _outNode(StringInfo str, void *obj) ...@@ -1330,18 +1374,18 @@ _outNode(StringInfo str, void *obj)
{ {
List *l; List *l;
appendStringInfo(str, "("); appendStringInfoChar(str, '(');
foreach(l, (List *) obj) foreach(l, (List *) obj)
{ {
_outNode(str, lfirst(l)); _outNode(str, lfirst(l));
if (lnext(l)) if (lnext(l))
appendStringInfo(str, " "); appendStringInfoChar(str, ' ');
} }
appendStringInfo(str, ")"); appendStringInfoChar(str, ')');
} }
else else
{ {
appendStringInfo(str, "{"); appendStringInfoChar(str, '{');
switch (nodeTag(obj)) switch (nodeTag(obj))
{ {
case T_CreateStmt: case T_CreateStmt:
...@@ -1350,7 +1394,6 @@ _outNode(StringInfo str, void *obj) ...@@ -1350,7 +1394,6 @@ _outNode(StringInfo str, void *obj)
case T_IndexStmt: case T_IndexStmt:
_outIndexStmt(str, obj); _outIndexStmt(str, obj);
break; break;
case T_ColumnDef: case T_ColumnDef:
_outColumnDef(str, obj); _outColumnDef(str, obj);
break; break;
...@@ -1551,9 +1594,8 @@ _outNode(StringInfo str, void *obj) ...@@ -1551,9 +1594,8 @@ _outNode(StringInfo str, void *obj)
nodeTag(obj)); nodeTag(obj));
break; break;
} }
appendStringInfo(str, "}"); appendStringInfoChar(str, '}');
} }
return;
} }
/* /*
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/read.c,v 1.18 1999/07/17 20:17:08 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/read.c,v 1.19 2000/01/14 00:53:21 tgl Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <ctype.h> #include <ctype.h>
#include "postgres.h" #include "postgres.h"
#include "nodes/pg_list.h" #include "nodes/pg_list.h"
#include "nodes/readfuncs.h" #include "nodes/readfuncs.h"
...@@ -43,6 +44,134 @@ stringToNode(char *str) ...@@ -43,6 +44,134 @@ stringToNode(char *str)
* *
*****************************************************************************/ *****************************************************************************/
/*
* lsptok --- retrieve next "token" from a string.
*
* Works kinda like strtok, except it never modifies the source string.
* (Instead of storing nulls into the string, the length of the token
* is returned to the caller.)
* Also, the rules about what is a token are hard-wired rather than being
* configured by passing a set of terminating characters.
*
* The string is initially set by passing a non-NULL "string" value,
* and subsequent calls with string==NULL read the previously given value.
* (Pass length==NULL to set the string without reading its first token.)
*
* The rules for tokens are:
* * Whitespace (space, tab, newline) always separates tokens.
* * The characters '(', ')', '{', '}' form individual tokens even
* without any whitespace around them.
* * Otherwise, a token is all the characters up to the next whitespace
* or occurrence of one of the four special characters.
* * A backslash '\' can be used to quote whitespace or one of the four
* special characters, so that it is treated as a plain token character.
* Backslashes themselves must also be backslashed for consistency.
* Any other character can be, but need not be, backslashed as well.
* * If the resulting token is '<>' (with no backslash), it is returned
* as a non-NULL pointer to the token but with length == 0. Note that
* there is no other way to get a zero-length token.
*
* Returns a pointer to the start of the next token, and the length of the
* token (including any embedded backslashes!) in *length. If there are
* no more tokens, NULL and 0 are returned.
*
* NOTE: this routine doesn't remove backslashes; the caller must do so
* if necessary (see "debackslash").
*
* NOTE: prior to release 7.0, this routine also had a special case to treat
* a token starting with '"' as extending to the next '"'. This code was
* broken, however, since it would fail to cope with a string containing an
* embedded '"'. I have therefore removed this special case, and instead
* introduced rules for using backslashes to quote characters. Higher-level
* code should add backslashes to a string constant to ensure it is treated
* as a single token.
*/
char *
lsptok(char *string, int *length)
{
static char *saved_str = NULL;
char *local_str; /* working pointer to string */
char *ret_str; /* start of token to return */
if (string != NULL)
{
saved_str = string;
if (length == NULL)
return NULL;
}
local_str = saved_str;
while (*local_str == ' ' || *local_str == '\n' || *local_str == '\t')
local_str++;
if (*local_str == '\0')
{
*length = 0;
saved_str = local_str;
return NULL; /* no more tokens */
}
/*
* Now pointing at start of next token.
*/
ret_str = local_str;
if (*local_str == '(' || *local_str == ')' ||
*local_str == '{' || *local_str == '}')
{
/* special 1-character token */
local_str++;
}
else
{
/* Normal token, possibly containing backslashes */
while (*local_str != '\0' &&
*local_str != ' ' && *local_str != '\n' &&
*local_str != '\t' &&
*local_str != '(' && *local_str != ')' &&
*local_str != '{' && *local_str != '}')
{
if (*local_str == '\\' && local_str[1] != '\0')
local_str += 2;
else
local_str++;
}
}
*length = local_str - ret_str;
/* Recognize special case for "empty" token */
if (*length == 2 && ret_str[0] == '<' && ret_str[1] == '>')
*length = 0;
saved_str = local_str;
return ret_str;
}
/*
* debackslash -
* create a palloc'd string holding the given token.
* any protective backslashes in the token are removed.
*/
char *
debackslash(char *token, int length)
{
char *result = palloc(length+1);
char *ptr = result;
while (length > 0)
{
if (*token == '\\' && length > 1)
token++, length--;
*ptr++ = *token++;
length--;
}
*ptr = '\0';
return result;
}
#define RIGHT_PAREN (1000000 + 1) #define RIGHT_PAREN (1000000 + 1)
#define LEFT_PAREN (1000000 + 2) #define LEFT_PAREN (1000000 + 2)
#define PLAN_SYM (1000000 + 3) #define PLAN_SYM (1000000 + 3)
...@@ -62,127 +191,72 @@ stringToNode(char *str) ...@@ -62,127 +191,72 @@ stringToNode(char *str)
static NodeTag static NodeTag
nodeTokenType(char *token, int length) nodeTokenType(char *token, int length)
{ {
NodeTag retval = 0; NodeTag retval;
/* /*
* Check if the token is a number (decimal or integer, positive or * Check if the token is a number (decimal or integer, positive or
* negative * negative)
*/ */
if (isdigit(*token) || if (isdigit(*token) ||
(length >= 2 && *token == '-' && isdigit(*(token + 1)))) (length >= 2 && *token == '-' && isdigit(token[1])))
{ {
/* /*
* skip the optional '-' (i.e. negative number) * skip the optional '-' (i.e. negative number)
*/ */
if (*token == '-') if (*token == '-')
token++; token++, length--;
/* /*
* See if there is a decimal point * See if there is a decimal point
*/ */
while (length > 0 && *token != '.')
for (; length && *token != '.'; token++, length--); token++, length--;
/* /*
* if there isn't, token's an int, otherwise it's a float. * if there isn't, token's an int, otherwise it's a float.
*/ */
retval = (*token != '.') ? T_Integer : T_Float; retval = (*token != '.') ? T_Integer : T_Float;
} }
else if (isalpha(*token) || *token == '_' || /*
(token[0] == '<' && token[1] == '>')) * these three cases do not need length checks, since lsptok()
retval = ATOM_TOKEN; * will always treat them as single-byte tokens
*/
else if (*token == '(') else if (*token == '(')
retval = LEFT_PAREN; retval = LEFT_PAREN;
else if (*token == ')') else if (*token == ')')
retval = RIGHT_PAREN; retval = RIGHT_PAREN;
else if (*token == '@')
retval = AT_SYMBOL;
else if (*token == '\"')
retval = T_String;
else if (*token == '{') else if (*token == '{')
retval = PLAN_SYM; retval = PLAN_SYM;
else if (*token == '@' && length == 1)
retval = AT_SYMBOL;
else if (*token == '\"' && length > 1 && token[length-1] == '\"')
retval = T_String;
else
retval = ATOM_TOKEN;
return retval; return retval;
} }
/* /*
* Works kinda like strtok, except it doesn't put nulls into string. * nodeRead -
* * Slightly higher-level reader.
* Returns the length in length instead. The string can be set without
* returning a token by calling lsptok with length == NULL.
* *
*/ * This routine applies some semantic knowledge on top of the purely
char * * lexical tokenizer lsptok(). It can read
lsptok(char *string, int *length) * * Value token nodes (integers, floats, or strings);
{ * * Plan nodes (via parsePlanString() from readfuncs.c);
static char *local_str; * * Lists of the above.
char *ret_string;
if (string != NULL)
{
local_str = string;
if (length == NULL)
return NULL;
}
for (; *local_str == ' '
|| *local_str == '\n'
|| *local_str == '\t'; local_str++);
/*
* Now pointing at next token.
*/
ret_string = local_str;
if (*local_str == '\0')
return NULL;
*length = 1;
if (*local_str == '"')
{
for (local_str++; *local_str != '"'; (*length)++, local_str++)
;
(*length)++;
local_str++;
}
/* NULL */
else if (local_str[0] == '<' && local_str[1] == '>')
{
*length = 0;
local_str += 2;
}
else if (*local_str == ')' || *local_str == '(' ||
*local_str == '}' || *local_str == '{')
local_str++;
else
{
for (; *local_str != ' '
&& *local_str != '\n'
&& *local_str != '\t'
&& *local_str != '{'
&& *local_str != '}'
&& *local_str != '('
&& *local_str != ')'; local_str++, (*length)++);
(*length)--;
}
return ret_string;
}
/*
* This guy does all the reading.
* *
* Secrets: He assumes that lsptok already has the string (see below). * Secrets: He assumes that lsptok already has the string (see above).
* Any callers should set read_car_only to true. * Any callers should set read_car_only to true.
*/ */
void * void *
nodeRead(bool read_car_only) nodeRead(bool read_car_only)
{ {
char *token; char *token;
NodeTag type;
Node *this_value = NULL,
*return_value = NULL;
int tok_len; int tok_len;
char tmp; NodeTag type;
Node *this_value,
*return_value;
bool make_dotted_pair_cell = false; bool make_dotted_pair_cell = false;
token = lsptok(NULL, &tok_len); token = lsptok(NULL, &tok_len);
...@@ -198,8 +272,7 @@ nodeRead(bool read_car_only) ...@@ -198,8 +272,7 @@ nodeRead(bool read_car_only)
this_value = parsePlanString(); this_value = parsePlanString();
token = lsptok(NULL, &tok_len); token = lsptok(NULL, &tok_len);
if (token[0] != '}') if (token[0] != '}')
return NULL; elog(ERROR, "nodeRead: did not find '}' at end of plan node");
if (!read_car_only) if (!read_car_only)
make_dotted_pair_cell = true; make_dotted_pair_cell = true;
else else
...@@ -221,12 +294,13 @@ nodeRead(bool read_car_only) ...@@ -221,12 +294,13 @@ nodeRead(bool read_car_only)
this_value = NULL; this_value = NULL;
break; break;
case AT_SYMBOL: case AT_SYMBOL:
this_value = NULL;
break; break;
case ATOM_TOKEN: case ATOM_TOKEN:
if (!strncmp(token, "<>", 2)) if (tok_len == 0)
{ {
/* must be "<>" */
this_value = NULL; this_value = NULL;
/* /*
* It might be NULL but it is an atom! * It might be NULL but it is an atom!
*/ */
...@@ -237,39 +311,28 @@ nodeRead(bool read_car_only) ...@@ -237,39 +311,28 @@ nodeRead(bool read_car_only)
} }
else else
{ {
tmp = token[tok_len]; /* !attention! result is not a Node. Use with caution. */
token[tok_len] = '\0'; this_value = (Node *) debackslash(token, tok_len);
this_value = (Node *) pstrdup(token); /* !attention! not a
* Node. use with
* caution */
token[tok_len] = tmp;
make_dotted_pair_cell = true; make_dotted_pair_cell = true;
} }
break; break;
case T_Float: case T_Float:
tmp = token[tok_len]; /* we know that the token terminates on a char atof will stop at */
token[tok_len] = '\0';
this_value = (Node *) makeFloat(atof(token)); this_value = (Node *) makeFloat(atof(token));
token[tok_len] = tmp;
make_dotted_pair_cell = true; make_dotted_pair_cell = true;
break; break;
case T_Integer: case T_Integer:
tmp = token[tok_len]; /* we know that the token terminates on a char atoi will stop at */
token[tok_len] = '\0';
this_value = (Node *) makeInteger(atoi(token)); this_value = (Node *) makeInteger(atoi(token));
token[tok_len] = tmp;
make_dotted_pair_cell = true; make_dotted_pair_cell = true;
break; break;
case T_String: case T_String:
tmp = token[tok_len - 1]; this_value = (Node *) makeString(debackslash(token+1, tok_len-2));
token[tok_len - 1] = '\0';
token++;
this_value = (Node *) makeString(token); /* !! not strdup'd */
token[tok_len - 2] = tmp;
make_dotted_pair_cell = true; make_dotted_pair_cell = true;
break; break;
default: default:
elog(ERROR, "nodeRead: Bad type %d", type); elog(ERROR, "nodeRead: Bad type %d", type);
this_value = NULL; /* keep compiler happy */
break; break;
} }
if (make_dotted_pair_cell) if (make_dotted_pair_cell)
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.77 2000/01/09 00:26:24 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.78 2000/01/14 00:53:21 tgl Exp $
* *
* NOTES * NOTES
* Most of the read functions for plan nodes are tested. (In fact, they * Most of the read functions for plan nodes are tested. (In fact, they
...@@ -26,8 +26,6 @@ ...@@ -26,8 +26,6 @@
#include "postgres.h" #include "postgres.h"
#include "catalog/pg_index.h" #include "catalog/pg_index.h"
#include "nodes/plannodes.h" #include "nodes/plannodes.h"
#include "nodes/readfuncs.h" #include "nodes/readfuncs.h"
...@@ -81,8 +79,7 @@ _readQuery() ...@@ -81,8 +79,7 @@ _readQuery()
{ {
NotifyStmt *n = makeNode(NotifyStmt); NotifyStmt *n = makeNode(NotifyStmt);
n->relname = palloc(length + 1); n->relname = debackslash(token, length);
StrNCpy(n->relname, token, length + 1);
local_node->utilityStmt = (Node *) n; local_node->utilityStmt = (Node *) n;
} }
...@@ -95,10 +92,7 @@ _readQuery() ...@@ -95,10 +92,7 @@ _readQuery()
if (length == 0) if (length == 0)
local_node->into = NULL; local_node->into = NULL;
else else
{ local_node->into = debackslash(token, length);
local_node->into = palloc(length + 1);
StrNCpy(local_node->into, token, length + 1);
}
token = lsptok(NULL, &length); /* skip :isPortal */ token = lsptok(NULL, &length); /* skip :isPortal */
token = lsptok(NULL, &length); /* get isPortal */ token = lsptok(NULL, &length); /* get isPortal */
...@@ -121,10 +115,7 @@ _readQuery() ...@@ -121,10 +115,7 @@ _readQuery()
if (length == 0) if (length == 0)
local_node->uniqueFlag = NULL; local_node->uniqueFlag = NULL;
else else
{ local_node->uniqueFlag = debackslash(token, length);
local_node->uniqueFlag = palloc(length + 1);
StrNCpy(local_node->uniqueFlag, token, length + 1);
}
token = lsptok(NULL, &length); /* skip :sortClause */ token = lsptok(NULL, &length); /* skip :sortClause */
local_node->sortClause = nodeRead(true); local_node->sortClause = nodeRead(true);
...@@ -289,9 +280,6 @@ _readPlan() ...@@ -289,9 +280,6 @@ _readPlan()
/* ---------------- /* ----------------
* _readResult * _readResult
*
* Does some obscene, possibly unportable, magic with
* sizes of things.
* ---------------- * ----------------
*/ */
static Result * static Result *
...@@ -718,14 +706,10 @@ _readResdom() ...@@ -718,14 +706,10 @@ _readResdom()
token = lsptok(NULL, &length); /* eat :resname */ token = lsptok(NULL, &length); /* eat :resname */
token = lsptok(NULL, &length); /* get the name */ token = lsptok(NULL, &length); /* get the name */
if (length == 0) if (length == 0)
local_node->resname = NULL; local_node->resname = NULL;
else else
{ local_node->resname = debackslash(token, length);
local_node->resname = (char *) palloc(length + 1);
StrNCpy(local_node->resname, token + 1, length + 1 - 2); /* strip quotes */
}
token = lsptok(NULL, &length); /* eat :reskey */ token = lsptok(NULL, &length); /* eat :reskey */
token = lsptok(NULL, &length); /* get reskey */ token = lsptok(NULL, &length); /* get reskey */
...@@ -779,6 +763,8 @@ _readExpr() ...@@ -779,6 +763,8 @@ _readExpr()
local_node->opType = NOT_EXPR; local_node->opType = NOT_EXPR;
else if (!strncmp(token, "subp", 4)) else if (!strncmp(token, "subp", 4))
local_node->opType = SUBPLAN_EXPR; local_node->opType = SUBPLAN_EXPR;
else
elog(ERROR, "_readExpr: unknown opType \"%.10s\"", token);
token = lsptok(NULL, &length); /* eat :oper */ token = lsptok(NULL, &length); /* eat :oper */
local_node->oper = nodeRead(true); local_node->oper = nodeRead(true);
...@@ -1140,10 +1126,7 @@ _readParam() ...@@ -1140,10 +1126,7 @@ _readParam()
if (length == 0) if (length == 0)
local_node->paramname = NULL; local_node->paramname = NULL;
else else
{ local_node->paramname = debackslash(token, length);
local_node->paramname = (char *) palloc(length + 1);
StrNCpy(local_node->paramname, token, length + 1);
}
token = lsptok(NULL, &length); /* get :paramtype */ token = lsptok(NULL, &length); /* get :paramtype */
token = lsptok(NULL, &length); /* now read it */ token = lsptok(NULL, &length); /* now read it */
...@@ -1172,8 +1155,7 @@ _readAggref() ...@@ -1172,8 +1155,7 @@ _readAggref()
token = lsptok(NULL, &length); /* eat :aggname */ token = lsptok(NULL, &length); /* eat :aggname */
token = lsptok(NULL, &length); /* get aggname */ token = lsptok(NULL, &length); /* get aggname */
local_node->aggname = (char *) palloc(length + 1); local_node->aggname = debackslash(token, length);
StrNCpy(local_node->aggname, token, length + 1);
token = lsptok(NULL, &length); /* eat :basetype */ token = lsptok(NULL, &length); /* eat :basetype */
token = lsptok(NULL, &length); /* get basetype */ token = lsptok(NULL, &length); /* get basetype */
...@@ -1416,20 +1398,14 @@ _readRangeTblEntry() ...@@ -1416,20 +1398,14 @@ _readRangeTblEntry()
if (length == 0) if (length == 0)
local_node->relname = NULL; local_node->relname = NULL;
else else
{ local_node->relname = debackslash(token, length);
local_node->relname = (char *) palloc(length + 1);
StrNCpy(local_node->relname, token, length + 1);
}
token = lsptok(NULL, &length); /* eat :refname */ token = lsptok(NULL, &length); /* eat :refname */
token = lsptok(NULL, &length); /* get :refname */ token = lsptok(NULL, &length); /* get :refname */
if (length == 0) if (length == 0)
local_node->refname = NULL; local_node->refname = NULL;
else else
{ local_node->refname = debackslash(token, length);
local_node->refname = (char *) palloc(length + 1);
StrNCpy(local_node->refname, token, length + 1);
}
token = lsptok(NULL, &length); /* eat :relid */ token = lsptok(NULL, &length); /* eat :relid */
token = lsptok(NULL, &length); /* get :relid */ token = lsptok(NULL, &length); /* get :relid */
...@@ -1854,7 +1830,7 @@ _readIter() ...@@ -1854,7 +1830,7 @@ _readIter()
* Given a character string containing a plan, parsePlanString sets up the * Given a character string containing a plan, parsePlanString sets up the
* plan structure representing that plan. * plan structure representing that plan.
* *
* The string passed to parsePlanString must be null-terminated. * The string to be read must already have been loaded into lsptok().
* ---------------- * ----------------
*/ */
Node * Node *
...@@ -1866,101 +1842,101 @@ parsePlanString(void) ...@@ -1866,101 +1842,101 @@ parsePlanString(void)
token = lsptok(NULL, &length); token = lsptok(NULL, &length);
if (!strncmp(token, "PLAN", length)) if (length == 4 && strncmp(token, "PLAN", length) == 0)
return_value = _readPlan(); return_value = _readPlan();
else if (!strncmp(token, "RESULT", length)) else if (length == 6 && strncmp(token, "RESULT", length) == 0)
return_value = _readResult(); return_value = _readResult();
else if (!strncmp(token, "APPEND", length)) else if (length == 6 && strncmp(token, "APPEND", length) == 0)
return_value = _readAppend(); return_value = _readAppend();
else if (!strncmp(token, "JOIN", length)) else if (length == 4 && strncmp(token, "JOIN", length) == 0)
return_value = _readJoin(); return_value = _readJoin();
else if (!strncmp(token, "NESTLOOP", length)) else if (length == 8 && strncmp(token, "NESTLOOP", length) == 0)
return_value = _readNestLoop(); return_value = _readNestLoop();
else if (!strncmp(token, "MERGEJOIN", length)) else if (length == 9 && strncmp(token, "MERGEJOIN", length) == 0)
return_value = _readMergeJoin(); return_value = _readMergeJoin();
else if (!strncmp(token, "HASHJOIN", length)) else if (length == 8 && strncmp(token, "HASHJOIN", length) == 0)
return_value = _readHashJoin(); return_value = _readHashJoin();
else if (!strncmp(token, "SCAN", length)) else if (length == 4 && strncmp(token, "SCAN", length) == 0)
return_value = _readScan(); return_value = _readScan();
else if (!strncmp(token, "SEQSCAN", length)) else if (length == 7 && strncmp(token, "SEQSCAN", length) == 0)
return_value = _readSeqScan(); return_value = _readSeqScan();
else if (!strncmp(token, "INDEXSCAN", length)) else if (length == 9 && strncmp(token, "INDEXSCAN", length) == 0)
return_value = _readIndexScan(); return_value = _readIndexScan();
else if (!strncmp(token, "TIDSCAN", length)) else if (length == 7 && strncmp(token, "TIDSCAN", length) == 0)
return_value = _readTidScan(); return_value = _readTidScan();
else if (!strncmp(token, "NONAME", length)) else if (length == 6 && strncmp(token, "NONAME", length) == 0)
return_value = _readNoname(); return_value = _readNoname();
else if (!strncmp(token, "SORT", length)) else if (length == 4 && strncmp(token, "SORT", length) == 0)
return_value = _readSort(); return_value = _readSort();
else if (!strncmp(token, "AGGREG", length)) else if (length == 6 && strncmp(token, "AGGREG", length) == 0)
return_value = _readAggref(); return_value = _readAggref();
else if (!strncmp(token, "SUBLINK", length)) else if (length == 7 && strncmp(token, "SUBLINK", length) == 0)
return_value = _readSubLink(); return_value = _readSubLink();
else if (!strncmp(token, "AGG", length)) else if (length == 3 && strncmp(token, "AGG", length) == 0)
return_value = _readAgg(); return_value = _readAgg();
else if (!strncmp(token, "UNIQUE", length)) else if (length == 6 && strncmp(token, "UNIQUE", length) == 0)
return_value = _readUnique(); return_value = _readUnique();
else if (!strncmp(token, "HASH", length)) else if (length == 4 && strncmp(token, "HASH", length) == 0)
return_value = _readHash(); return_value = _readHash();
else if (!strncmp(token, "RESDOM", length)) else if (length == 6 && strncmp(token, "RESDOM", length) == 0)
return_value = _readResdom(); return_value = _readResdom();
else if (!strncmp(token, "EXPR", length)) else if (length == 4 && strncmp(token, "EXPR", length) == 0)
return_value = _readExpr(); return_value = _readExpr();
else if (!strncmp(token, "ARRAYREF", length)) else if (length == 8 && strncmp(token, "ARRAYREF", length) == 0)
return_value = _readArrayRef(); return_value = _readArrayRef();
else if (!strncmp(token, "ARRAY", length)) else if (length == 5 && strncmp(token, "ARRAY", length) == 0)
return_value = _readArray(); return_value = _readArray();
else if (!strncmp(token, "VAR", length)) else if (length == 3 && strncmp(token, "VAR", length) == 0)
return_value = _readVar(); return_value = _readVar();
else if (!strncmp(token, "CONST", length)) else if (length == 5 && strncmp(token, "CONST", length) == 0)
return_value = _readConst(); return_value = _readConst();
else if (!strncmp(token, "FUNC", length)) else if (length == 4 && strncmp(token, "FUNC", length) == 0)
return_value = _readFunc(); return_value = _readFunc();
else if (!strncmp(token, "OPER", length)) else if (length == 4 && strncmp(token, "OPER", length) == 0)
return_value = _readOper(); return_value = _readOper();
else if (!strncmp(token, "PARAM", length)) else if (length == 5 && strncmp(token, "PARAM", length) == 0)
return_value = _readParam(); return_value = _readParam();
else if (!strncmp(token, "ESTATE", length)) else if (length == 6 && strncmp(token, "ESTATE", length) == 0)
return_value = _readEState(); return_value = _readEState();
else if (!strncmp(token, "RELOPTINFO", length)) else if (length == 10 && strncmp(token, "RELOPTINFO", length) == 0)
return_value = _readRelOptInfo(); return_value = _readRelOptInfo();
else if (!strncmp(token, "INDEXOPTINFO", length)) else if (length == 12 && strncmp(token, "INDEXOPTINFO", length) == 0)
return_value = _readIndexOptInfo(); return_value = _readIndexOptInfo();
else if (!strncmp(token, "TARGETENTRY", length)) else if (length == 11 && strncmp(token, "TARGETENTRY", length) == 0)
return_value = _readTargetEntry(); return_value = _readTargetEntry();
else if (!strncmp(token, "RTE", length)) else if (length == 3 && strncmp(token, "RTE", length) == 0)
return_value = _readRangeTblEntry(); return_value = _readRangeTblEntry();
else if (!strncmp(token, "PATH", length)) else if (length == 4 && strncmp(token, "PATH", length) == 0)
return_value = _readPath(); return_value = _readPath();
else if (!strncmp(token, "INDEXPATH", length)) else if (length == 9 && strncmp(token, "INDEXPATH", length) == 0)
return_value = _readIndexPath(); return_value = _readIndexPath();
else if (!strncmp(token, "TIDPATH", length)) else if (length == 7 && strncmp(token, "TIDPATH", length) == 0)
return_value = _readTidPath(); return_value = _readTidPath();
else if (!strncmp(token, "NESTPATH", length)) else if (length == 8 && strncmp(token, "NESTPATH", length) == 0)
return_value = _readNestPath(); return_value = _readNestPath();
else if (!strncmp(token, "MERGEPATH", length)) else if (length == 9 && strncmp(token, "MERGEPATH", length) == 0)
return_value = _readMergePath(); return_value = _readMergePath();
else if (!strncmp(token, "HASHPATH", length)) else if (length == 8 && strncmp(token, "HASHPATH", length) == 0)
return_value = _readHashPath(); return_value = _readHashPath();
else if (!strncmp(token, "PATHKEYITEM", length)) else if (length == 11 && strncmp(token, "PATHKEYITEM", length) == 0)
return_value = _readPathKeyItem(); return_value = _readPathKeyItem();
else if (!strncmp(token, "RESTRICTINFO", length)) else if (length == 12 && strncmp(token, "RESTRICTINFO", length) == 0)
return_value = _readRestrictInfo(); return_value = _readRestrictInfo();
else if (!strncmp(token, "JOININFO", length)) else if (length == 8 && strncmp(token, "JOININFO", length) == 0)
return_value = _readJoinInfo(); return_value = _readJoinInfo();
else if (!strncmp(token, "ITER", length)) else if (length == 4 && strncmp(token, "ITER", length) == 0)
return_value = _readIter(); return_value = _readIter();
else if (!strncmp(token, "QUERY", length)) else if (length == 5 && strncmp(token, "QUERY", length) == 0)
return_value = _readQuery(); return_value = _readQuery();
else if (!strncmp(token, "SORTCLAUSE", length)) else if (length == 10 && strncmp(token, "SORTCLAUSE", length) == 0)
return_value = _readSortClause(); return_value = _readSortClause();
else if (!strncmp(token, "GROUPCLAUSE", length)) else if (length == 11 && strncmp(token, "GROUPCLAUSE", length) == 0)
return_value = _readGroupClause(); return_value = _readGroupClause();
else if (!strncmp(token, "CASE", length)) else if (length == 4 && strncmp(token, "CASE", length) == 0)
return_value = _readCaseExpr(); return_value = _readCaseExpr();
else if (!strncmp(token, "WHEN", length)) else if (length == 4 && strncmp(token, "WHEN", length) == 0)
return_value = _readCaseWhen(); return_value = _readCaseWhen();
else if (!strncmp(token, "ROWMARK", length)) else if (length == 7 && strncmp(token, "ROWMARK", length) == 0)
return_value = _readRowMark(); return_value = _readRowMark();
else else
elog(ERROR, "badly formatted planstring \"%.10s\"...\n", token); elog(ERROR, "badly formatted planstring \"%.10s\"...\n", token);
...@@ -2001,6 +1977,7 @@ readDatum(Oid type) ...@@ -2001,6 +1977,7 @@ readDatum(Oid type)
{ {
if (length > sizeof(Datum)) if (length > sizeof(Datum))
elog(ERROR, "readValue: byval & length = %d", length); elog(ERROR, "readValue: byval & length = %d", length);
res = (Datum) 0;
s = (char *) (&res); s = (char *) (&res);
for (i = 0; i < sizeof(Datum); i++) for (i = 0; i < sizeof(Datum); i++)
{ {
...@@ -2009,11 +1986,10 @@ readDatum(Oid type) ...@@ -2009,11 +1986,10 @@ readDatum(Oid type)
} }
} }
else if (length <= 0) else if (length <= 0)
s = NULL; res = (Datum) NULL;
else if (length >= 1) else
{ {
s = (char *) palloc(length); s = (char *) palloc(length);
Assert(s != NULL);
for (i = 0; i < length; i++) for (i = 0; i < length; i++)
{ {
token = lsptok(NULL, &tokenLength); token = lsptok(NULL, &tokenLength);
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: readfuncs.h,v 1.7 1999/02/13 23:21:41 momjian Exp $ * $Id: readfuncs.h,v 1.8 2000/01/14 00:53:20 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
* prototypes for functions in read.c (the lisp token parser) * prototypes for functions in read.c (the lisp token parser)
*/ */
extern char *lsptok(char *string, int *length); extern char *lsptok(char *string, int *length);
extern char *debackslash(char *token, int length);
extern void *nodeRead(bool read_car_only); extern void *nodeRead(bool read_car_only);
/* /*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment