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