Header And Logo

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

Functions

json.h File Reference

#include "fmgr.h"
#include "lib/stringinfo.h"
Include dependency graph for json.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

Datum json_in (PG_FUNCTION_ARGS)
Datum json_out (PG_FUNCTION_ARGS)
Datum json_recv (PG_FUNCTION_ARGS)
Datum json_send (PG_FUNCTION_ARGS)
Datum array_to_json (PG_FUNCTION_ARGS)
Datum array_to_json_pretty (PG_FUNCTION_ARGS)
Datum row_to_json (PG_FUNCTION_ARGS)
Datum row_to_json_pretty (PG_FUNCTION_ARGS)
Datum to_json (PG_FUNCTION_ARGS)
Datum json_agg_transfn (PG_FUNCTION_ARGS)
Datum json_agg_finalfn (PG_FUNCTION_ARGS)
void escape_json (StringInfo buf, const char *str)
Datum json_object_field (PG_FUNCTION_ARGS)
Datum json_object_field_text (PG_FUNCTION_ARGS)
Datum json_array_element (PG_FUNCTION_ARGS)
Datum json_array_element_text (PG_FUNCTION_ARGS)
Datum json_extract_path (PG_FUNCTION_ARGS)
Datum json_extract_path_text (PG_FUNCTION_ARGS)
Datum json_object_keys (PG_FUNCTION_ARGS)
Datum json_array_length (PG_FUNCTION_ARGS)
Datum json_each (PG_FUNCTION_ARGS)
Datum json_each_text (PG_FUNCTION_ARGS)
Datum json_array_elements (PG_FUNCTION_ARGS)
Datum json_populate_record (PG_FUNCTION_ARGS)
Datum json_populate_recordset (PG_FUNCTION_ARGS)

Function Documentation

Datum array_to_json ( PG_FUNCTION_ARGS   ) 
Datum array_to_json_pretty ( PG_FUNCTION_ARGS   ) 

Definition at line 1441 of file json.c.

References array_to_json_internal(), cstring_to_text(), StringInfoData::data, makeStringInfo(), PG_GETARG_BOOL, PG_GETARG_DATUM, and PG_RETURN_TEXT_P.

{
    Datum       array = PG_GETARG_DATUM(0);
    bool        use_line_feeds = PG_GETARG_BOOL(1);
    StringInfo  result;

    result = makeStringInfo();

    array_to_json_internal(array, result, use_line_feeds);

    PG_RETURN_TEXT_P(cstring_to_text(result->data));
}

void escape_json ( StringInfo  buf,
const char *  str 
)

Definition at line 1707 of file json.c.

References appendStringInfo(), appendStringInfoCharMacro, and appendStringInfoString().

Referenced by composite_to_json(), datum_to_json(), escape_yaml(), ExplainDummyGroup(), ExplainOpenGroup(), ExplainProperty(), ExplainPropertyList(), hstore_to_json(), and hstore_to_json_loose().

{
    const char *p;

    appendStringInfoCharMacro(buf, '\"');
    for (p = str; *p; p++)
    {
        switch (*p)
        {
            case '\b':
                appendStringInfoString(buf, "\\b");
                break;
            case '\f':
                appendStringInfoString(buf, "\\f");
                break;
            case '\n':
                appendStringInfoString(buf, "\\n");
                break;
            case '\r':
                appendStringInfoString(buf, "\\r");
                break;
            case '\t':
                appendStringInfoString(buf, "\\t");
                break;
            case '"':
                appendStringInfoString(buf, "\\\"");
                break;
            case '\\':
                appendStringInfoString(buf, "\\\\");
                break;
            default:
                if ((unsigned char) *p < ' ')
                    appendStringInfo(buf, "\\u%04x", (int) *p);
                else
                    appendStringInfoCharMacro(buf, *p);
                break;
        }
    }
    appendStringInfoCharMacro(buf, '\"');
}

Datum json_agg_finalfn ( PG_FUNCTION_ARGS   ) 

Definition at line 1686 of file json.c.

References AggCheckCallContext(), appendStringInfoChar(), Assert, cstring_to_text(), StringInfoData::data, NULL, PG_ARGISNULL, PG_GETARG_POINTER, PG_RETURN_NULL, and PG_RETURN_TEXT_P.

{
    StringInfo  state;

    /* cannot be called directly because of internal-type argument */
    Assert(AggCheckCallContext(fcinfo, NULL));

    state = PG_ARGISNULL(0) ? NULL : (StringInfo) PG_GETARG_POINTER(0);

    if (state == NULL)
        PG_RETURN_NULL();

    appendStringInfoChar(state, ']');

    PG_RETURN_TEXT_P(cstring_to_text(state->data));
}

Datum json_agg_transfn ( PG_FUNCTION_ARGS   ) 

Definition at line 1566 of file json.c.

References AggCheckCallContext(), appendStringInfoChar(), appendStringInfoString(), CASTSOURCETARGET, COERCION_METHOD_FUNCTION, datum_to_json(), DatumGetPointer, elog, ereport, errcode(), errmsg(), ERROR, FirstNormalObjectId, get_fn_expr_argtype(), GETSTRUCT, getTypeOutputInfo(), HeapTupleIsValid, InvalidOid, JSONOID, makeStringInfo(), MemoryContextSwitchTo(), ObjectIdGetDatum, pfree(), PG_ARGISNULL, PG_DETOAST_DATUM, PG_GETARG_DATUM, PG_GETARG_POINTER, PG_RETURN_POINTER, PointerGetDatum, RECORDARRAYOID, RECORDOID, ReleaseSysCache(), SearchSysCache2, TYPCATEGORY_ARRAY, TYPCATEGORY_COMPOSITE, TypeCategory(), and val.

{
    Oid         val_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
    MemoryContext aggcontext,
                oldcontext;
    StringInfo  state;
    Datum       orig_val,
                val;
    TYPCATEGORY tcategory;
    Oid         typoutput;
    bool        typisvarlena;
    Oid         castfunc = InvalidOid;

    if (val_type == InvalidOid)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("could not determine input data type")));

    if (!AggCheckCallContext(fcinfo, &aggcontext))
    {
        /* cannot be called directly because of internal-type argument */
        elog(ERROR, "json_agg_transfn called in non-aggregate context");
    }

    if (PG_ARGISNULL(0))
    {
        /*
         * Make this StringInfo in a context where it will persist for the
         * duration off the aggregate call. It's only needed for this initial
         * piece, as the StringInfo routines make sure they use the right
         * context to enlarge the object if necessary.
         */
        oldcontext = MemoryContextSwitchTo(aggcontext);
        state = makeStringInfo();
        MemoryContextSwitchTo(oldcontext);

        appendStringInfoChar(state, '[');
    }
    else
    {
        state = (StringInfo) PG_GETARG_POINTER(0);
        appendStringInfoString(state, ", ");
    }

    /* fast path for NULLs */
    if (PG_ARGISNULL(1))
    {
        orig_val = (Datum) 0;
        datum_to_json(orig_val, true, state, 0, InvalidOid);
        PG_RETURN_POINTER(state);
    }


    orig_val = PG_GETARG_DATUM(1);

    getTypeOutputInfo(val_type, &typoutput, &typisvarlena);

    if (val_type > FirstNormalObjectId)
    {
        HeapTuple   tuple;
        Form_pg_cast castForm;

        tuple = SearchSysCache2(CASTSOURCETARGET,
                                ObjectIdGetDatum(val_type),
                                ObjectIdGetDatum(JSONOID));
        if (HeapTupleIsValid(tuple))
        {
            castForm = (Form_pg_cast) GETSTRUCT(tuple);

            if (castForm->castmethod == COERCION_METHOD_FUNCTION)
                castfunc = typoutput = castForm->castfunc;

            ReleaseSysCache(tuple);
        }
    }

    if (castfunc != InvalidOid)
        tcategory = TYPCATEGORY_JSON_CAST;
    else if (val_type == RECORDARRAYOID)
        tcategory = TYPCATEGORY_ARRAY;
    else if (val_type == RECORDOID)
        tcategory = TYPCATEGORY_COMPOSITE;
    else if (val_type == JSONOID)
        tcategory = TYPCATEGORY_JSON;
    else
        tcategory = TypeCategory(val_type);

    /*
     * If we have a toasted datum, forcibly detoast it here to avoid memory
     * leakage inside the type's output routine.
     */
    if (typisvarlena)
        val = PointerGetDatum(PG_DETOAST_DATUM(orig_val));
    else
        val = orig_val;

    if (!PG_ARGISNULL(0) &&
      (tcategory == TYPCATEGORY_ARRAY || tcategory == TYPCATEGORY_COMPOSITE))
    {
        appendStringInfoString(state, "\n ");
    }

    datum_to_json(val, false, state, tcategory, typoutput);

    /* Clean up detoasted copy, if any */
    if (val != orig_val)
        pfree(DatumGetPointer(val));

    /*
     * The transition type for array_agg() is declared to be "internal", which
     * is a pass-by-value type the same size as a pointer.  So we can safely
     * pass the ArrayBuildState pointer through nodeAgg.c's machinations.
     */
    PG_RETURN_POINTER(state);
}

Datum json_array_element ( PG_FUNCTION_ARGS   ) 

Definition at line 378 of file jsonfuncs.c.

References element(), get_worker(), NULL, PG_GETARG_INT32, PG_GETARG_TEXT_P, PG_RETURN_NULL, and PG_RETURN_TEXT_P.

{
    text       *json = PG_GETARG_TEXT_P(0);
    text       *result;
    int         element = PG_GETARG_INT32(1);

    result = get_worker(json, NULL, element, NULL, NULL, -1, false);

    if (result != NULL)
        PG_RETURN_TEXT_P(result);
    else
        PG_RETURN_NULL();
}

Datum json_array_element_text ( PG_FUNCTION_ARGS   ) 

Definition at line 393 of file jsonfuncs.c.

References element(), get_worker(), NULL, PG_GETARG_INT32, PG_GETARG_TEXT_P, PG_RETURN_NULL, and PG_RETURN_TEXT_P.

{
    text       *json = PG_GETARG_TEXT_P(0);
    text       *result;
    int         element = PG_GETARG_INT32(1);

    result = get_worker(json, NULL, element, NULL, NULL, -1, true);

    if (result != NULL)
        PG_RETURN_TEXT_P(result);
    else
        PG_RETURN_NULL();
}

Datum json_array_elements ( PG_FUNCTION_ARGS   ) 

Definition at line 1071 of file jsonfuncs.c.

References ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate(), ReturnSetInfo::allowedModes, jsonSemAction::array_element_end, jsonSemAction::array_element_start, BlessTupleDesc(), CreateTupleDescCopy(), CurrentMemoryContext, ReturnSetInfo::econtext, ExprContext::ecxt_per_query_memory, ereport, errcode(), errmsg(), ERROR, ReturnSetInfo::expectedDesc, IsA, elementsState::lex, makeJsonLexContext(), MemoryContextSwitchTo(), NULL, jsonSemAction::object_start, palloc0(), PG_GETARG_TEXT_P, pg_parse_json(), PG_RETURN_NULL, elementsState::ret_tdesc, ReturnSetInfo::returnMode, jsonSemAction::scalar, jsonSemAction::semstate, ReturnSetInfo::setDesc, ReturnSetInfo::setResult, SFRM_Materialize_Random, elementsState::tmp_cxt, elementsState::tuple_store, tuplestore_begin_heap(), and work_mem.

{
    text       *json = PG_GETARG_TEXT_P(0);

    /* elements doesn't need any escaped strings, so use false here */
    JsonLexContext *lex = makeJsonLexContext(json, false);
    JsonSemAction sem;
    ReturnSetInfo *rsi;
    MemoryContext old_cxt;
    TupleDesc   tupdesc;
    ElementsState state;

    state = palloc0(sizeof(elementsState));
    sem = palloc0(sizeof(jsonSemAction));

    rsi = (ReturnSetInfo *) fcinfo->resultinfo;

    if (!rsi || !IsA(rsi, ReturnSetInfo) ||
        (rsi->allowedModes & SFRM_Materialize) == 0 ||
        rsi->expectedDesc == NULL)
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                 errmsg("set-valued function called in context that "
                        "cannot accept a set")));


    rsi->returnMode = SFRM_Materialize;

    /* it's a simple type, so don't use get_call_result_type() */
    tupdesc = rsi->expectedDesc;

    /* make these in a sufficiently long-lived memory context */
    old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);

    state->ret_tdesc = CreateTupleDescCopy(tupdesc);
    BlessTupleDesc(state->ret_tdesc);
    state->tuple_store =
        tuplestore_begin_heap(rsi->allowedModes & SFRM_Materialize_Random,
                              false, work_mem);

    MemoryContextSwitchTo(old_cxt);

    sem->semstate = (void *) state;
    sem->object_start = elements_object_start;
    sem->scalar = elements_scalar;
    sem->array_element_start = elements_array_element_start;
    sem->array_element_end = elements_array_element_end;

    state->lex = lex;
    state->tmp_cxt = AllocSetContextCreate(CurrentMemoryContext,
                                         "json_array_elements temporary cxt",
                                           ALLOCSET_DEFAULT_MINSIZE,
                                           ALLOCSET_DEFAULT_INITSIZE,
                                           ALLOCSET_DEFAULT_MAXSIZE);

    pg_parse_json(lex, sem);

    rsi->setResult = state->tuple_store;
    rsi->setDesc = state->ret_tdesc;

    PG_RETURN_NULL();
}

Datum json_array_length ( PG_FUNCTION_ARGS   ) 

Definition at line 815 of file jsonfuncs.c.

References jsonSemAction::array_element_start, alenState::count, alenState::lex, makeJsonLexContext(), jsonSemAction::object_start, palloc0(), PG_GETARG_TEXT_P, pg_parse_json(), PG_RETURN_INT32, jsonSemAction::scalar, and jsonSemAction::semstate.

{
    text       *json = PG_GETARG_TEXT_P(0);

    AlenState   state;
    JsonLexContext *lex = makeJsonLexContext(json, false);
    JsonSemAction sem;

    state = palloc0(sizeof(alenState));
    sem = palloc0(sizeof(jsonSemAction));

    /* palloc0 does this for us */
#if 0
    state->count = 0;
#endif
    state->lex = lex;

    sem->semstate = (void *) state;
    sem->object_start = alen_object_start;
    sem->scalar = alen_scalar;
    sem->array_element_start = alen_array_element_start;

    pg_parse_json(lex, sem);

    PG_RETURN_INT32(state->count);
}

Datum json_each ( PG_FUNCTION_ARGS   ) 

Definition at line 892 of file jsonfuncs.c.

References each_worker().

{
    return each_worker(fcinfo, false);
}

Datum json_each_text ( PG_FUNCTION_ARGS   ) 

Definition at line 898 of file jsonfuncs.c.

References each_worker().

{
    return each_worker(fcinfo, true);
}

Datum json_extract_path ( PG_FUNCTION_ARGS   ) 

Definition at line 408 of file jsonfuncs.c.

References get_path_all().

{
    return get_path_all(fcinfo, false);
}

Datum json_extract_path_text ( PG_FUNCTION_ARGS   ) 

Definition at line 414 of file jsonfuncs.c.

References get_path_all().

{
    return get_path_all(fcinfo, true);
}

Datum json_in ( PG_FUNCTION_ARGS   ) 

Definition at line 165 of file json.c.

References cstring_to_text(), makeJsonLexContext(), PG_GETARG_CSTRING, pg_parse_json(), and PG_RETURN_TEXT_P.

{
    char       *json = PG_GETARG_CSTRING(0);
    text       *result = cstring_to_text(json);
    JsonLexContext *lex;

    /* validate it */
    lex = makeJsonLexContext(result, false);
    pg_parse_json(lex, NullSemAction);

    /* Internal representation is the same as text, for now */
    PG_RETURN_TEXT_P(result);
}

Datum json_object_field ( PG_FUNCTION_ARGS   ) 

Definition at line 346 of file jsonfuncs.c.

References get_worker(), NULL, PG_GETARG_TEXT_P, PG_RETURN_NULL, PG_RETURN_TEXT_P, and text_to_cstring().

{
    text       *json = PG_GETARG_TEXT_P(0);
    text       *result;
    text       *fname = PG_GETARG_TEXT_P(1);
    char       *fnamestr = text_to_cstring(fname);

    result = get_worker(json, fnamestr, -1, NULL, NULL, -1, false);

    if (result != NULL)
        PG_RETURN_TEXT_P(result);
    else
        PG_RETURN_NULL();
}

Datum json_object_field_text ( PG_FUNCTION_ARGS   ) 

Definition at line 362 of file jsonfuncs.c.

References get_worker(), NULL, PG_GETARG_TEXT_P, PG_RETURN_NULL, PG_RETURN_TEXT_P, and text_to_cstring().

{
    text       *json = PG_GETARG_TEXT_P(0);
    text       *result;
    text       *fname = PG_GETARG_TEXT_P(1);
    char       *fnamestr = text_to_cstring(fname);

    result = get_worker(json, fnamestr, -1, NULL, NULL, -1, true);

    if (result != NULL)
        PG_RETURN_TEXT_P(result);
    else
        PG_RETURN_NULL();
}

Datum json_object_keys ( PG_FUNCTION_ARGS   ) 

Definition at line 229 of file jsonfuncs.c.

References jsonSemAction::array_start, CStringGetTextDatum, StringInfoData::data, i, okeysState::lex, makeJsonLexContext(), MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, jsonSemAction::object_field_start, palloc(), palloc0(), pfree(), PG_GETARG_TEXT_P, pg_parse_json(), okeysState::result, okeysState::result_count, okeysState::result_size, jsonSemAction::scalar, jsonSemAction::semstate, okeysState::sent_count, SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, JsonLexContext::strval, and FuncCallContext::user_fctx.

{
    FuncCallContext *funcctx;
    OkeysState  state;
    int         i;

    if (SRF_IS_FIRSTCALL())
    {
        text       *json = PG_GETARG_TEXT_P(0);
        JsonLexContext *lex = makeJsonLexContext(json, true);
        JsonSemAction sem;

        MemoryContext oldcontext;

        funcctx = SRF_FIRSTCALL_INIT();
        oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);

        state = palloc(sizeof(okeysState));
        sem = palloc0(sizeof(jsonSemAction));

        state->lex = lex;
        state->result_size = 256;
        state->result_count = 0;
        state->sent_count = 0;
        state->result = palloc(256 * sizeof(char *));

        sem->semstate = (void *) state;
        sem->array_start = okeys_array_start;
        sem->scalar = okeys_scalar;
        sem->object_field_start = okeys_object_field_start;
        /* remainder are all NULL, courtesy of palloc0 above */

        pg_parse_json(lex, sem);
        /* keys are now in state->result */

        pfree(lex->strval->data);
        pfree(lex->strval);
        pfree(lex);
        pfree(sem);

        MemoryContextSwitchTo(oldcontext);
        funcctx->user_fctx = (void *) state;

    }

    funcctx = SRF_PERCALL_SETUP();
    state = (OkeysState) funcctx->user_fctx;

    if (state->sent_count < state->result_count)
    {
        char       *nxt = state->result[state->sent_count++];

        SRF_RETURN_NEXT(funcctx, CStringGetTextDatum(nxt));
    }

    /* cleanup to reduce or eliminate memory leaks */
    for (i = 0; i < state->result_count; i++)
        pfree(state->result[i]);
    pfree(state->result);
    pfree(state);

    SRF_RETURN_DONE(funcctx);
}

Datum json_out ( PG_FUNCTION_ARGS   ) 

Definition at line 183 of file json.c.

References PG_GETARG_DATUM, PG_RETURN_CSTRING, and TextDatumGetCString.

{
    /* we needn't detoast because text_to_cstring will handle that */
    Datum       txt = PG_GETARG_DATUM(0);

    PG_RETURN_CSTRING(TextDatumGetCString(txt));
}

Datum json_populate_record ( PG_FUNCTION_ARGS   ) 

Definition at line 1217 of file jsonfuncs.c.

References tupleDesc::attrs, ColumnIOData::column_type, RecordIOData::columns, ereport, errcode(), errmsg(), ERROR, fmgr_info_cxt(), FmgrInfo::fn_mcxt, get_fn_expr_argtype(), get_json_object_as_hash(), getTypeInputInfo(), HASH_FIND, hash_get_num_entries(), hash_search(), heap_deform_tuple(), heap_form_tuple(), HeapTupleGetDatum, HeapTupleHeaderGetDatumLength, HeapTupleHeaderGetTypeId, HeapTupleHeaderGetTypMod, i, InputFunctionCall(), InvalidOid, jsonHashEntry::isnull, ItemPointerSetInvalid, lookup_rowtype_tupdesc(), MemoryContextAlloc(), MemSet, NAMEDATALEN, NameStr, tupleDesc::natts, RecordIOData::ncolumns, NULL, palloc(), PG_ARGISNULL, PG_GETARG_BOOL, PG_GETARG_HEAPTUPLEHEADER, PG_GETARG_TEXT_P, PG_RETURN_DATUM, PG_RETURN_NULL, PG_RETURN_POINTER, ColumnIOData::proc, RecordIOData::record_type, RecordIOData::record_typmod, ReleaseTupleDesc, HeapTupleData::t_data, HeapTupleData::t_len, HeapTupleData::t_self, HeapTupleData::t_tableOid, type_is_rowtype(), ColumnIOData::typiofunc, ColumnIOData::typioparam, jsonHashEntry::val, value, and values.

{
    Oid         argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
    text       *json;
    bool        use_json_as_text;
    HTAB       *json_hash;
    HeapTupleHeader rec;
    Oid         tupType;
    int32       tupTypmod;
    TupleDesc   tupdesc;
    HeapTupleData tuple;
    HeapTuple   rettuple;
    RecordIOData *my_extra;
    int         ncolumns;
    int         i;
    Datum      *values;
    bool       *nulls;
    char        fname[NAMEDATALEN];
    JsonHashEntry hashentry;

    use_json_as_text = PG_ARGISNULL(2) ? false : PG_GETARG_BOOL(2);

    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);
    }

    json = PG_GETARG_TEXT_P(1);

    json_hash = get_json_object_as_hash(json, "json_populate_record", use_json_as_text);

    /*
     * if the input json 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 (hash_get_num_entries(json_hash) == 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;

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

        memset(fname, 0, NAMEDATALEN);
        strncpy(fname, NameStr(tupdesc->attrs[i]->attname), NAMEDATALEN);
        hashentry = hash_search(json_hash, fname, HASH_FIND, NULL);

        /*
         * 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 (hashentry == NULL && 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 (hashentry == NULL || hashentry->isnull)
        {
            /*
             * 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
        {
            value = hashentry->val;

            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 json_populate_recordset ( PG_FUNCTION_ARGS   ) 

Definition at line 1562 of file jsonfuncs.c.

References ReturnSetInfo::allowedModes, jsonSemAction::array_element_start, jsonSemAction::array_start, BlessTupleDesc(), CreateTupleDescCopy(), ReturnSetInfo::econtext, ExprContext::ecxt_per_query_memory, ereport, errcode(), errmsg(), ERROR, ReturnSetInfo::expectedDesc, populateRecordsetState::fn_mcxt, get_call_result_type(), get_fn_expr_argtype(), InvalidOid, IsA, populateRecordsetState::lex, makeJsonLexContext(), MemoryContextAlloc(), MemoryContextSwitchTo(), MemSet, populateRecordsetState::my_extra, tupleDesc::natts, RecordIOData::ncolumns, NULL, jsonSemAction::object_end, jsonSemAction::object_field_end, jsonSemAction::object_field_start, jsonSemAction::object_start, palloc0(), PG_ARGISNULL, PG_GETARG_BOOL, PG_GETARG_HEAPTUPLEHEADER, PG_GETARG_TEXT_P, pg_parse_json(), PG_RETURN_NULL, populateRecordsetState::rec, RecordIOData::record_type, RecordIOData::record_typmod, populateRecordsetState::ret_tdesc, ReturnSetInfo::returnMode, jsonSemAction::scalar, jsonSemAction::semstate, ReturnSetInfo::setDesc, ReturnSetInfo::setResult, SFRM_Materialize_Random, tupleDesc::tdtypeid, tupleDesc::tdtypmod, populateRecordsetState::tuple_store, tuplestore_begin_heap(), type_is_rowtype(), populateRecordsetState::use_json_as_text, and work_mem.

{
    Oid         argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
    text       *json;
    bool        use_json_as_text;
    ReturnSetInfo *rsi;
    MemoryContext old_cxt;
    Oid         tupType;
    int32       tupTypmod;
    HeapTupleHeader rec;
    TupleDesc   tupdesc;
    RecordIOData *my_extra;
    int         ncolumns;
    JsonLexContext *lex;
    JsonSemAction sem;
    PopulateRecordsetState state;

    use_json_as_text = PG_ARGISNULL(2) ? false : PG_GETARG_BOOL(2);

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

    rsi = (ReturnSetInfo *) fcinfo->resultinfo;

    if (!rsi || !IsA(rsi, ReturnSetInfo) ||
        (rsi->allowedModes & SFRM_Materialize) == 0 ||
        rsi->expectedDesc == NULL)
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                 errmsg("set-valued function called in context that "
                        "cannot accept a set")));


    rsi->returnMode = SFRM_Materialize;

    /*
     * get the tupdesc from the result set info - it must be a record type
     * because we already checked that arg1 is a record type.
     */
    (void) get_call_result_type(fcinfo, NULL, &tupdesc);

    state = palloc0(sizeof(populateRecordsetState));
    sem = palloc0(sizeof(jsonSemAction));


    /* make these in a sufficiently long-lived memory context */
    old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);

    state->ret_tdesc = CreateTupleDescCopy(tupdesc);
    BlessTupleDesc(state->ret_tdesc);
    state->tuple_store =
        tuplestore_begin_heap(rsi->allowedModes & SFRM_Materialize_Random,
                              false, work_mem);

    MemoryContextSwitchTo(old_cxt);

    /* if the json is null send back an empty set */
    if (PG_ARGISNULL(1))
        PG_RETURN_NULL();

    json = PG_GETARG_TEXT_P(1);

    if (PG_ARGISNULL(0))
        rec = NULL;
    else
        rec = PG_GETARG_HEAPTUPLEHEADER(0);

    tupType = tupdesc->tdtypeid;
    tupTypmod = tupdesc->tdtypmod;
    ncolumns = tupdesc->natts;

    lex = makeJsonLexContext(json, true);

    /*
     * 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;
    }

    sem->semstate = (void *) state;
    sem->array_start = populate_recordset_array_start;
    sem->array_element_start = populate_recordset_array_element_start;
    sem->scalar = populate_recordset_scalar;
    sem->object_field_start = populate_recordset_object_field_start;
    sem->object_field_end = populate_recordset_object_field_end;
    sem->object_start = populate_recordset_object_start;
    sem->object_end = populate_recordset_object_end;

    state->lex = lex;

    state->my_extra = my_extra;
    state->rec = rec;
    state->use_json_as_text = use_json_as_text;
    state->fn_mcxt = fcinfo->flinfo->fn_mcxt;

    pg_parse_json(lex, sem);

    rsi->setResult = state->tuple_store;
    rsi->setDesc = state->ret_tdesc;

    PG_RETURN_NULL();

}

Datum json_recv ( PG_FUNCTION_ARGS   ) 

Definition at line 209 of file json.c.

References buf, StringInfoData::cursor, StringInfoData::len, makeJsonLexContext(), palloc(), PG_GETARG_POINTER, pg_parse_json(), PG_RETURN_TEXT_P, pq_getmsgtext(), SET_VARSIZE, VARDATA, and VARHDRSZ.

{
    StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
    text       *result;
    char       *str;
    int         nbytes;
    JsonLexContext *lex;

    str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);

    result = palloc(nbytes + VARHDRSZ);
    SET_VARSIZE(result, nbytes + VARHDRSZ);
    memcpy(VARDATA(result), str, nbytes);

    /* Validate it. */
    lex = makeJsonLexContext(result, false);
    pg_parse_json(lex, NullSemAction);

    PG_RETURN_TEXT_P(result);
}

Datum json_send ( PG_FUNCTION_ARGS   ) 
Datum row_to_json ( PG_FUNCTION_ARGS   ) 
Datum row_to_json_pretty ( PG_FUNCTION_ARGS   ) 

Definition at line 1474 of file json.c.

References composite_to_json(), cstring_to_text(), StringInfoData::data, makeStringInfo(), PG_GETARG_BOOL, PG_GETARG_DATUM, and PG_RETURN_TEXT_P.

{
    Datum       array = PG_GETARG_DATUM(0);
    bool        use_line_feeds = PG_GETARG_BOOL(1);
    StringInfo  result;

    result = makeStringInfo();

    composite_to_json(array, result, use_line_feeds);

    PG_RETURN_TEXT_P(cstring_to_text(result->data));
}

Datum to_json ( PG_FUNCTION_ARGS   ) 

Definition at line 1491 of file json.c.

References CASTSOURCETARGET, COERCION_METHOD_FUNCTION, cstring_to_text(), StringInfoData::data, datum_to_json(), DatumGetPointer, ereport, errcode(), errmsg(), ERROR, FirstNormalObjectId, get_fn_expr_argtype(), GETSTRUCT, getTypeOutputInfo(), HeapTupleIsValid, InvalidOid, JSONOID, makeStringInfo(), ObjectIdGetDatum, pfree(), PG_ARGISNULL, PG_DETOAST_DATUM, PG_GETARG_DATUM, PG_RETURN_TEXT_P, PointerGetDatum, RECORDARRAYOID, RECORDOID, ReleaseSysCache(), SearchSysCache2, TypeCategory(), and val.

{
    Oid         val_type = get_fn_expr_argtype(fcinfo->flinfo, 0);
    StringInfo  result;
    Datum       orig_val,
                val;
    TYPCATEGORY tcategory;
    Oid         typoutput;
    bool        typisvarlena;
    Oid         castfunc = InvalidOid;

    if (val_type == InvalidOid)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("could not determine input data type")));


    result = makeStringInfo();

    orig_val = PG_ARGISNULL(0) ? (Datum) 0 : PG_GETARG_DATUM(0);

    getTypeOutputInfo(val_type, &typoutput, &typisvarlena);

    if (val_type > FirstNormalObjectId)
    {
        HeapTuple   tuple;
        Form_pg_cast castForm;

        tuple = SearchSysCache2(CASTSOURCETARGET,
                                ObjectIdGetDatum(val_type),
                                ObjectIdGetDatum(JSONOID));
        if (HeapTupleIsValid(tuple))
        {
            castForm = (Form_pg_cast) GETSTRUCT(tuple);

            if (castForm->castmethod == COERCION_METHOD_FUNCTION)
                castfunc = typoutput = castForm->castfunc;

            ReleaseSysCache(tuple);
        }
    }

    if (castfunc != InvalidOid)
        tcategory = TYPCATEGORY_JSON_CAST;
    else if (val_type == RECORDARRAYOID)
        tcategory = TYPCATEGORY_ARRAY;
    else if (val_type == RECORDOID)
        tcategory = TYPCATEGORY_COMPOSITE;
    else if (val_type == JSONOID)
        tcategory = TYPCATEGORY_JSON;
    else
        tcategory = TypeCategory(val_type);

    /*
     * If we have a toasted datum, forcibly detoast it here to avoid memory
     * leakage inside the type's output routine.
     */
    if (typisvarlena && orig_val != (Datum) 0)
        val = PointerGetDatum(PG_DETOAST_DATUM(orig_val));
    else
        val = orig_val;

    datum_to_json(val, false, result, tcategory, typoutput);

    /* Clean up detoasted copy, if any */
    if (val != orig_val)
        pfree(DatumGetPointer(val));

    PG_RETURN_TEXT_P(cstring_to_text(result->data));
}