Header And Logo

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

Data Structures | Defines | Typedefs | Functions | Variables

hstore_io.c File Reference

#include "postgres.h"
#include <ctype.h>
#include "access/htup_details.h"
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "lib/stringinfo.h"
#include "libpq/pqformat.h"
#include "utils/builtins.h"
#include "utils/json.h"
#include "utils/lsyscache.h"
#include "utils/typcache.h"
#include "hstore.h"
Include dependency graph for hstore_io.c:

Go to the source code of this file.

Data Structures

struct  HSParser
struct  ColumnIOData
struct  RecordIOData

Defines

#define RESIZEPRSBUF
#define GV_WAITVAL   0
#define GV_INVAL   1
#define GV_INESCVAL   2
#define GV_WAITESCIN   3
#define GV_WAITESCESCIN   4
#define WKEY   0
#define WVAL   1
#define WEQ   2
#define WGT   3
#define WDEL   4

Typedefs

typedef struct ColumnIOData ColumnIOData
typedef struct RecordIOData RecordIOData

Functions

 HSTORE_POLLUTE (hstore_from_text, tconvert)
static bool get_val (HSParser *state, bool ignoreeq, bool *escaped)
static void parse_hstore (HSParser *state)
static int comparePairs (const void *a, const void *b)
int hstoreUniquePairs (Pairs *a, int32 l, int32 *buflen)
size_t hstoreCheckKeyLen (size_t len)
size_t hstoreCheckValLen (size_t len)
HStorehstorePairs (Pairs *pairs, int32 pcount, int32 buflen)
 PG_FUNCTION_INFO_V1 (hstore_in)
Datum hstore_in (PG_FUNCTION_ARGS)
 PG_FUNCTION_INFO_V1 (hstore_recv)
Datum hstore_recv (PG_FUNCTION_ARGS)
 PG_FUNCTION_INFO_V1 (hstore_from_text)
Datum hstore_from_text (PG_FUNCTION_ARGS)
 PG_FUNCTION_INFO_V1 (hstore_from_arrays)
Datum hstore_from_arrays (PG_FUNCTION_ARGS)
 PG_FUNCTION_INFO_V1 (hstore_from_array)
Datum hstore_from_array (PG_FUNCTION_ARGS)
 PG_FUNCTION_INFO_V1 (hstore_from_record)
Datum hstore_from_record (PG_FUNCTION_ARGS)
 PG_FUNCTION_INFO_V1 (hstore_populate_record)
Datum hstore_populate_record (PG_FUNCTION_ARGS)
static char * cpw (char *dst, char *src, int len)
 PG_FUNCTION_INFO_V1 (hstore_out)
Datum hstore_out (PG_FUNCTION_ARGS)
 PG_FUNCTION_INFO_V1 (hstore_send)
Datum hstore_send (PG_FUNCTION_ARGS)
 PG_FUNCTION_INFO_V1 (hstore_to_json_loose)
Datum hstore_to_json_loose (PG_FUNCTION_ARGS)
 PG_FUNCTION_INFO_V1 (hstore_to_json)
Datum hstore_to_json (PG_FUNCTION_ARGS)

Variables

 PG_MODULE_MAGIC

Define Documentation

#define GV_INESCVAL   2

Definition at line 53 of file hstore_io.c.

Referenced by get_val().

#define GV_INVAL   1

Definition at line 52 of file hstore_io.c.

Referenced by get_val().

#define GV_WAITESCESCIN   4

Definition at line 55 of file hstore_io.c.

Referenced by get_val().

#define GV_WAITESCIN   3

Definition at line 54 of file hstore_io.c.

Referenced by get_val().

#define GV_WAITVAL   0

Definition at line 51 of file hstore_io.c.

Referenced by get_val().

#define RESIZEPRSBUF
Value:
do { \
        if ( state->cur - state->word + 1 >= state->wordlen ) \
        { \
                int32 clen = state->cur - state->word; \
                state->wordlen *= 2; \
                state->word = (char*)repalloc( (void*)state->word, state->wordlen ); \
                state->cur = state->word + clen; \
        } \
} while (0)

Definition at line 39 of file hstore_io.c.

#define WDEL   4

Definition at line 176 of file hstore_io.c.

Referenced by parse_hstore().

#define WEQ   2

Definition at line 174 of file hstore_io.c.

Referenced by parse_hstore().

#define WGT   3

Definition at line 175 of file hstore_io.c.

Referenced by parse_hstore().

#define WKEY   0

Definition at line 172 of file hstore_io.c.

Referenced by parse_hstore().

#define WVAL   1

Definition at line 173 of file hstore_io.c.

Referenced by parse_hstore().


Typedef Documentation

typedef struct ColumnIOData ColumnIOData
typedef struct RecordIOData RecordIOData

Function Documentation

static int comparePairs ( const void *  a,
const void *  b 
) [static]

Definition at line 279 of file hstore_io.c.

References Pairs::key, Pairs::keylen, memcmp(), and Pairs::needfree.

Referenced by hstoreUniquePairs().

{
    const Pairs *pa = a;
    const Pairs *pb = b;

    if (pa->keylen == pb->keylen)
    {
        int         res = memcmp(pa->key, pb->key, pa->keylen);

        if (res)
            return res;

        /* guarantee that needfree will be later */
        if (pb->needfree == pa->needfree)
            return 0;
        else if (pa->needfree)
            return 1;
        else
            return -1;
    }
    return (pa->keylen > pb->keylen) ? 1 : -1;
}

static char* cpw ( char *  dst,
char *  src,
int  len 
) [static]

Definition at line 1089 of file hstore_io.c.

Referenced by hstore_out().

{
    char       *ptr = src;

    while (ptr - src < len)
    {
        if (*ptr == '"' || *ptr == '\\')
            *dst++ = '\\';
        *dst++ = *ptr++;
    }
    return dst;
}

static bool get_val ( HSParser state,
bool  ignoreeq,
bool escaped 
) [static]

Definition at line 58 of file hstore_io.c.

References HSParser::begin, HSParser::cur, elog, ERROR, GV_INESCVAL, GV_INVAL, GV_WAITESCESCIN, GV_WAITESCIN, GV_WAITVAL, palloc(), HSParser::ptr, HSParser::word, and HSParser::wordlen.

Referenced by parse_hstore().

{
    int         st = GV_WAITVAL;

    state->wordlen = 32;
    state->cur = state->word = palloc(state->wordlen);
    *escaped = false;

    while (1)
    {
        if (st == GV_WAITVAL)
        {
            if (*(state->ptr) == '"')
            {
                *escaped = true;
                st = GV_INESCVAL;
            }
            else if (*(state->ptr) == '\0')
            {
                return false;
            }
            else if (*(state->ptr) == '=' && !ignoreeq)
            {
                elog(ERROR, "Syntax error near '%c' at position %d", *(state->ptr), (int32) (state->ptr - state->begin));
            }
            else if (*(state->ptr) == '\\')
            {
                st = GV_WAITESCIN;
            }
            else if (!isspace((unsigned char) *(state->ptr)))
            {
                *(state->cur) = *(state->ptr);
                state->cur++;
                st = GV_INVAL;
            }
        }
        else if (st == GV_INVAL)
        {
            if (*(state->ptr) == '\\')
            {
                st = GV_WAITESCIN;
            }
            else if (*(state->ptr) == '=' && !ignoreeq)
            {
                state->ptr--;
                return true;
            }
            else if (*(state->ptr) == ',' && ignoreeq)
            {
                state->ptr--;
                return true;
            }
            else if (isspace((unsigned char) *(state->ptr)))
            {
                return true;
            }
            else if (*(state->ptr) == '\0')
            {
                state->ptr--;
                return true;
            }
            else
            {
                RESIZEPRSBUF;
                *(state->cur) = *(state->ptr);
                state->cur++;
            }
        }
        else if (st == GV_INESCVAL)
        {
            if (*(state->ptr) == '\\')
            {
                st = GV_WAITESCESCIN;
            }
            else if (*(state->ptr) == '"')
            {
                return true;
            }
            else if (*(state->ptr) == '\0')
            {
                elog(ERROR, "Unexpected end of string");
            }
            else
            {
                RESIZEPRSBUF;
                *(state->cur) = *(state->ptr);
                state->cur++;
            }
        }
        else if (st == GV_WAITESCIN)
        {
            if (*(state->ptr) == '\0')
                elog(ERROR, "Unexpected end of string");
            RESIZEPRSBUF;
            *(state->cur) = *(state->ptr);
            state->cur++;
            st = GV_INVAL;
        }
        else if (st == GV_WAITESCESCIN)
        {
            if (*(state->ptr) == '\0')
                elog(ERROR, "Unexpected end of string");
            RESIZEPRSBUF;
            *(state->cur) = *(state->ptr);
            state->cur++;
            st = GV_INESCVAL;
        }
        else
            elog(ERROR, "Unknown state %d at position line %d in file '%s'", st, __LINE__, __FILE__);

        state->ptr++;
    }
}

Datum hstore_from_array ( PG_FUNCTION_ARGS   ) 

Definition at line 632 of file hstore_io.c.

References ARR_DIMS, ARR_ELEMTYPE, ARR_NDIM, Assert, deconstruct_array(), ereport, errcode(), errmsg(), ERROR, hstoreCheckKeyLen(), hstoreCheckValLen(), hstorePairs(), hstoreUniquePairs(), i, Pairs::isnull, Pairs::key, Pairs::keylen, Pairs::needfree, NULL, palloc(), PG_GETARG_ARRAYTYPE_P, PG_RETURN_POINTER, TEXTOID, Pairs::val, Pairs::vallen, VARDATA_ANY, and VARSIZE_ANY_EXHDR.

{
    ArrayType  *in_array = PG_GETARG_ARRAYTYPE_P(0);
    int         ndims = ARR_NDIM(in_array);
    int         count;
    int32       buflen;
    HStore     *out;
    Pairs      *pairs;
    Datum      *in_datums;
    bool       *in_nulls;
    int         in_count;
    int         i;

    Assert(ARR_ELEMTYPE(in_array) == TEXTOID);

    switch (ndims)
    {
        case 0:
            out = hstorePairs(NULL, 0, 0);
            PG_RETURN_POINTER(out);

        case 1:
            if ((ARR_DIMS(in_array)[0]) % 2)
                ereport(ERROR,
                        (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                         errmsg("array must have even number of elements")));
            break;

        case 2:
            if ((ARR_DIMS(in_array)[1]) != 2)
                ereport(ERROR,
                        (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                         errmsg("array must have two columns")));
            break;

        default:
            ereport(ERROR,
                    (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                     errmsg("wrong number of array subscripts")));
    }

    deconstruct_array(in_array,
                      TEXTOID, -1, false, 'i',
                      &in_datums, &in_nulls, &in_count);

    count = in_count / 2;

    pairs = palloc(count * sizeof(Pairs));

    for (i = 0; i < count; ++i)
    {
        if (in_nulls[i * 2])
            ereport(ERROR,
                    (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
                     errmsg("null value not allowed for hstore key")));

        if (in_nulls[i * 2 + 1])
        {
            pairs[i].key = VARDATA_ANY(in_datums[i * 2]);
            pairs[i].val = NULL;
            pairs[i].keylen = hstoreCheckKeyLen(VARSIZE_ANY_EXHDR(in_datums[i * 2]));
            pairs[i].vallen = 4;
            pairs[i].isnull = true;
            pairs[i].needfree = false;
        }
        else
        {
            pairs[i].key = VARDATA_ANY(in_datums[i * 2]);
            pairs[i].val = VARDATA_ANY(in_datums[i * 2 + 1]);
            pairs[i].keylen = hstoreCheckKeyLen(VARSIZE_ANY_EXHDR(in_datums[i * 2]));
            pairs[i].vallen = hstoreCheckValLen(VARSIZE_ANY_EXHDR(in_datums[i * 2 + 1]));
            pairs[i].isnull = false;
            pairs[i].needfree = false;
        }
    }

    count = hstoreUniquePairs(pairs, count, &buflen);

    out = hstorePairs(pairs, count, buflen);

    PG_RETURN_POINTER(out);
}

Datum hstore_from_arrays ( PG_FUNCTION_ARGS   ) 

Definition at line 521 of file hstore_io.c.

References ARR_DIMS, ARR_ELEMTYPE, ARR_LBOUND, ARR_NDIM, Assert, deconstruct_array(), ereport, errcode(), errmsg(), ERROR, hstoreCheckKeyLen(), hstoreCheckValLen(), hstorePairs(), hstoreUniquePairs(), i, Pairs::isnull, Pairs::key, Pairs::keylen, Pairs::needfree, palloc(), PG_ARGISNULL, PG_GETARG_ARRAYTYPE_P, PG_RETURN_NULL, PG_RETURN_POINTER, TEXTOID, Pairs::val, Pairs::vallen, VARDATA_ANY, and VARSIZE_ANY_EXHDR.

{
    int32       buflen;
    HStore     *out;
    Pairs      *pairs;
    Datum      *key_datums;
    bool       *key_nulls;
    int         key_count;
    Datum      *value_datums;
    bool       *value_nulls;
    int         value_count;
    ArrayType  *key_array;
    ArrayType  *value_array;
    int         i;

    if (PG_ARGISNULL(0))
        PG_RETURN_NULL();

    key_array = PG_GETARG_ARRAYTYPE_P(0);

    Assert(ARR_ELEMTYPE(key_array) == TEXTOID);

    /*
     * must check >1 rather than != 1 because empty arrays have 0 dimensions,
     * not 1
     */

    if (ARR_NDIM(key_array) > 1)
        ereport(ERROR,
                (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                 errmsg("wrong number of array subscripts")));

    deconstruct_array(key_array,
                      TEXTOID, -1, false, 'i',
                      &key_datums, &key_nulls, &key_count);

    /* value_array might be NULL */

    if (PG_ARGISNULL(1))
    {
        value_array = NULL;
        value_count = key_count;
        value_datums = NULL;
        value_nulls = NULL;
    }
    else
    {
        value_array = PG_GETARG_ARRAYTYPE_P(1);

        Assert(ARR_ELEMTYPE(value_array) == TEXTOID);

        if (ARR_NDIM(value_array) > 1)
            ereport(ERROR,
                    (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                     errmsg("wrong number of array subscripts")));

        if ((ARR_NDIM(key_array) > 0 || ARR_NDIM(value_array) > 0) &&
            (ARR_NDIM(key_array) != ARR_NDIM(value_array) ||
             ARR_DIMS(key_array)[0] != ARR_DIMS(value_array)[0] ||
             ARR_LBOUND(key_array)[0] != ARR_LBOUND(value_array)[0]))
            ereport(ERROR,
                    (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                     errmsg("arrays must have same bounds")));

        deconstruct_array(value_array,
                          TEXTOID, -1, false, 'i',
                          &value_datums, &value_nulls, &value_count);

        Assert(key_count == value_count);
    }

    pairs = palloc(key_count * sizeof(Pairs));

    for (i = 0; i < key_count; ++i)
    {
        if (key_nulls[i])
            ereport(ERROR,
                    (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
                     errmsg("null value not allowed for hstore key")));

        if (!value_nulls || value_nulls[i])
        {
            pairs[i].key = VARDATA_ANY(key_datums[i]);
            pairs[i].val = NULL;
            pairs[i].keylen = hstoreCheckKeyLen(VARSIZE_ANY_EXHDR(key_datums[i]));
            pairs[i].vallen = 4;
            pairs[i].isnull = true;
            pairs[i].needfree = false;
        }
        else
        {
            pairs[i].key = VARDATA_ANY(key_datums[i]);
            pairs[i].val = VARDATA_ANY(value_datums[i]);
            pairs[i].keylen = hstoreCheckKeyLen(VARSIZE_ANY_EXHDR(key_datums[i]));
            pairs[i].vallen = hstoreCheckValLen(VARSIZE_ANY_EXHDR(value_datums[i]));
            pairs[i].isnull = false;
            pairs[i].needfree = false;
        }
    }

    key_count = hstoreUniquePairs(pairs, key_count, &buflen);

    out = hstorePairs(pairs, key_count, buflen);

    PG_RETURN_POINTER(out);
}

Datum hstore_from_record ( PG_FUNCTION_ARGS   ) 

Definition at line 739 of file hstore_io.c.

References tupleDesc::attrs, ColumnIOData::column_type, RecordIOData::columns, fmgr_info_cxt(), FmgrInfo::fn_mcxt, get_fn_expr_argtype(), getTypeOutputInfo(), heap_deform_tuple(), HeapTupleHeaderGetDatumLength, HeapTupleHeaderGetTypeId, HeapTupleHeaderGetTypMod, hstoreCheckKeyLen(), hstoreCheckValLen(), hstorePairs(), hstoreUniquePairs(), i, InvalidOid, Pairs::isnull, ItemPointerSetInvalid, Pairs::key, Pairs::keylen, lookup_rowtype_tupdesc(), MemoryContextAlloc(), MemSet, NameStr, tupleDesc::natts, RecordIOData::ncolumns, Pairs::needfree, NULL, OutputFunctionCall(), palloc(), PG_ARGISNULL, PG_GETARG_HEAPTUPLEHEADER, PG_RETURN_POINTER, ColumnIOData::proc, RecordIOData::record_type, RecordIOData::record_typmod, ReleaseTupleDesc, HeapTupleData::t_data, HeapTupleData::t_len, HeapTupleData::t_self, HeapTupleData::t_tableOid, ColumnIOData::typiofunc, Pairs::val, Pairs::vallen, value, and values.

{
    HeapTupleHeader rec;
    int32       buflen;
    HStore     *out;
    Pairs      *pairs;
    Oid         tupType;
    int32       tupTypmod;
    TupleDesc   tupdesc;
    HeapTupleData tuple;
    RecordIOData *my_extra;
    int         ncolumns;
    int         i,
                j;
    Datum      *values;
    bool       *nulls;

    if (PG_ARGISNULL(0))
    {
        Oid         argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);

        /*
         * have no tuple to look at, so the only source of type info is the
         * argtype. The lookup_rowtype_tupdesc call below will error out if we
         * don't have a known composite type oid here.
         */
        tupType = argtype;
        tupTypmod = -1;

        rec = NULL;
    }
    else
    {
        rec = PG_GETARG_HEAPTUPLEHEADER(0);

        /* Extract type info from the tuple itself */
        tupType = HeapTupleHeaderGetTypeId(rec);
        tupTypmod = HeapTupleHeaderGetTypMod(rec);
    }

    tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
    ncolumns = tupdesc->natts;

    /*
     * We arrange to look up the needed I/O info just once per series of
     * calls, assuming the record type doesn't change underneath us.
     */
    my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
    if (my_extra == NULL ||
        my_extra->ncolumns != ncolumns)
    {
        fcinfo->flinfo->fn_extra =
            MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
                               sizeof(RecordIOData) - sizeof(ColumnIOData)
                               + ncolumns * sizeof(ColumnIOData));
        my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
        my_extra->record_type = InvalidOid;
        my_extra->record_typmod = 0;
    }

    if (my_extra->record_type != tupType ||
        my_extra->record_typmod != tupTypmod)
    {
        MemSet(my_extra, 0,
               sizeof(RecordIOData) - sizeof(ColumnIOData)
               + ncolumns * sizeof(ColumnIOData));
        my_extra->record_type = tupType;
        my_extra->record_typmod = tupTypmod;
        my_extra->ncolumns = ncolumns;
    }

    pairs = palloc(ncolumns * sizeof(Pairs));

    if (rec)
    {
        /* Build a temporary HeapTuple control structure */
        tuple.t_len = HeapTupleHeaderGetDatumLength(rec);
        ItemPointerSetInvalid(&(tuple.t_self));
        tuple.t_tableOid = InvalidOid;
        tuple.t_data = rec;

        values = (Datum *) palloc(ncolumns * sizeof(Datum));
        nulls = (bool *) palloc(ncolumns * sizeof(bool));

        /* Break down the tuple into fields */
        heap_deform_tuple(&tuple, tupdesc, values, nulls);
    }
    else
    {
        values = NULL;
        nulls = NULL;
    }

    for (i = 0, j = 0; i < ncolumns; ++i)
    {
        ColumnIOData *column_info = &my_extra->columns[i];
        Oid         column_type = tupdesc->attrs[i]->atttypid;
        char       *value;

        /* Ignore dropped columns in datatype */
        if (tupdesc->attrs[i]->attisdropped)
            continue;

        pairs[j].key = NameStr(tupdesc->attrs[i]->attname);
        pairs[j].keylen = hstoreCheckKeyLen(strlen(NameStr(tupdesc->attrs[i]->attname)));

        if (!nulls || nulls[i])
        {
            pairs[j].val = NULL;
            pairs[j].vallen = 4;
            pairs[j].isnull = true;
            pairs[j].needfree = false;
            ++j;
            continue;
        }

        /*
         * Convert the column value to text
         */
        if (column_info->column_type != column_type)
        {
            bool        typIsVarlena;

            getTypeOutputInfo(column_type,
                              &column_info->typiofunc,
                              &typIsVarlena);
            fmgr_info_cxt(column_info->typiofunc, &column_info->proc,
                          fcinfo->flinfo->fn_mcxt);
            column_info->column_type = column_type;
        }

        value = OutputFunctionCall(&column_info->proc, values[i]);

        pairs[j].val = value;
        pairs[j].vallen = hstoreCheckValLen(strlen(value));
        pairs[j].isnull = false;
        pairs[j].needfree = false;
        ++j;
    }

    ncolumns = hstoreUniquePairs(pairs, j, &buflen);

    out = hstorePairs(pairs, ncolumns, buflen);

    ReleaseTupleDesc(tupdesc);

    PG_RETURN_POINTER(out);
}

Datum hstore_from_text ( PG_FUNCTION_ARGS   ) 
Datum hstore_in ( PG_FUNCTION_ARGS   ) 

Definition at line 404 of file hstore_io.c.

References HSParser::begin, hstorePairs(), hstoreUniquePairs(), HSParser::pairs, parse_hstore(), HSParser::pcur, PG_GETARG_CSTRING, and PG_RETURN_POINTER.

{
    HSParser    state;
    int32       buflen;
    HStore     *out;

    state.begin = PG_GETARG_CSTRING(0);

    parse_hstore(&state);

    state.pcur = hstoreUniquePairs(state.pairs, state.pcur, &buflen);

    out = hstorePairs(state.pairs, state.pcur, buflen);

    PG_RETURN_POINTER(out);
}

Datum hstore_out ( PG_FUNCTION_ARGS   ) 

Definition at line 1105 of file hstore_io.c.

References ARRPTR, cpw(), HS_COUNT, HS_KEY, HS_KEYLEN, HS_VAL, HS_VALISNULL, HS_VALLEN, i, palloc(), PG_GETARG_HS, PG_RETURN_CSTRING, and STRPTR.

{
    HStore     *in = PG_GETARG_HS(0);
    int         buflen,
                i;
    int         count = HS_COUNT(in);
    char       *out,
               *ptr;
    char       *base = STRPTR(in);
    HEntry     *entries = ARRPTR(in);

    if (count == 0)
    {
        out = palloc(1);
        *out = '\0';
        PG_RETURN_CSTRING(out);
    }

    buflen = 0;

    /*
     * this loop overestimates due to pessimistic assumptions about escaping,
     * so very large hstore values can't be output. this could be fixed, but
     * many other data types probably have the same issue. This replaced code
     * that used the original varlena size for calculations, which was wrong
     * in some subtle ways.
     */

    for (i = 0; i < count; i++)
    {
        /* include "" and => and comma-space */
        buflen += 6 + 2 * HS_KEYLEN(entries, i);
        /* include "" only if nonnull */
        buflen += 2 + (HS_VALISNULL(entries, i)
                       ? 2
                       : 2 * HS_VALLEN(entries, i));
    }

    out = ptr = palloc(buflen);

    for (i = 0; i < count; i++)
    {
        *ptr++ = '"';
        ptr = cpw(ptr, HS_KEY(entries, base, i), HS_KEYLEN(entries, i));
        *ptr++ = '"';
        *ptr++ = '=';
        *ptr++ = '>';
        if (HS_VALISNULL(entries, i))
        {
            *ptr++ = 'N';
            *ptr++ = 'U';
            *ptr++ = 'L';
            *ptr++ = 'L';
        }
        else
        {
            *ptr++ = '"';
            ptr = cpw(ptr, HS_VAL(entries, base, i), HS_VALLEN(entries, i));
            *ptr++ = '"';
        }

        if (i + 1 != count)
        {
            *ptr++ = ',';
            *ptr++ = ' ';
        }
    }
    *ptr = '\0';

    PG_RETURN_CSTRING(out);
}

HSTORE_POLLUTE ( hstore_from_text  ,
tconvert   
)
Datum hstore_populate_record ( PG_FUNCTION_ARGS   ) 

Definition at line 892 of file hstore_io.c.

References ARRPTR, tupleDesc::attrs, ColumnIOData::column_type, RecordIOData::columns, ereport, errcode(), errmsg(), ERROR, fmgr_info_cxt(), FmgrInfo::fn_mcxt, get_fn_expr_argtype(), getTypeInputInfo(), heap_deform_tuple(), heap_form_tuple(), HeapTupleGetDatum, HeapTupleHeaderGetDatumLength, HeapTupleHeaderGetTypeId, HeapTupleHeaderGetTypMod, HS_COUNT, HS_VAL, HS_VALISNULL, HS_VALLEN, hstoreFindKey(), i, InputFunctionCall(), InvalidOid, ItemPointerSetInvalid, lookup_rowtype_tupdesc(), MemoryContextAlloc(), MemSet, NameStr, tupleDesc::natts, RecordIOData::ncolumns, NULL, palloc(), PG_ARGISNULL, PG_GETARG_HEAPTUPLEHEADER, PG_GETARG_HS, PG_RETURN_DATUM, PG_RETURN_NULL, PG_RETURN_POINTER, ColumnIOData::proc, RecordIOData::record_type, RecordIOData::record_typmod, ReleaseTupleDesc, STRPTR, HeapTupleData::t_data, HeapTupleData::t_len, HeapTupleData::t_self, HeapTupleData::t_tableOid, type_is_rowtype(), ColumnIOData::typiofunc, ColumnIOData::typioparam, value, and values.

{
    Oid         argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
    HStore     *hs;
    HEntry     *entries;
    char       *ptr;
    HeapTupleHeader rec;
    Oid         tupType;
    int32       tupTypmod;
    TupleDesc   tupdesc;
    HeapTupleData tuple;
    HeapTuple   rettuple;
    RecordIOData *my_extra;
    int         ncolumns;
    int         i;
    Datum      *values;
    bool       *nulls;

    if (!type_is_rowtype(argtype))
        ereport(ERROR,
                (errcode(ERRCODE_DATATYPE_MISMATCH),
                 errmsg("first argument must be a rowtype")));

    if (PG_ARGISNULL(0))
    {
        if (PG_ARGISNULL(1))
            PG_RETURN_NULL();

        rec = NULL;

        /*
         * have no tuple to look at, so the only source of type info is the
         * argtype. The lookup_rowtype_tupdesc call below will error out if we
         * don't have a known composite type oid here.
         */
        tupType = argtype;
        tupTypmod = -1;
    }
    else
    {
        rec = PG_GETARG_HEAPTUPLEHEADER(0);

        if (PG_ARGISNULL(1))
            PG_RETURN_POINTER(rec);

        /* Extract type info from the tuple itself */
        tupType = HeapTupleHeaderGetTypeId(rec);
        tupTypmod = HeapTupleHeaderGetTypMod(rec);
    }

    hs = PG_GETARG_HS(1);
    entries = ARRPTR(hs);
    ptr = STRPTR(hs);

    /*
     * if the input hstore is empty, we can only skip the rest if we were
     * passed in a non-null record, since otherwise there may be issues with
     * domain nulls.
     */

    if (HS_COUNT(hs) == 0 && rec)
        PG_RETURN_POINTER(rec);

    tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
    ncolumns = tupdesc->natts;

    if (rec)
    {
        /* Build a temporary HeapTuple control structure */
        tuple.t_len = HeapTupleHeaderGetDatumLength(rec);
        ItemPointerSetInvalid(&(tuple.t_self));
        tuple.t_tableOid = InvalidOid;
        tuple.t_data = rec;
    }

    /*
     * We arrange to look up the needed I/O info just once per series of
     * calls, assuming the record type doesn't change underneath us.
     */
    my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
    if (my_extra == NULL ||
        my_extra->ncolumns != ncolumns)
    {
        fcinfo->flinfo->fn_extra =
            MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
                               sizeof(RecordIOData) - sizeof(ColumnIOData)
                               + ncolumns * sizeof(ColumnIOData));
        my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
        my_extra->record_type = InvalidOid;
        my_extra->record_typmod = 0;
    }

    if (my_extra->record_type != tupType ||
        my_extra->record_typmod != tupTypmod)
    {
        MemSet(my_extra, 0,
               sizeof(RecordIOData) - sizeof(ColumnIOData)
               + ncolumns * sizeof(ColumnIOData));
        my_extra->record_type = tupType;
        my_extra->record_typmod = tupTypmod;
        my_extra->ncolumns = ncolumns;
    }

    values = (Datum *) palloc(ncolumns * sizeof(Datum));
    nulls = (bool *) palloc(ncolumns * sizeof(bool));

    if (rec)
    {
        /* Break down the tuple into fields */
        heap_deform_tuple(&tuple, tupdesc, values, nulls);
    }
    else
    {
        for (i = 0; i < ncolumns; ++i)
        {
            values[i] = (Datum) 0;
            nulls[i] = true;
        }
    }

    for (i = 0; i < ncolumns; ++i)
    {
        ColumnIOData *column_info = &my_extra->columns[i];
        Oid         column_type = tupdesc->attrs[i]->atttypid;
        char       *value;
        int         idx;
        int         vallen;

        /* Ignore dropped columns in datatype */
        if (tupdesc->attrs[i]->attisdropped)
        {
            nulls[i] = true;
            continue;
        }

        idx = hstoreFindKey(hs, 0,
                            NameStr(tupdesc->attrs[i]->attname),
                            strlen(NameStr(tupdesc->attrs[i]->attname)));

        /*
         * we can't just skip here if the key wasn't found since we might have
         * a domain to deal with. If we were passed in a non-null record
         * datum, we assume that the existing values are valid (if they're
         * not, then it's not our fault), but if we were passed in a null,
         * then every field which we don't populate needs to be run through
         * the input function just in case it's a domain type.
         */
        if (idx < 0 && rec)
            continue;

        /*
         * Prepare to convert the column value from text
         */
        if (column_info->column_type != column_type)
        {
            getTypeInputInfo(column_type,
                             &column_info->typiofunc,
                             &column_info->typioparam);
            fmgr_info_cxt(column_info->typiofunc, &column_info->proc,
                          fcinfo->flinfo->fn_mcxt);
            column_info->column_type = column_type;
        }

        if (idx < 0 || HS_VALISNULL(entries, idx))
        {
            /*
             * need InputFunctionCall to happen even for nulls, so that domain
             * checks are done
             */
            values[i] = InputFunctionCall(&column_info->proc, NULL,
                                          column_info->typioparam,
                                          tupdesc->attrs[i]->atttypmod);
            nulls[i] = true;
        }
        else
        {
            vallen = HS_VALLEN(entries, idx);
            value = palloc(1 + vallen);
            memcpy(value, HS_VAL(entries, ptr, idx), vallen);
            value[vallen] = 0;

            values[i] = InputFunctionCall(&column_info->proc, value,
                                          column_info->typioparam,
                                          tupdesc->attrs[i]->atttypmod);
            nulls[i] = false;
        }
    }

    rettuple = heap_form_tuple(tupdesc, values, nulls);

    ReleaseTupleDesc(tupdesc);

    PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
}

Datum hstore_recv ( PG_FUNCTION_ARGS   ) 

Definition at line 425 of file hstore_io.c.

References buf, ereport, errcode(), errmsg(), ERROR, hstoreCheckKeyLen(), hstoreCheckValLen(), hstorePairs(), hstoreUniquePairs(), i, Pairs::isnull, Pairs::key, Pairs::keylen, Pairs::needfree, NULL, palloc(), PG_GETARG_POINTER, PG_RETURN_POINTER, pq_getmsgint(), pq_getmsgtext(), Pairs::val, and Pairs::vallen.

{
    int32       buflen;
    HStore     *out;
    Pairs      *pairs;
    int32       i;
    int32       pcount;
    StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);

    pcount = pq_getmsgint(buf, 4);

    if (pcount == 0)
    {
        out = hstorePairs(NULL, 0, 0);
        PG_RETURN_POINTER(out);
    }

    pairs = palloc(pcount * sizeof(Pairs));

    for (i = 0; i < pcount; ++i)
    {
        int         rawlen = pq_getmsgint(buf, 4);
        int         len;

        if (rawlen < 0)
            ereport(ERROR,
                    (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
                     errmsg("null value not allowed for hstore key")));

        pairs[i].key = pq_getmsgtext(buf, rawlen, &len);
        pairs[i].keylen = hstoreCheckKeyLen(len);
        pairs[i].needfree = true;

        rawlen = pq_getmsgint(buf, 4);
        if (rawlen < 0)
        {
            pairs[i].val = NULL;
            pairs[i].vallen = 0;
            pairs[i].isnull = true;
        }
        else
        {
            pairs[i].val = pq_getmsgtext(buf, rawlen, &len);
            pairs[i].vallen = hstoreCheckValLen(len);
            pairs[i].isnull = false;
        }
    }

    pcount = hstoreUniquePairs(pairs, pcount, &buflen);

    out = hstorePairs(pairs, pcount, buflen);

    PG_RETURN_POINTER(out);
}

Datum hstore_send ( PG_FUNCTION_ARGS   ) 

Definition at line 1181 of file hstore_io.c.

References ARRPTR, buf, HS_COUNT, HS_KEY, HS_KEYLEN, HS_VAL, HS_VALISNULL, HS_VALLEN, i, PG_GETARG_HS, PG_RETURN_BYTEA_P, pq_begintypsend(), pq_endtypsend(), pq_sendint(), pq_sendtext(), and STRPTR.

{
    HStore     *in = PG_GETARG_HS(0);
    int         i;
    int         count = HS_COUNT(in);
    char       *base = STRPTR(in);
    HEntry     *entries = ARRPTR(in);
    StringInfoData buf;

    pq_begintypsend(&buf);

    pq_sendint(&buf, count, 4);

    for (i = 0; i < count; i++)
    {
        int32       keylen = HS_KEYLEN(entries, i);

        pq_sendint(&buf, keylen, 4);
        pq_sendtext(&buf, HS_KEY(entries, base, i), keylen);
        if (HS_VALISNULL(entries, i))
        {
            pq_sendint(&buf, -1, 4);
        }
        else
        {
            int32       vallen = HS_VALLEN(entries, i);

            pq_sendint(&buf, vallen, 4);
            pq_sendtext(&buf, HS_VAL(entries, base, i), vallen);
        }
    }

    PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}

Datum hstore_to_json ( PG_FUNCTION_ARGS   ) 

Definition at line 1357 of file hstore_io.c.

References appendBinaryStringInfo(), appendStringInfoString(), ARRPTR, cstring_to_text(), StringInfoData::data, escape_json(), HS_COUNT, HS_KEY, HS_KEYLEN, HS_VAL, HS_VALISNULL, HS_VALLEN, i, StringInfoData::len, makeStringInfo(), palloc(), PG_GETARG_HS, PG_RETURN_TEXT_P, resetStringInfo(), and STRPTR.

{
    HStore     *in = PG_GETARG_HS(0);
    int         buflen,
                i;
    int         count = HS_COUNT(in);
    char       *out,
               *ptr;
    char       *base = STRPTR(in);
    HEntry     *entries = ARRPTR(in);
    StringInfo  src,
                dst;

    if (count == 0)
    {
        out = palloc(1);
        *out = '\0';
        PG_RETURN_TEXT_P(cstring_to_text(out));
    }

    buflen = 3;

    /*
     * Formula adjusted slightly from the logic in hstore_out. We have to take
     * account of out treatment of booleans to be a bit more pessimistic about
     * the length of values.
     */

    for (i = 0; i < count; i++)
    {
        /* include "" and colon-space and comma-space */
        buflen += 6 + 2 * HS_KEYLEN(entries, i);
        /* include "" only if nonnull */
        buflen += 3 + (HS_VALISNULL(entries, i)
                       ? 1
                       : 2 * HS_VALLEN(entries, i));
    }

    out = ptr = palloc(buflen);

    src = makeStringInfo();
    dst = makeStringInfo();

    *ptr++ = '{';

    for (i = 0; i < count; i++)
    {
        resetStringInfo(src);
        resetStringInfo(dst);
        appendBinaryStringInfo(src, HS_KEY(entries, base, i), HS_KEYLEN(entries, i));
        escape_json(dst, src->data);
        strncpy(ptr, dst->data, dst->len);
        ptr += dst->len;
        *ptr++ = ':';
        *ptr++ = ' ';
        resetStringInfo(dst);
        if (HS_VALISNULL(entries, i))
            appendStringInfoString(dst, "null");
        else
        {
            resetStringInfo(src);
            appendBinaryStringInfo(src, HS_VAL(entries, base, i), HS_VALLEN(entries, i));
            escape_json(dst, src->data);
        }
        strncpy(ptr, dst->data, dst->len);
        ptr += dst->len;

        if (i + 1 != count)
        {
            *ptr++ = ',';
            *ptr++ = ' ';
        }
    }
    *ptr++ = '}';
    *ptr = '\0';

    PG_RETURN_TEXT_P(cstring_to_text(out));
}

Datum hstore_to_json_loose ( PG_FUNCTION_ARGS   ) 

Definition at line 1228 of file hstore_io.c.

References appendBinaryStringInfo(), appendStringInfoString(), ARRPTR, cstring_to_text(), StringInfoData::data, escape_json(), HS_COUNT, HS_KEY, HS_KEYLEN, HS_VAL, HS_VALISNULL, HS_VALLEN, i, StringInfoData::len, makeStringInfo(), palloc(), PG_GETARG_HS, PG_RETURN_TEXT_P, resetStringInfo(), and STRPTR.

{
    HStore     *in = PG_GETARG_HS(0);
    int         buflen,
                i;
    int         count = HS_COUNT(in);
    char       *out,
               *ptr;
    char       *base = STRPTR(in);
    HEntry     *entries = ARRPTR(in);
    bool        is_number;
    StringInfo  src,
                dst;

    if (count == 0)
    {
        out = palloc(1);
        *out = '\0';
        PG_RETURN_TEXT_P(cstring_to_text(out));
    }

    buflen = 3;

    /*
     * Formula adjusted slightly from the logic in hstore_out. We have to take
     * account of out treatment of booleans to be a bit more pessimistic about
     * the length of values.
     */

    for (i = 0; i < count; i++)
    {
        /* include "" and colon-space and comma-space */
        buflen += 6 + 2 * HS_KEYLEN(entries, i);
        /* include "" only if nonnull */
        buflen += 3 + (HS_VALISNULL(entries, i)
                       ? 1
                       : 2 * HS_VALLEN(entries, i));
    }

    out = ptr = palloc(buflen);

    src = makeStringInfo();
    dst = makeStringInfo();

    *ptr++ = '{';

    for (i = 0; i < count; i++)
    {
        resetStringInfo(src);
        resetStringInfo(dst);
        appendBinaryStringInfo(src, HS_KEY(entries, base, i), HS_KEYLEN(entries, i));
        escape_json(dst, src->data);
        strncpy(ptr, dst->data, dst->len);
        ptr += dst->len;
        *ptr++ = ':';
        *ptr++ = ' ';
        resetStringInfo(dst);
        if (HS_VALISNULL(entries, i))
            appendStringInfoString(dst, "null");
        /* guess that values of 't' or 'f' are booleans */
        else if (HS_VALLEN(entries, i) == 1 && *(HS_VAL(entries, base, i)) == 't')
            appendStringInfoString(dst, "true");
        else if (HS_VALLEN(entries, i) == 1 && *(HS_VAL(entries, base, i)) == 'f')
            appendStringInfoString(dst, "false");
        else
        {
            is_number = false;
            resetStringInfo(src);
            appendBinaryStringInfo(src, HS_VAL(entries, base, i), HS_VALLEN(entries, i));

            /*
             * don't treat something with a leading zero followed by another
             * digit as numeric - could be a zip code or similar
             */
            if (src->len > 0 &&
                !(src->data[0] == '0' && isdigit((unsigned char) src->data[1])) &&
                strspn(src->data, "+-0123456789Ee.") == src->len)
            {
                /*
                 * might be a number. See if we can input it as a numeric
                 * value. Ignore any actual parsed value.
                 */
                char       *endptr = "junk";
                long        lval;

                lval =  strtol(src->data, &endptr, 10);
                (void) lval;
                if (*endptr == '\0')
                {
                    /*
                     * strol man page says this means the whole string is
                     * valid
                     */
                    is_number = true;
                }
                else
                {
                    /* not an int - try a double */
                    double dval;

                    dval = strtod(src->data, &endptr);
                    (void) dval;
                    if (*endptr == '\0')
                        is_number = true;
                }
            }
            if (is_number)
                appendBinaryStringInfo(dst, src->data, src->len);
            else
                escape_json(dst, src->data);
        }
        strncpy(ptr, dst->data, dst->len);
        ptr += dst->len;

        if (i + 1 != count)
        {
            *ptr++ = ',';
            *ptr++ = ' ';
        }
    }
    *ptr++ = '}';
    *ptr = '\0';

    PG_RETURN_TEXT_P(cstring_to_text(out));
}

size_t hstoreCheckKeyLen ( size_t  len  ) 

Definition at line 351 of file hstore_io.c.

References ereport, errcode(), errmsg(), ERROR, and HSTORE_MAX_KEY_LEN.

Referenced by hstore_from_array(), hstore_from_arrays(), hstore_from_record(), hstore_from_text(), hstore_recv(), and parse_hstore().

{
    if (len > HSTORE_MAX_KEY_LEN)
        ereport(ERROR,
                (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
                 errmsg("string too long for hstore key")));
    return len;
}

size_t hstoreCheckValLen ( size_t  len  ) 

Definition at line 361 of file hstore_io.c.

References ereport, errcode(), errmsg(), ERROR, and HSTORE_MAX_VALUE_LEN.

Referenced by hstore_from_array(), hstore_from_arrays(), hstore_from_record(), hstore_from_text(), hstore_recv(), and parse_hstore().

{
    if (len > HSTORE_MAX_VALUE_LEN)
        ereport(ERROR,
                (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
                 errmsg("string too long for hstore value")));
    return len;
}

HStore* hstorePairs ( Pairs pairs,
int32  pcount,
int32  buflen 
)

Definition at line 372 of file hstore_io.c.

References ARRPTR, buf, CALCDATASIZE, HS_ADDITEM, HS_FINALIZE, HS_SETCOUNT, i, palloc(), SET_VARSIZE, and STRPTR.

Referenced by hstore_from_array(), hstore_from_arrays(), hstore_from_record(), hstore_from_text(), hstore_in(), hstore_recv(), and hstore_slice_to_hstore().

{
    HStore     *out;
    HEntry     *entry;
    char       *ptr;
    char       *buf;
    int32       len;
    int32       i;

    len = CALCDATASIZE(pcount, buflen);
    out = palloc(len);
    SET_VARSIZE(out, len);
    HS_SETCOUNT(out, pcount);

    if (pcount == 0)
        return out;

    entry = ARRPTR(out);
    buf = ptr = STRPTR(out);

    for (i = 0; i < pcount; i++)
        HS_ADDITEM(entry, buf, ptr, pairs[i]);

    HS_FINALIZE(out, pcount, buf, ptr);

    return out;
}

int hstoreUniquePairs ( Pairs a,
int32  l,
int32 buflen 
)

Definition at line 309 of file hstore_io.c.

References comparePairs(), Pairs::isnull, Pairs::key, Pairs::keylen, memcmp(), Pairs::needfree, pfree(), qsort, Pairs::val, and Pairs::vallen.

Referenced by hstore_from_array(), hstore_from_arrays(), hstore_from_record(), hstore_in(), hstore_recv(), and hstoreArrayToPairs().

{
    Pairs      *ptr,
               *res;

    *buflen = 0;
    if (l < 2)
    {
        if (l == 1)
            *buflen = a->keylen + ((a->isnull) ? 0 : a->vallen);
        return l;
    }

    qsort((void *) a, l, sizeof(Pairs), comparePairs);
    ptr = a + 1;
    res = a;
    while (ptr - a < l)
    {
        if (ptr->keylen == res->keylen &&
            memcmp(ptr->key, res->key, res->keylen) == 0)
        {
            if (ptr->needfree)
            {
                pfree(ptr->key);
                pfree(ptr->val);
            }
        }
        else
        {
            *buflen += res->keylen + ((res->isnull) ? 0 : res->vallen);
            res++;
            memcpy(res, ptr, sizeof(Pairs));
        }

        ptr++;
    }

    *buflen += res->keylen + ((res->isnull) ? 0 : res->vallen);
    return res + 1 - a;
}

static void parse_hstore ( HSParser state  )  [static]

Definition at line 180 of file hstore_io.c.

References HSParser::begin, HSParser::cur, elog, ERROR, get_val(), hstoreCheckKeyLen(), hstoreCheckValLen(), Pairs::isnull, Pairs::key, Pairs::keylen, Pairs::needfree, HSParser::pairs, palloc(), HSParser::pcur, pg_strcasecmp(), HSParser::plen, HSParser::ptr, repalloc(), Pairs::val, Pairs::vallen, WDEL, WEQ, WGT, WKEY, HSParser::word, and WVAL.

Referenced by hstore_in().

{
    int         st = WKEY;
    bool        escaped = false;

    state->plen = 16;
    state->pairs = (Pairs *) palloc(sizeof(Pairs) * state->plen);
    state->pcur = 0;
    state->ptr = state->begin;
    state->word = NULL;

    while (1)
    {
        if (st == WKEY)
        {
            if (!get_val(state, false, &escaped))
                return;
            if (state->pcur >= state->plen)
            {
                state->plen *= 2;
                state->pairs = (Pairs *) repalloc(state->pairs, sizeof(Pairs) * state->plen);
            }
            state->pairs[state->pcur].key = state->word;
            state->pairs[state->pcur].keylen = hstoreCheckKeyLen(state->cur - state->word);
            state->pairs[state->pcur].val = NULL;
            state->word = NULL;
            st = WEQ;
        }
        else if (st == WEQ)
        {
            if (*(state->ptr) == '=')
            {
                st = WGT;
            }
            else if (*(state->ptr) == '\0')
            {
                elog(ERROR, "Unexpected end of string");
            }
            else if (!isspace((unsigned char) *(state->ptr)))
            {
                elog(ERROR, "Syntax error near '%c' at position %d", *(state->ptr), (int32) (state->ptr - state->begin));
            }
        }
        else if (st == WGT)
        {
            if (*(state->ptr) == '>')
            {
                st = WVAL;
            }
            else if (*(state->ptr) == '\0')
            {
                elog(ERROR, "Unexpected end of string");
            }
            else
            {
                elog(ERROR, "Syntax error near '%c' at position %d", *(state->ptr), (int32) (state->ptr - state->begin));
            }
        }
        else if (st == WVAL)
        {
            if (!get_val(state, true, &escaped))
                elog(ERROR, "Unexpected end of string");
            state->pairs[state->pcur].val = state->word;
            state->pairs[state->pcur].vallen = hstoreCheckValLen(state->cur - state->word);
            state->pairs[state->pcur].isnull = false;
            state->pairs[state->pcur].needfree = true;
            if (state->cur - state->word == 4 && !escaped)
            {
                state->word[4] = '\0';
                if (0 == pg_strcasecmp(state->word, "null"))
                    state->pairs[state->pcur].isnull = true;
            }
            state->word = NULL;
            state->pcur++;
            st = WDEL;
        }
        else if (st == WDEL)
        {
            if (*(state->ptr) == ',')
            {
                st = WKEY;
            }
            else if (*(state->ptr) == '\0')
            {
                return;
            }
            else if (!isspace((unsigned char) *(state->ptr)))
            {
                elog(ERROR, "Syntax error near '%c' at position %d", *(state->ptr), (int32) (state->ptr - state->begin));
            }
        }
        else
            elog(ERROR, "Unknown state %d at line %d in file '%s'", st, __LINE__, __FILE__);

        state->ptr++;
    }
}

PG_FUNCTION_INFO_V1 ( hstore_populate_record   ) 
PG_FUNCTION_INFO_V1 ( hstore_from_text   ) 
PG_FUNCTION_INFO_V1 ( hstore_from_arrays   ) 
PG_FUNCTION_INFO_V1 ( hstore_to_json   ) 
PG_FUNCTION_INFO_V1 ( hstore_recv   ) 
PG_FUNCTION_INFO_V1 ( hstore_from_record   ) 
PG_FUNCTION_INFO_V1 ( hstore_in   ) 
PG_FUNCTION_INFO_V1 ( hstore_out   ) 
PG_FUNCTION_INFO_V1 ( hstore_to_json_loose   ) 
PG_FUNCTION_INFO_V1 ( hstore_from_array   ) 
PG_FUNCTION_INFO_V1 ( hstore_send   ) 

Variable Documentation

Definition at line 20 of file hstore_io.c.