mirror of
https://github.com/postgres/postgres.git
synced 2025-07-30 11:03:19 +03:00
Rewrite nodeRead() in a less obfuscated fashion, per discussion with
Neil Conway.
This commit is contained in:
@ -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)
|
|||||||
/* 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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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 @@
|
|||||||
#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)
|
|||||||
|
|
||||||
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)
|
|||||||
|
|
||||||
#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)
|
|||||||
* 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)
|
|||||||
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)
|
|||||||
* * 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");
|
||||||
|
result = NULL; /* keep compiler happy */
|
||||||
break;
|
break;
|
||||||
case AT_SYMBOL:
|
case OTHER_TOKEN:
|
||||||
this_value = NULL;
|
|
||||||
break;
|
|
||||||
case ATOM_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)
|
|||||||
* 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)
|
|||||||
|
|
||||||
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)
|
|||||||
/* 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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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 @@
|
|||||||
/* 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 @@
|
|||||||
* 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 @@
|
|||||||
*/
|
*/
|
||||||
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
|
||||||
|
Reference in New Issue
Block a user