Header And Logo

PostgreSQL
| The world's most advanced open source database.

Defines | Functions | Variables

read.c File Reference

#include "postgres.h"
#include <ctype.h>
#include "nodes/pg_list.h"
#include "nodes/readfuncs.h"
#include "nodes/value.h"
Include dependency graph for read.c:

Go to the source code of this file.

Defines

#define RIGHT_PAREN   (1000000 + 1)
#define LEFT_PAREN   (1000000 + 2)
#define LEFT_BRACE   (1000000 + 3)
#define OTHER_TOKEN   (1000000 + 4)

Functions

void * stringToNode (char *str)
char * pg_strtok (int *length)
char * debackslash (char *token, int length)
static NodeTag nodeTokenType (char *token, int length)
void * nodeRead (char *token, int tok_len)

Variables

static char * pg_strtok_ptr = NULL

Define Documentation

#define LEFT_BRACE   (1000000 + 3)

Definition at line 186 of file read.c.

Referenced by nodeRead().

#define LEFT_PAREN   (1000000 + 2)

Definition at line 185 of file read.c.

Referenced by nodeRead().

#define OTHER_TOKEN   (1000000 + 4)

Definition at line 187 of file read.c.

Referenced by nodeRead().

#define RIGHT_PAREN   (1000000 + 1)

Definition at line 184 of file read.c.

Referenced by nodeRead().


Function Documentation

char* debackslash ( char *  token,
int  length 
)

Definition at line 168 of file read.c.

References palloc().

Referenced by nodeRead().

{
    char       *result = palloc(length + 1);
    char       *ptr = result;

    while (length > 0)
    {
        if (*token == '\\' && length > 1)
            token++, length--;
        *ptr++ = *token++;
        length--;
    }
    *ptr = '\0';
    return result;
}

void* nodeRead ( char *  token,
int  tok_len 
)

Definition at line 278 of file read.c.

References debackslash(), elog, ERROR, lappend(), lappend_int(), lappend_oid(), LEFT_BRACE, LEFT_PAREN, makeBitString(), makeFloat(), makeInteger(), makeString(), nodeRead(), nodeTokenType(), NULL, OTHER_TOKEN, palloc(), parseNodeString(), pg_strtok(), RIGHT_PAREN, T_BitString, T_Float, T_Integer, T_String, and val.

Referenced by nodeRead(), and stringToNode().

{
    Node       *result;
    NodeTag     type;

    if (token == NULL)          /* need to read a token? */
    {
        token = pg_strtok(&tok_len);

        if (token == NULL)      /* end of input */
            return NULL;
    }

    type = nodeTokenType(token, tok_len);

    switch ((int) type)
    {
        case LEFT_BRACE:
            result = parseNodeString();
            token = pg_strtok(&tok_len);
            if (token == NULL || token[0] != '}')
                elog(ERROR, "did not find '}' at end of input node");
            break;
        case LEFT_PAREN:
            {
                List       *l = NIL;

                /*----------
                 * Could be an integer list:    (i int int ...)
                 * or an OID list:              (o int int ...)
                 * or a list of nodes/values:   (node node ...)
                 *----------
                 */
                token = pg_strtok(&tok_len);
                if (token == NULL)
                    elog(ERROR, "unterminated List structure");
                if (tok_len == 1 && token[0] == 'i')
                {
                    /* List of integers */
                    for (;;)
                    {
                        int         val;
                        char       *endptr;

                        token = pg_strtok(&tok_len);
                        if (token == NULL)
                            elog(ERROR, "unterminated List structure");
                        if (token[0] == ')')
                            break;
                        val = (int) strtol(token, &endptr, 10);
                        if (endptr != token + tok_len)
                            elog(ERROR, "unrecognized integer: \"%.*s\"",
                                 tok_len, token);
                        l = lappend_int(l, val);
                    }
                }
                else if (tok_len == 1 && token[0] == 'o')
                {
                    /* List of OIDs */
                    for (;;)
                    {
                        Oid         val;
                        char       *endptr;

                        token = pg_strtok(&tok_len);
                        if (token == NULL)
                            elog(ERROR, "unterminated List structure");
                        if (token[0] == ')')
                            break;
                        val = (Oid) strtoul(token, &endptr, 10);
                        if (endptr != token + tok_len)
                            elog(ERROR, "unrecognized OID: \"%.*s\"",
                                 tok_len, token);
                        l = lappend_oid(l, val);
                    }
                }
                else
                {
                    /* List of other node types */
                    for (;;)
                    {
                        /* We have already scanned next token... */
                        if (token[0] == ')')
                            break;
                        l = lappend(l, nodeRead(token, tok_len));
                        token = pg_strtok(&tok_len);
                        if (token == NULL)
                            elog(ERROR, "unterminated List structure");
                    }
                }
                result = (Node *) l;
                break;
            }
        case RIGHT_PAREN:
            elog(ERROR, "unexpected right parenthesis");
            result = NULL;      /* keep compiler happy */
            break;
        case OTHER_TOKEN:
            if (tok_len == 0)
            {
                /* must be "<>" --- represents a null pointer */
                result = NULL;
            }
            else
            {
                elog(ERROR, "unrecognized token: \"%.*s\"", tok_len, token);
                result = NULL;  /* keep compiler happy */
            }
            break;
        case T_Integer:

            /*
             * we know that the token terminates on a char atol will stop at
             */
            result = (Node *) makeInteger(atol(token));
            break;
        case T_Float:
            {
                char       *fval = (char *) palloc(tok_len + 1);

                memcpy(fval, token, tok_len);
                fval[tok_len] = '\0';
                result = (Node *) makeFloat(fval);
            }
            break;
        case T_String:
            /* need to remove leading and trailing quotes, and backslashes */
            result = (Node *) makeString(debackslash(token + 1, tok_len - 2));
            break;
        case T_BitString:
            {
                char       *val = palloc(tok_len);

                /* skip leading 'b' */
                memcpy(val, token + 1, tok_len - 1);
                val[tok_len - 1] = '\0';
                result = (Node *) makeBitString(val);
                break;
            }
        default:
            elog(ERROR, "unrecognized node type: %d", (int) type);
            result = NULL;      /* keep compiler happy */
            break;
    }

    return (void *) result;
}

static NodeTag nodeTokenType ( char *  token,
int  length 
) [static]

Definition at line 200 of file read.c.

References T_Float, and val.

Referenced by nodeRead().

{
    NodeTag     retval;
    char       *numptr;
    int         numlen;

    /*
     * Check if the token is a number
     */
    numptr = token;
    numlen = length;
    if (*numptr == '+' || *numptr == '-')
        numptr++, numlen--;
    if ((numlen > 0 && isdigit((unsigned char) *numptr)) ||
        (numlen > 1 && *numptr == '.' && isdigit((unsigned char) numptr[1])))
    {
        /*
         * Yes.  Figure out whether it is integral or float; this requires
         * both a syntax check and a range check. strtol() can do both for us.
         * We know the token will end at a character that strtol will stop at,
         * so we do not need to modify the string.
         */
        long        val;
        char       *endptr;

        errno = 0;
        val = strtol(token, &endptr, 10);
        (void) val;             /* avoid compiler warning if unused */
        if (endptr != token + length || errno == ERANGE
#ifdef HAVE_LONG_INT_64
        /* if long > 32 bits, check for overflow of int4 */
            || val != (long) ((int32) val)
#endif
            )
            return T_Float;
        return T_Integer;
    }

    /*
     * these three cases do not need length checks, since pg_strtok() will
     * always treat them as single-byte tokens
     */
    else if (*token == '(')
        retval = LEFT_PAREN;
    else if (*token == ')')
        retval = RIGHT_PAREN;
    else if (*token == '{')
        retval = LEFT_BRACE;
    else if (*token == '\"' && length > 1 && token[length - 1] == '\"')
        retval = T_String;
    else if (*token == 'b')
        retval = T_BitString;
    else
        retval = OTHER_TOKEN;
    return retval;
}

char* pg_strtok ( int *  length  ) 

Definition at line 107 of file read.c.

References pg_strtok_ptr.

Referenced by _readBitmapset(), _readBoolExpr(), _readConst(), nodeRead(), parseNodeString(), and readDatum().

{
    char       *local_str;      /* working pointer to string */
    char       *ret_str;        /* start of token to return */

    local_str = pg_strtok_ptr;

    while (*local_str == ' ' || *local_str == '\n' || *local_str == '\t')
        local_str++;

    if (*local_str == '\0')
    {
        *length = 0;
        pg_strtok_ptr = 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;

    pg_strtok_ptr = local_str;

    return ret_str;
}

void* stringToNode ( char *  str  ) 

Definition at line 38 of file read.c.

References nodeRead(), NULL, and pg_strtok_ptr.

Referenced by AddRelationNewConstraints(), build_column_default(), ExecRelCheck(), fetch_function_defaults(), func_get_detail(), generateClonedIndexStmt(), get_relation_constraints(), get_typdefault(), GetDomainConstraints(), make_ruledef(), make_viewdef(), MergeAttributes(), MergeWithExistingConstraint(), pg_get_constraintdef_worker(), pg_get_expr_worker(), pg_get_indexdef_worker(), pg_get_triggerdef_worker(), print_function_arguments(), ProcedureCreate(), RelationBuildRuleLock(), RelationGetIndexExpressions(), RelationGetIndexPredicate(), transformTableLikeClause(), TriggerEnabled(), TypeCreate(), validateCheckConstraint(), and validateDomainConstraint().

{
    char       *save_strtok;
    void       *retval;

    /*
     * We save and restore the pre-existing state of pg_strtok. This makes the
     * world safe for re-entrant invocation of stringToNode, without incurring
     * a lot of notational overhead by having to pass the next-character
     * pointer around through all the readfuncs.c code.
     */
    save_strtok = pg_strtok_ptr;

    pg_strtok_ptr = str;        /* point pg_strtok at the string to read */

    retval = nodeRead(NULL, 0); /* do the reading */

    pg_strtok_ptr = save_strtok;

    return retval;
}


Variable Documentation

char* pg_strtok_ptr = NULL [static]

Definition at line 30 of file read.c.

Referenced by pg_strtok(), and stringToNode().