#include "fmgr.h"
#include "lib/stringinfo.h"
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) |
Datum array_to_json | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1425 of file json.c.
References array_to_json_internal(), cstring_to_text(), StringInfoData::data, makeStringInfo(), PG_GETARG_DATUM, and PG_RETURN_TEXT_P.
{ Datum array = PG_GETARG_DATUM(0); StringInfo result; result = makeStringInfo(); array_to_json_internal(array, result, false); PG_RETURN_TEXT_P(cstring_to_text(result->data)); }
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 | ) |
Definition at line 195 of file json.c.
References buf, PG_GETARG_TEXT_PP, PG_RETURN_BYTEA_P, pq_begintypsend(), pq_endtypsend(), pq_sendtext(), VARDATA_ANY, and VARSIZE_ANY_EXHDR.
{ text *t = PG_GETARG_TEXT_PP(0); StringInfoData buf; pq_begintypsend(&buf); pq_sendtext(&buf, VARDATA_ANY(t), VARSIZE_ANY_EXHDR(t)); PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); }
Datum row_to_json | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1458 of file json.c.
References composite_to_json(), cstring_to_text(), StringInfoData::data, makeStringInfo(), PG_GETARG_DATUM, and PG_RETURN_TEXT_P.
{ Datum array = PG_GETARG_DATUM(0); StringInfo result; result = makeStringInfo(); composite_to_json(array, result, false); PG_RETURN_TEXT_P(cstring_to_text(result->data)); }
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)); }