Commit eee6f9d5 authored by Tom Lane's avatar Tom Lane

Rewrite nodeRead() in a less obfuscated fashion, per discussion with

Neil Conway.
parent 839be02e
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.233 2004/03/17 20:48:42 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.234 2004/05/06 14:01:33 tgl Exp $
* *
* NOTES * NOTES
* Every node type that can appear in stored rules' parsetrees *must* * Every node type that can appear in stored rules' parsetrees *must*
...@@ -130,7 +130,6 @@ _outToken(StringInfo str, char *s) ...@@ -130,7 +130,6 @@ _outToken(StringInfo str, char *s)
/* These characters only need to be quoted at the start of the string */ /* These characters only need to be quoted at the start of the string */
if (*s == '<' || if (*s == '<' ||
*s == '\"' || *s == '\"' ||
*s == '@' ||
isdigit((unsigned char) *s) || isdigit((unsigned char) *s) ||
((*s == '+' || *s == '-') && ((*s == '+' || *s == '-') &&
(isdigit((unsigned char) s[1]) || s[1] == '.'))) (isdigit((unsigned char) s[1]) || s[1] == '.')))
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/read.c,v 1.39 2004/01/09 03:07:32 momjian Exp $ * $PostgreSQL: pgsql/src/backend/nodes/read.c,v 1.40 2004/05/06 14:01:33 tgl Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include "postgres.h" #include "postgres.h"
#include <ctype.h> #include <ctype.h>
#include <errno.h>
#include "nodes/pg_list.h" #include "nodes/pg_list.h"
#include "nodes/readfuncs.h" #include "nodes/readfuncs.h"
...@@ -51,7 +50,7 @@ stringToNode(char *str) ...@@ -51,7 +50,7 @@ stringToNode(char *str)
pg_strtok_ptr = str; /* point pg_strtok at the string to read */ pg_strtok_ptr = str; /* point pg_strtok at the string to read */
retval = nodeRead(true); /* do the reading */ retval = nodeRead(NULL, 0); /* do the reading */
pg_strtok_ptr = save_strtok; pg_strtok_ptr = save_strtok;
...@@ -184,9 +183,8 @@ debackslash(char *token, int length) ...@@ -184,9 +183,8 @@ debackslash(char *token, int length)
#define RIGHT_PAREN (1000000 + 1) #define RIGHT_PAREN (1000000 + 1)
#define LEFT_PAREN (1000000 + 2) #define LEFT_PAREN (1000000 + 2)
#define NODE_SYM (1000000 + 3) #define LEFT_BRACE (1000000 + 3)
#define AT_SYMBOL (1000000 + 4) #define OTHER_TOKEN (1000000 + 4)
#define ATOM_TOKEN (1000000 + 5)
/* /*
* nodeTokenType - * nodeTokenType -
...@@ -194,7 +192,7 @@ debackslash(char *token, int length) ...@@ -194,7 +192,7 @@ debackslash(char *token, int length)
* It returns one of the following valid NodeTags: * It returns one of the following valid NodeTags:
* T_Integer, T_Float, T_String, T_BitString * T_Integer, T_Float, T_String, T_BitString
* and some of its own: * and some of its own:
* RIGHT_PAREN, LEFT_PAREN, NODE_SYM, AT_SYMBOL, ATOM_TOKEN * RIGHT_PAREN, LEFT_PAREN, LEFT_BRACE, OTHER_TOKEN
* *
* Assumption: the ascii representation is legal * Assumption: the ascii representation is legal
*/ */
...@@ -245,15 +243,13 @@ nodeTokenType(char *token, int length) ...@@ -245,15 +243,13 @@ nodeTokenType(char *token, int length)
else if (*token == ')') else if (*token == ')')
retval = RIGHT_PAREN; retval = RIGHT_PAREN;
else if (*token == '{') else if (*token == '{')
retval = NODE_SYM; retval = LEFT_BRACE;
else if (*token == '@' && length == 1)
retval = AT_SYMBOL;
else if (*token == '\"' && length > 1 && token[length - 1] == '\"') else if (*token == '\"' && length > 1 && token[length - 1] == '\"')
retval = T_String; retval = T_String;
else if (*token == 'b') else if (*token == 'b')
retval = T_BitString; retval = T_BitString;
else else
retval = ATOM_TOKEN; retval = OTHER_TOKEN;
return retval; return retval;
} }
...@@ -266,77 +262,70 @@ nodeTokenType(char *token, int length) ...@@ -266,77 +262,70 @@ nodeTokenType(char *token, int length)
* * Value token nodes (integers, floats, or strings); * * Value token nodes (integers, floats, or strings);
* * General nodes (via parseNodeString() from readfuncs.c); * * General nodes (via parseNodeString() from readfuncs.c);
* * Lists of the above. * * Lists of the above.
* The return value is declared void *, not Node *, to avoid having to
* cast it explicitly in callers that assign to fields of different types.
*
* External callers should always pass NULL/0 for the arguments. Internally
* a non-NULL token may be passed when the upper recursion level has already
* scanned the first token of a node's representation.
* *
* We assume pg_strtok is already initialized with a string to read (hence * We assume pg_strtok is already initialized with a string to read (hence
* this should only be invoked from within a stringToNode operation). * this should only be invoked from within a stringToNode operation).
* Any callers should set read_car_only to true.
*/ */
void * void *
nodeRead(bool read_car_only) nodeRead(char *token, int tok_len)
{ {
char *token; Node *result;
int tok_len;
NodeTag type; NodeTag type;
Node *this_value,
*return_value;
bool make_dotted_pair_cell = false;
token = pg_strtok(&tok_len); if (token == NULL) /* need to read a token? */
{
token = pg_strtok(&tok_len);
if (token == NULL) if (token == NULL) /* end of input */
return NULL; return NULL;
}
type = nodeTokenType(token, tok_len); type = nodeTokenType(token, tok_len);
switch (type) switch (type)
{ {
case NODE_SYM: case LEFT_BRACE:
this_value = parseNodeString(); result = parseNodeString();
token = pg_strtok(&tok_len); token = pg_strtok(&tok_len);
if (token == NULL || token[0] != '}') if (token == NULL || token[0] != '}')
elog(ERROR, "did not find '}' at end of input node"); elog(ERROR, "did not find '}' at end of input node");
if (!read_car_only)
make_dotted_pair_cell = true;
else
make_dotted_pair_cell = false;
break; break;
case LEFT_PAREN: case LEFT_PAREN:
if (!read_car_only)
{ {
List *l = makeNode(List); List *l = NIL;
lfirst(l) = nodeRead(false); for (;;)
lnext(l) = nodeRead(false); {
this_value = (Node *) l; token = pg_strtok(&tok_len);
if (token == NULL)
elog(ERROR, "unterminated List structure");
if (token[0] == ')')
break;
l = lappend(l, nodeRead(token, tok_len));
}
result = (Node *) l;
break;
} }
else
this_value = nodeRead(false);
break;
case RIGHT_PAREN: case RIGHT_PAREN:
this_value = NULL; elog(ERROR, "unexpected right parenthesis");
break; result = NULL; /* keep compiler happy */
case AT_SYMBOL:
this_value = NULL;
break; break;
case ATOM_TOKEN: case OTHER_TOKEN:
if (tok_len == 0) if (tok_len == 0)
{ {
/* must be "<>" */ /* must be "<>" --- represents a null pointer */
this_value = NULL; result = NULL;
/*
* It might be NULL but it is an atom!
*/
if (read_car_only)
make_dotted_pair_cell = false;
else
make_dotted_pair_cell = true;
} }
else else
{ {
/* !attention! result is not a Node. Use with caution. */ elog(ERROR, "unrecognized token: \"%.*s\"", tok_len, token);
this_value = (Node *) debackslash(token, tok_len); result = NULL; /* keep compiler happy */
make_dotted_pair_cell = true;
} }
break; break;
case T_Integer: case T_Integer:
...@@ -345,8 +334,7 @@ nodeRead(bool read_car_only) ...@@ -345,8 +334,7 @@ nodeRead(bool read_car_only)
* we know that the token terminates on a char atol will stop * we know that the token terminates on a char atol will stop
* at * at
*/ */
this_value = (Node *) makeInteger(atol(token)); result = (Node *) makeInteger(atol(token));
make_dotted_pair_cell = true;
break; break;
case T_Float: case T_Float:
{ {
...@@ -354,14 +342,12 @@ nodeRead(bool read_car_only) ...@@ -354,14 +342,12 @@ nodeRead(bool read_car_only)
memcpy(fval, token, tok_len); memcpy(fval, token, tok_len);
fval[tok_len] = '\0'; fval[tok_len] = '\0';
this_value = (Node *) makeFloat(fval); result = (Node *) makeFloat(fval);
make_dotted_pair_cell = true;
} }
break; break;
case T_String: case T_String:
/* need to remove leading and trailing quotes, and backslashes */ /* need to remove leading and trailing quotes, and backslashes */
this_value = (Node *) makeString(debackslash(token + 1, tok_len - 2)); result = (Node *) makeString(debackslash(token + 1, tok_len - 2));
make_dotted_pair_cell = true;
break; break;
case T_BitString: case T_BitString:
{ {
...@@ -370,27 +356,14 @@ nodeRead(bool read_car_only) ...@@ -370,27 +356,14 @@ nodeRead(bool read_car_only)
/* skip leading 'b' */ /* skip leading 'b' */
strncpy(val, token + 1, tok_len - 1); strncpy(val, token + 1, tok_len - 1);
val[tok_len - 1] = '\0'; val[tok_len - 1] = '\0';
this_value = (Node *) makeBitString(val); result = (Node *) makeBitString(val);
break; break;
} }
default: default:
elog(ERROR, "unrecognized node type: %d", (int) type); elog(ERROR, "unrecognized node type: %d", (int) type);
this_value = NULL; /* keep compiler happy */ result = NULL; /* keep compiler happy */
break; break;
} }
if (make_dotted_pair_cell)
{
List *l = makeNode(List);
lfirst(l) = this_value; return (void *) result;
if (!read_car_only)
lnext(l) = nodeRead(false);
else
lnext(l) = NULL;
return_value = (Node *) l;
}
else
return_value = this_value;
return return_value;
} }
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.166 2004/03/17 20:48:42 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.167 2004/05/06 14:01:33 tgl Exp $
* *
* NOTES * NOTES
* Path and Plan nodes do not have any readfuncs support, because we * Path and Plan nodes do not have any readfuncs support, because we
...@@ -99,17 +99,17 @@ ...@@ -99,17 +99,17 @@
/* Read a Node field */ /* Read a Node field */
#define READ_NODE_FIELD(fldname) \ #define READ_NODE_FIELD(fldname) \
token = pg_strtok(&length); /* skip :fldname */ \ token = pg_strtok(&length); /* skip :fldname */ \
local_node->fldname = nodeRead(true) local_node->fldname = nodeRead(NULL, 0)
/* Read an integer-list field */ /* Read an integer-list field */
#define READ_INTLIST_FIELD(fldname) \ #define READ_INTLIST_FIELD(fldname) \
token = pg_strtok(&length); /* skip :fldname */ \ token = pg_strtok(&length); /* skip :fldname */ \
local_node->fldname = toIntList(nodeRead(true)) local_node->fldname = toIntList(nodeRead(NULL, 0))
/* Read an OID-list field */ /* Read an OID-list field */
#define READ_OIDLIST_FIELD(fldname) \ #define READ_OIDLIST_FIELD(fldname) \
token = pg_strtok(&length); /* skip :fldname */ \ token = pg_strtok(&length); /* skip :fldname */ \
local_node->fldname = toOidList(nodeRead(true)) local_node->fldname = toOidList(nodeRead(NULL, 0))
/* Routine exit */ /* Routine exit */
#define READ_DONE() \ #define READ_DONE() \
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/nodes/readfuncs.h,v 1.18 2003/11/29 22:41:06 pgsql Exp $ * $PostgreSQL: pgsql/src/include/nodes/readfuncs.h,v 1.19 2004/05/06 14:01:33 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
*/ */
extern char *pg_strtok(int *length); extern char *pg_strtok(int *length);
extern char *debackslash(char *token, int length); extern char *debackslash(char *token, int length);
extern void *nodeRead(bool read_car_only); extern void *nodeRead(char *token, int tok_len);
/* /*
* prototypes for functions in readfuncs.c * prototypes for functions in readfuncs.c
......
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