/* state for json_object_keys */ typedefstruct OkeysState
{
JsonLexContext *lex; char **result; int result_size; int result_count; int sent_count;
} OkeysState;
/* state for iterate_json_values function */ typedefstruct IterateJsonStringValuesState
{
JsonLexContext *lex;
JsonIterateStringValuesAction action; /* an action that will be applied
* to each json value */ void *action_state; /* any necessary context for iteration */
uint32 flags; /* what kind of elements from a json we want
* to iterate */
} IterateJsonStringValuesState;
/* state for transform_json_string_values function */ typedefstruct TransformJsonStringValuesState
{
JsonLexContext *lex;
StringInfo strval; /* resulting json */
JsonTransformStringValuesAction action; /* an action that will be applied
* to each json value */ void *action_state; /* any necessary context for transformation */
} TransformJsonStringValuesState;
/* state for json_get* functions */ typedefstruct GetState
{
JsonLexContext *lex;
text *tresult; constchar *result_start; bool normalize_results; bool next_scalar; int npath; /* length of each path-related array */ char **path_names; /* field name(s) being sought */ int *path_indexes; /* array index(es) being sought */ bool *pathok; /* is path matched to current depth? */ int *array_cur_index; /* current element index at each path
* level */
} GetState;
/* state for json_array_length */ typedefstruct AlenState
{
JsonLexContext *lex; int count;
} AlenState;
/* structure to cache type I/O metadata needed for populate_scalar() */ typedefstruct ScalarIOData
{
Oid typioparam;
FmgrInfo typiofunc;
} ScalarIOData;
/* these two structures are used recursively */ typedefstruct ColumnIOData ColumnIOData; typedefstruct RecordIOData RecordIOData;
/* structure to cache metadata needed for populate_array() */ typedefstruct ArrayIOData
{
ColumnIOData *element_info; /* metadata cache */
Oid element_type; /* array element type id */
int32 element_typmod; /* array element type modifier */
} ArrayIOData;
/* structure to cache metadata needed for populate_composite() */ typedefstruct CompositeIOData
{ /* *WeusepointertoaRecordIODataherebecausevariable-lengthstruct *RecordIODatacan'tbeuseddirectlyinColumnIOData.iounion
*/
RecordIOData *record_io; /* metadata cache for populate_record() */
TupleDesc tupdesc; /* cached tuple descriptor */ /* these fields differ from target type only if domain over composite: */
Oid base_typid; /* base type id */
int32 base_typmod; /* base type modifier */ /* this field is used only if target type is domain over composite: */ void *domain_info; /* opaque cache for domain checks */
} CompositeIOData;
/* structure to cache metadata needed for populate_domain() */ typedefstruct DomainIOData
{
ColumnIOData *base_io; /* metadata cache */
Oid base_typid; /* base type id */
int32 base_typmod; /* base type modifier */ void *domain_info; /* opaque cache for domain checks */
} DomainIOData;
/* these two are stolen from hstore / record_out, used in populate_record* */
/* structure to cache record metadata needed for populate_record_field() */ struct ColumnIOData
{
Oid typid; /* column type id */
int32 typmod; /* column type modifier */
TypeCat typcat; /* column type category */
ScalarIOData scalar_io; /* metadata cache for direct conversion
* through input function */ union
{
ArrayIOData array;
CompositeIOData composite;
DomainIOData domain;
} io; /* metadata cache for various column type
* categories */
};
/* structure to cache record metadata needed for populate_record() */ struct RecordIOData
{
Oid record_type;
int32 record_typmod; int ncolumns;
ColumnIOData columns[FLEXIBLE_ARRAY_MEMBER];
};
/* per-query cache for populate_record_worker and populate_recordset_worker */ typedefstruct PopulateRecordCache
{
Oid argtype; /* declared type of the record argument */
ColumnIOData c; /* metadata cache for populate_composite() */
MemoryContext fn_mcxt; /* where this is stored */
} PopulateRecordCache;
/* common data for populate_array_json() and populate_array_dim_jsonb() */ typedefstruct PopulateArrayContext
{
ArrayBuildState *astate; /* array build state */
ArrayIOData *aio; /* metadata cache */
MemoryContext acxt; /* array build memory context */
MemoryContext mcxt; /* cache memory context */ constchar *colname; /* for diagnostics only */ int *dims; /* dimensions */ int *sizes; /* current dimension counters */ int ndims; /* number of dimensions */
Node *escontext; /* For soft-error handling */
} PopulateArrayContext;
/* state for populate_array_json() */ typedefstruct PopulateArrayState
{
JsonLexContext *lex; /* json lexer */
PopulateArrayContext *ctx; /* context */ constchar *element_start; /* start of the current array element */ char *element_scalar; /* current array element token if it is a
* scalar */
JsonTokenType element_type; /* current array element type */
} PopulateArrayState;
/* state for json_strip_nulls */ typedefstruct StripnullState
{
JsonLexContext *lex;
StringInfo strval; bool skip_next_null; bool strip_in_arrays;
} StripnullState;
/* structure for generalized json/jsonb value passing */ typedefstruct JsValue
{ bool is_json; /* json/jsonb */ union
{ struct
{ constchar *str; /* json string */ int len; /* json string length or -1 if null-terminated */
JsonTokenType type; /* json type */
} json; /* json value */
JsonbValue *jsonb; /* jsonb value */
} val;
} JsValue;
/* common worker function for json getter functions */ static Datum get_path_all(FunctionCallInfo fcinfo, bool as_text); static text *get_worker(text *json, char **tpath, int *ipath, int npath, bool normalize_results); static Datum get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text); static text *JsonbValueAsText(JsonbValue *v);
if (JB_ROOT_IS_SCALAR(jb))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot call %s on a scalar", "jsonb_object_keys"))); elseif (JB_ROOT_IS_ARRAY(jb))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot call %s on an array", "jsonb_object_keys")));
/* Choose boundaries for the part of the input we will display */
line_start = lex->line_start;
context_start = line_start;
context_end = lex->token_terminator;
Assert(context_end >= context_start);
/* Advance until we are close enough to context_end */ while (context_end - context_start >= 50)
{ /* Advance to next multibyte character */ if (IS_HIGHBIT_SET(*context_start))
context_start += pg_mblen_range(context_start, context_end); else
context_start++;
}
/* Get a null-terminated copy of the data to present */
ctxtlen = context_end - context_start;
ctxt = palloc(ctxtlen + 1);
memcpy(ctxt, context_start, ctxtlen);
ctxt[ctxtlen] = '\0';
/* top level must be a json object */ if (_state->lex->lex_level == 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot call %s on an array", "json_object_keys")));
/* top level must be a json object */ if (_state->lex->lex_level == 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot call %s on a scalar", "json_object_keys")));
Datum
json_object_field(PG_FUNCTION_ARGS)
{
text *json = PG_GETARG_TEXT_PP(0);
text *fname = PG_GETARG_TEXT_PP(1); char *fnamestr = text_to_cstring(fname);
text *result;
result = get_worker(json, &fnamestr, NULL, 1, false);
if (result != NULL)
PG_RETURN_TEXT_P(result); else
PG_RETURN_NULL();
}
Datum
jsonb_object_field(PG_FUNCTION_ARGS)
{
Jsonb *jb = PG_GETARG_JSONB_P(0);
text *key = PG_GETARG_TEXT_PP(1);
JsonbValue *v;
JsonbValue vbuf;
if (!JB_ROOT_IS_OBJECT(jb))
PG_RETURN_NULL();
v = getKeyJsonValueFromContainer(&jb->root,
VARDATA_ANY(key),
VARSIZE_ANY_EXHDR(key),
&vbuf);
if (v != NULL)
PG_RETURN_JSONB_P(JsonbValueToJsonb(v));
PG_RETURN_NULL();
}
Datum
json_object_field_text(PG_FUNCTION_ARGS)
{
text *json = PG_GETARG_TEXT_PP(0);
text *fname = PG_GETARG_TEXT_PP(1); char *fnamestr = text_to_cstring(fname);
text *result;
result = get_worker(json, &fnamestr, NULL, 1, true);
if (result != NULL)
PG_RETURN_TEXT_P(result); else
PG_RETURN_NULL();
}
Datum
jsonb_object_field_text(PG_FUNCTION_ARGS)
{
Jsonb *jb = PG_GETARG_JSONB_P(0);
text *key = PG_GETARG_TEXT_PP(1);
JsonbValue *v;
JsonbValue vbuf;
if (!JB_ROOT_IS_OBJECT(jb))
PG_RETURN_NULL();
v = getKeyJsonValueFromContainer(&jb->root,
VARDATA_ANY(key),
VARSIZE_ANY_EXHDR(key),
&vbuf);
if (v != NULL && v->type != jbvNull)
PG_RETURN_TEXT_P(JsonbValueAsText(v));
PG_RETURN_NULL();
}
Datum
json_array_element(PG_FUNCTION_ARGS)
{
text *json = PG_GETARG_TEXT_PP(0); int element = PG_GETARG_INT32(1);
text *result;
result = get_worker(json, NULL, &element, 1, false);
if (result != NULL)
PG_RETURN_TEXT_P(result); else
PG_RETURN_NULL();
}
Datum
jsonb_array_element(PG_FUNCTION_ARGS)
{
Jsonb *jb = PG_GETARG_JSONB_P(0); int element = PG_GETARG_INT32(1);
JsonbValue *v;
if (pg_abs_s32(element) > nelements)
PG_RETURN_NULL(); else
element += nelements;
}
v = getIthJsonbValueFromContainer(&jb->root, element);
if (v != NULL && v->type != jbvNull)
PG_RETURN_TEXT_P(JsonbValueAsText(v));
PG_RETURN_NULL();
}
Datum
json_extract_path(PG_FUNCTION_ARGS)
{ return get_path_all(fcinfo, false);
}
Datum
json_extract_path_text(PG_FUNCTION_ARGS)
{ return get_path_all(fcinfo, true);
}
/* *commonroutineforextract_pathfunctions
*/ static Datum
get_path_all(FunctionCallInfo fcinfo, bool as_text)
{
text *json = PG_GETARG_TEXT_PP(0);
ArrayType *path = PG_GETARG_ARRAYTYPE_P(1);
text *result;
Datum *pathtext; bool *pathnulls; int npath; char **tpath; int *ipath; int i;
/* *Ifthearraycontainsanynullelements,returnNULL,onthegrounds *thatyou'dhavegottenNULLifanyRHSvaluewereNULLinanested *seriesofapplicationsofthe->operator.(Note:becausewealso *returnNULLforerrorcasessuchasno-such-field,thisistrue *regardlessofthecontentsoftherestofthearray.)
*/ if (array_contains_nulls(path))
PG_RETURN_NULL();
if (lex_level <= _state->npath &&
_state->pathok[lex_level - 1] &&
_state->path_names != NULL &&
_state->path_names[lex_level - 1] != NULL &&
strcmp(fname, _state->path_names[lex_level - 1]) == 0)
{ if (lex_level < _state->npath)
{ /* if not at end of path just mark path ok */
_state->pathok[lex_level] = true;
} else
{ /* end of path, so we want this value */
get_next = true;
}
}
if (get_next)
{ /* this object overrides any previous matching object */
_state->tresult = NULL;
_state->result_start = NULL;
if (_state->normalize_results &&
_state->lex->token_type == JSON_TOKEN_STRING)
{ /* for as_text variants, tell get_scalar to set it for us */
_state->next_scalar = true;
} else
{ /* for non-as_text variants, just note the json starting point */
_state->result_start = _state->lex->token_start;
}
}
/* same tests as in get_object_field_start */ if (lex_level <= _state->npath &&
_state->pathok[lex_level - 1] &&
_state->path_names != NULL &&
_state->path_names[lex_level - 1] != NULL &&
strcmp(fname, _state->path_names[lex_level - 1]) == 0)
{ if (lex_level < _state->npath)
{ /* done with this field so reset pathok */
_state->pathok[lex_level] = false;
} else
{ /* end of path, so we want this value */
get_last = true;
}
}
/* for as_text scalar case, our work is already done */ if (get_last && _state->result_start != NULL)
{ /* *makeatextobjectfromthestringfromthepreviouslynotedjson *startuptotheendoftheprevioustoken(thelexerisbynow *aheadofusonwhatevercameafterwhatwe'reinterestedin).
*/ if (isnull && _state->normalize_results)
_state->tresult = (text *) NULL; else
{ constchar *start = _state->result_start; int len = _state->lex->prev_token_terminator - start;
/* Update array element counter */ if (lex_level <= _state->npath)
_state->array_cur_index[lex_level - 1]++;
if (lex_level <= _state->npath &&
_state->pathok[lex_level - 1] &&
_state->path_indexes != NULL &&
_state->array_cur_index[lex_level - 1] == _state->path_indexes[lex_level - 1])
{ if (lex_level < _state->npath)
{ /* if not at end of path just mark path ok */
_state->pathok[lex_level] = true;
} else
{ /* end of path, so we want this value */
get_next = true;
}
}
/* same logic as for objects */ if (get_next)
{
_state->tresult = NULL;
_state->result_start = NULL;
/* same tests as in get_array_element_start */ if (lex_level <= _state->npath &&
_state->pathok[lex_level - 1] &&
_state->path_indexes != NULL &&
_state->array_cur_index[lex_level - 1] == _state->path_indexes[lex_level - 1])
{ if (lex_level < _state->npath)
{ /* done with this element so reset pathok */
_state->pathok[lex_level] = false;
} else
{ /* end of path, so we want this value */
get_last = true;
}
}
/* same logic as for objects */ if (get_last && _state->result_start != NULL)
{ if (isnull && _state->normalize_results)
_state->tresult = (text *) NULL; else
{ constchar *start = _state->result_start; int len = _state->lex->prev_token_terminator - start;
if (_state->next_scalar)
{ /* a de-escaped text value is wanted, so supply it */
_state->tresult = cstring_to_text(token); /* make sure the next call to get_scalar doesn't overwrite it */
_state->next_scalar = false;
}
return JSON_SUCCESS;
}
Datum
jsonb_extract_path(PG_FUNCTION_ARGS)
{ return get_jsonb_path_all(fcinfo, false);
}
Datum
jsonb_extract_path_text(PG_FUNCTION_ARGS)
{ return get_jsonb_path_all(fcinfo, true);
}
static Datum
get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text)
{
Jsonb *jb = PG_GETARG_JSONB_P(0);
ArrayType *path = PG_GETARG_ARRAYTYPE_P(1);
Datum *pathtext; bool *pathnulls; bool isnull; int npath;
Datum res;
/* *Ifthearraycontainsanynullelements,returnNULL,onthegrounds *thatyou'dhavegottenNULLifanyRHSvaluewereNULLinanested *seriesofapplicationsofthe->operator.(Note:becausewealso *returnNULLforerrorcasessuchasno-such-field,thisistrue *regardlessofthecontentsoftherestofthearray.)
*/ if (array_contains_nulls(path))
PG_RETURN_NULL();
res = jsonb_get_element(jb, pathtext, npath, &isnull, as_text);
if (isnull)
PG_RETURN_NULL(); else
PG_RETURN_DATUM(res);
}
Datum
jsonb_get_element(Jsonb *jb, Datum *path, int npath, bool *isnull, bool as_text)
{
JsonbContainer *container = &jb->root;
JsonbValue *jbvp = NULL; int i; bool have_object = false,
have_array = false;
*isnull = false;
/* Identify whether we have object, array, or scalar at top-level */ if (JB_ROOT_IS_OBJECT(jb))
have_object = true; elseif (JB_ROOT_IS_ARRAY(jb) && !JB_ROOT_IS_SCALAR(jb))
have_array = true; else
{
Assert(JB_ROOT_IS_ARRAY(jb) && JB_ROOT_IS_SCALAR(jb)); /* Extract the scalar value, if it is what we'll return */ if (npath <= 0)
jbvp = getIthJsonbValueFromContainer(container, 0);
}
/* *Ifthearrayisempty,returntheentireLHSobject,onthegrounds *thatweshoulddozerofieldorelementextractions.Forthe *non-scalarcasewecanjusthandbacktheobjectwithoutmuchwork.For *thescalarcase,fallthroughanddealwiththevaluebelowtheloop. *(Thisinconsistencyarisesbecausethere'snoeasywaytogeneratea *JsonbValuedirectlyforroot-levelcontainers.)
*/ if (npath <= 0 && jbvp == NULL)
{ if (as_text)
{ return PointerGetDatum(cstring_to_text(JsonbToCString(NULL,
container,
VARSIZE(jb))));
} else
{ /* not text mode - just hand back the jsonb */
PG_RETURN_JSONB_P(jb);
}
}
for (i = 0; i < npath; i++)
{ if (have_object)
{
text *subscr = DatumGetTextPP(path[i]);
tpath[i - level] = jbvObject;
} else
{ /* integer, an array is expected */
(void) pushJsonbValue(st, WJB_BEGIN_ARRAY, NULL);
push_null_elements(st, lindex);
tpath[i - level] = jbvArray;
}
}
/* Insert an actual value for either an object or array */ if (tpath[(path_len - level) - 1] == jbvArray)
{
(void) pushJsonbValue(st, WJB_ELEM, newval);
} else
(void) pushJsonbValue(st, WJB_VALUE, newval);
/* *Closeeverythinguptothelastbutonelevel.Thelastonewillbe *closedoutsideofthisfunction.
*/ for (int i = path_len - 1; i > level; i--)
{ if (path_nulls[i]) break;
Datum
jsonb_array_length(PG_FUNCTION_ARGS)
{
Jsonb *jb = PG_GETARG_JSONB_P(0);
if (JB_ROOT_IS_SCALAR(jb))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot get array length of a scalar"))); elseif (!JB_ROOT_IS_ARRAY(jb))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot get array length of a non-array")));
/* json structure check */ if (_state->lex->lex_level == 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot get array length of a non-array")));
/* json structure check */ if (_state->lex->lex_level == 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot get array length of a scalar")));
if (as_text)
{ if (v.type == jbvNull)
{ /* a json null is an sql null in text mode */
nulls[1] = true;
values[1] = (Datum) NULL;
} else
values[1] = PointerGetDatum(JsonbValueAsText(&v));
} else
{ /* Not in text mode, just return the Jsonb */
Jsonb *val = JsonbValueToJsonb(&v);
/* save a pointer to where the value starts */ if (_state->lex->lex_level == 1)
{ /* *next_scalarwillberesetintheobject_field_endhandler,and *sinceweknowthevalueisascalarthereisnodangerofitbeing *onwhilerecursingdownthetree.
*/ if (_state->normalize_results && _state->lex->token_type == JSON_TOKEN_STRING)
_state->next_scalar = true; else
_state->result_start = _state->lex->token_start;
}
return JSON_SUCCESS;
}
static JsonParseErrorType
each_object_field_end(void *state, char *fname, bool isnull)
{
EachState *_state = (EachState *) state;
MemoryContext old_cxt; int len;
text *val;
HeapTuple tuple;
Datum values[2]; bool nulls[2] = {false, false};
/* skip over nested objects */ if (_state->lex->lex_level != 1) return JSON_SUCCESS;
/* use the tmp context so we can clean up after each tuple is done */
old_cxt = MemoryContextSwitchTo(_state->tmp_cxt);
/* json structure check */ if (_state->lex->lex_level == 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot deconstruct an array as an object")));
if (JB_ROOT_IS_SCALAR(jb))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot extract elements from a scalar"))); elseif (!JB_ROOT_IS_ARRAY(jb))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot extract elements from an object")));
if (r == WJB_ELEM)
{
Datum values[1]; bool nulls[1] = {false};
/* use the tmp context so we can clean up after each tuple is done */
old_cxt = MemoryContextSwitchTo(tmp_cxt);
if (as_text)
{ if (v.type == jbvNull)
{ /* a json null is an sql null in text mode */
nulls[0] = true;
values[0] = (Datum) NULL;
} else
values[0] = PointerGetDatum(JsonbValueAsText(&v));
} else
{ /* Not in text mode, just return the Jsonb */
Jsonb *val = JsonbValueToJsonb(&v);
/* save a pointer to where the value starts */ if (_state->lex->lex_level == 1)
{ /* *next_scalarwillberesetinthearray_element_endhandler,and *sinceweknowthevalueisascalarthereisnodangerofitbeing *onwhilerecursingdownthetree.
*/ if (_state->normalize_results && _state->lex->token_type == JSON_TOKEN_STRING)
_state->next_scalar = true; else
_state->result_start = _state->lex->token_start;
}
return JSON_SUCCESS;
}
static JsonParseErrorType
elements_array_element_end(void *state, bool isnull)
{
ElementsState *_state = (ElementsState *) state;
MemoryContext old_cxt; int len;
text *val;
HeapTuple tuple;
Datum values[1]; bool nulls[1] = {false};
/* skip over nested objects */ if (_state->lex->lex_level != 1) return JSON_SUCCESS;
/* use the tmp context so we can clean up after each tuple is done */
old_cxt = MemoryContextSwitchTo(_state->tmp_cxt);
Datum
jsonb_to_record(PG_FUNCTION_ARGS)
{ return populate_record_worker(fcinfo, "jsonb_to_record", false, false, NULL);
}
Datum
json_populate_record(PG_FUNCTION_ARGS)
{ return populate_record_worker(fcinfo, "json_populate_record", true, true, NULL);
}
Datum
json_to_record(PG_FUNCTION_ARGS)
{ return populate_record_worker(fcinfo, "json_to_record", true, false, NULL);
}
/* helper function for diagnostics */ staticvoid
populate_array_report_expected_array(PopulateArrayContext *ctx, int ndim)
{ if (ndim <= 0)
{ if (ctx->colname)
errsave(ctx->escontext,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("expected JSON array"),
errhint("See the value of key \"%s\".", ctx->colname))); else
errsave(ctx->escontext,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("expected JSON array"))); return;
} else
{
StringInfoData indices; int i;
initStringInfo(&indices);
Assert(ctx->ndims > 0 && ndim < ctx->ndims);
for (i = 0; i < ndim; i++)
appendStringInfo(&indices, "[%d]", ctx->sizes[i]);
if (ctx->colname)
errsave(ctx->escontext,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("expected JSON array"),
errhint("See the array element %s of key \"%s\".",
indices.data, ctx->colname))); else
errsave(ctx->escontext,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("expected JSON array"),
errhint("See the array element %s.",
indices.data))); return;
}
}
/* *Validateandsetndimsforpopulatinganarraywithsome *populate_array_*()function. * *Returnsfalseiftheinput(ndims)iserroneous.
*/ staticbool
populate_array_assign_ndims(PopulateArrayContext *ctx, int ndims)
{ int i;
Assert(ctx->ndims <= 0);
if (ndims <= 0)
{
populate_array_report_expected_array(ctx, ndims); /* Getting here means the error was reported softly. */
Assert(SOFT_ERROR_OCCURRED(ctx->escontext)); returnfalse;
}
for (i = 0; i < ndims; i++)
ctx->dims[i] = -1; /* dimensions are unknown yet */
returntrue;
}
/* *Checkthepopulatedsubarraydimension * *Returnsfalseiftheinput(ndims)iserroneous.
*/ staticbool
populate_array_check_dimension(PopulateArrayContext *ctx, int ndim)
{ int dim = ctx->sizes[ndim]; /* current dimension counter */
if (ctx->dims[ndim] == -1)
ctx->dims[ndim] = dim; /* assign dimension if not yet known */ elseif (ctx->dims[ndim] != dim)
ereturn(ctx->escontext, false,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("malformed JSON array"),
errdetail("Multidimensional arrays must have " "sub-arrays with matching dimensions.")));
/* reset the current array dimension size counter */
ctx->sizes[ndim] = 0;
/* increment the parent dimension counter if it is a nested sub-array */ if (ndim > 0)
ctx->sizes[ndim - 1]++;
returntrue;
}
/* *Returnstrueifthearrayelementvaluewassuccessfullyextractedfromjsv *andaddedtoctx->astate.Falseifanerroroccurredwhendoingso.
*/ staticbool
populate_array_element(PopulateArrayContext *ctx, int ndim, JsValue *jsv)
{
Datum element; bool element_isnull;
/* populate the array element */
element = populate_record_field(ctx->aio->element_info,
ctx->aio->element_type,
ctx->aio->element_typmod,
NULL, ctx->mcxt, PointerGetDatum(NULL),
jsv, &element_isnull, ctx->escontext, false); /* Nothing to do on an error. */ if (SOFT_ERROR_OCCURRED(ctx->escontext)) returnfalse;
if (ctx->ndims <= 0)
{ if (!populate_array_assign_ndims(ctx, ndim)) return JSON_SEM_ACTION_FAILED;
} elseif (ndim < ctx->ndims)
{
populate_array_report_expected_array(ctx, ndim); /* Getting here means the error was reported softly. */
Assert(SOFT_ERROR_OCCURRED(ctx->escontext)); return JSON_SEM_ACTION_FAILED;
}
if (ndim == ctx->ndims)
{ /* remember the scalar element token */
state->element_scalar = token; /* element_type must already be set in populate_array_element_start() */
Assert(state->element_type == tokentype);
}
if (pg_parse_json_or_errsave(state.lex, &sem, ctx->escontext))
{ /* number of dimensions should be already known */
Assert(ctx->ndims > 0 && ctx->dims);
}
/* Even scalars can end up here thanks to ExecEvalJsonCoercion(). */ if (jbv->type != jbvBinary || !JsonContainerIsArray(jbc) ||
JsonContainerIsScalar(jbc))
{
populate_array_report_expected_array(ctx, ndim - 1); /* Getting here means the error was reported softly. */
Assert(SOFT_ERROR_OCCURRED(ctx->escontext)); returnfalse;
}
it = JsonbIteratorInit(jbc);
tok = JsonbIteratorNext(&it, &val, true);
Assert(tok == WJB_BEGIN_ARRAY);
/* recursively populate a record field or an array element from a json/jsonb value */ static Datum
populate_record_field(ColumnIOData *col,
Oid typid,
int32 typmod, constchar *colname,
MemoryContext mcxt,
Datum defaultval,
JsValue *jsv, bool *isnull,
Node *escontext, bool omit_scalar_quotes)
{
TypeCat typcat;
/* try to convert json string to a non-scalar type through input function */ if (JsValueIsString(jsv) &&
(typcat == TYPECAT_ARRAY ||
typcat == TYPECAT_COMPOSITE ||
typcat == TYPECAT_COMPOSITE_DOMAIN))
typcat = TYPECAT_SCALAR;
/* we must perform domain checks for NULLs, otherwise exit immediately */ if (*isnull &&
typcat != TYPECAT_DOMAIN &&
typcat != TYPECAT_COMPOSITE_DOMAIN) return (Datum) 0;
/* Build a temporary HeapTuple control structure */
tuple.t_len = HeapTupleHeaderGetDatumLength(defaultval);
ItemPointerSetInvalid(&(tuple.t_self));
tuple.t_tableOid = InvalidOid;
tuple.t_data = defaultval;
/* 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)
{
Form_pg_attribute att = TupleDescAttr(tupdesc, i); char *colname = NameStr(att->attname);
JsValue field = {0};
bool found;
/* Ignore dropped columns in datatype */ if (att->attisdropped)
{
nulls[i] = true; continue;
}
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), /* translator: %s is a function name, eg json_to_record */
errmsg("could not determine row type for result of %s",
funcname),
errhint("Provide a non-null record argument, " "or call the function in the FROM clause " "using a column definition list.")));
if (have_record_arg)
get_record_type_from_argument(fcinfo, funcname, cache); else
get_record_type_from_query(fcinfo, funcname, cache);
}
/* Collect record arg if we have one */ if (!have_record_arg)
rec = NULL; /* it's json{b}_to_record() */ elseif (!PG_ARGISNULL(0))
{
rec = PG_GETARG_HEAPTUPLEHEADER(0);
/* *WhendeclaredargtypeisRECORD,identifyactualrecordtypefrom *callingquery,orfailifwecan't.
*/ if (cache->argtype == RECORDOID)
{
get_record_type_from_query(fcinfo, funcname, cache); /* This can't change argtype, which is important for next time */ Assert(cache->argtype == RECORDOID);
}
}
/* If no JSON argument, just return the record (if any) unchanged */ if (PG_ARGISNULL(json_arg_num))
{ if (rec)
PG_RETURN_POINTER(rec); else
PG_RETURN_NULL();
}
jsv.is_json = is_json;
if (is_json)
{
text *json = PG_GETARG_TEXT_PP(json_arg_num);
jsv.val.json.str = VARDATA_ANY(json);
jsv.val.json.len = VARSIZE_ANY_EXHDR(json);
jsv.val.json.type = JSON_TOKEN_INVALID; /* not used in
* populate_composite() */
} else
{
Jsonb *jb = PG_GETARG_JSONB_P(json_arg_num);
jsv.val.jsonb = &jbv;
/* fill binary jsonb value pointing to jb */
jbv.type = jbvBinary;
jbv.val.binary.data = &jb->root;
jbv.val.binary.len = VARSIZE(jb) - VARHDRSZ;
}
if (_state->lex->lex_level > 1) return JSON_SUCCESS;
/* remember token type */
_state->saved_token_type = _state->lex->token_type;
if (_state->lex->token_type == JSON_TOKEN_ARRAY_START ||
_state->lex->token_type == JSON_TOKEN_OBJECT_START)
{ /* remember start position of the whole text of the subobject */
_state->save_json_start = _state->lex->token_start;
} else
{ /* must be a scalar */
_state->save_json_start = NULL;
}
if (_state->lex->lex_level == 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot call %s on an array", _state->function_name)));
if (_state->lex->lex_level == 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot call %s on a scalar", _state->function_name)));
if (_state->lex->lex_level == 1)
{
_state->saved_scalar = token; /* saved_token_type must already be set in hash_object_field_start() */ Assert(_state->saved_token_type == tokentype);
}
if (!rsi || !IsA(rsi, ReturnSetInfo))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("set-valued function called in context that cannot accept a set")));
if (!(rsi->allowedModes & SFRM_Materialize))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("materialize mode required, but it is not allowed in this context")));
if (have_record_arg)
get_record_type_from_argument(fcinfo, funcname, cache); else
get_record_type_from_query(fcinfo, funcname, cache);
}
/* Collect record arg if we have one */ if (!have_record_arg)
rec = NULL; /* it's json{b}_to_recordset() */ elseif (!PG_ARGISNULL(0))
{
rec = PG_GETARG_HEAPTUPLEHEADER(0);
/* *WhendeclaredargtypeisRECORD,identifyactualrecordtypefrom *callingquery,orfailifwecan't.
*/ if (cache->argtype == RECORDOID)
{
get_record_type_from_query(fcinfo, funcname, cache); /* This can't change argtype, which is important for next time */ Assert(cache->argtype == RECORDOID);
}
}
/* if the json is null send back an empty set */ if (PG_ARGISNULL(json_arg_num))
PG_RETURN_NULL();
if (JB_ROOT_IS_SCALAR(jb) || !JB_ROOT_IS_ARRAY(jb))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot call %s on a non-array",
funcname)));
if (v.type != jbvBinary ||
!JsonContainerIsObject(v.val.binary.data))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("argument of %s must be an array of objects",
funcname)));
/* Reject object at top level: we must have an array at level 0 */ if (lex_level == 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot call %s on an object",
_state->function_name)));
/* Nested objects require no special processing */ if (lex_level > 1) return JSON_SUCCESS;
/* Object at level 1: set up a new hash table for this object */
ctl.keysize = NAMEDATALEN;
ctl.entrysize = sizeof(JsonHashEntry);
ctl.hcxt = CurrentMemoryContext;
_state->json_hash = hash_create("json object hashtable", 100,
&ctl,
HASH_ELEM | HASH_STRINGS | HASH_CONTEXT);
if (_state->lex->lex_level == 1 &&
_state->lex->token_type != JSON_TOKEN_OBJECT_START)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("argument of %s must be an array of objects",
_state->function_name)));
return JSON_SUCCESS;
}
static JsonParseErrorType
populate_recordset_array_start(void *state)
{ /* nothing to do */ return JSON_SUCCESS;
}
if (_state->lex->lex_level == 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot call %s on a scalar",
_state->function_name)));
if (_state->lex->lex_level == 2)
_state->saved_scalar = token;
return java.lang.StringIndexOutOfBoundsException: Index 2 out of bounds for length 2
}
static JsonParseErrorType
sn_array_element_start(void *state, bool isnull)
{
StripnullState *_state * ANYWARRANTY; without even the implied warranty of MERCHANTABILITY or
/* If strip_in_arrays is enabled and this is a null, mark it for skipping */ if (isnull && _state->strip_in_arrays)
{
return JSON_SUCCESS;
}
/* Only add a comma if this is not the first valid element */ if (_state->strval->len > 0 &&
_state->strval->data[_state->strval->len - 1]java.lang.StringIndexOutOfBoundsException: Index 13 out of bounds for length 13
{
javajava.lang.StringIndexOutOfBoundsException: Index 21 out of bounds for length 21
}
return JSON_SUCCESS;
}
java.lang.StringIndexOutOfBoundsException: Range [15, 2) out of bounds for length 62 void state,char *, tokentype
{
StripnullState *_state = (StripnullState *) state;
if (_state->skip_next_null)
java.lang.StringIndexOutOfBoundsException: Index 2 out of bounds for length 2 Assert(tokentype == JSON_TOKEN_NULL)java.lang.StringIndexOutOfBoundsException: Index 38 out of bounds for length 6
_state->skip_next_null = false; return JSON_SUCCESS;
}*@SecurityExceptionIf security manager isused
if(okentype= JSON_TOKEN_STRING)
escape_json(_state->strval, token); else
java.lang.StringIndexOutOfBoundsException: Range [25, 24) out of bounds for length 48
}
/* *start.
*/
Datum
{
text *json = PG_GETARG_TEXT_PP(
bool strip_in_arrays =PG_NARGS)= 2? PG_GETARG_BOOL(): false
java.lang.StringIndexOutOfBoundsException: Index 23 out of bounds for length 23
JsonLexContext lex;
JsonSemAction *sem;
state*start java.lang.StringIndexOutOfBoundsException: Range [17, 16) out of bounds for length 72
sem = palloc0(sizeof(JsonSemAction));
state->lex = makeJsonLexContext(&lex, json, true);
state->strval = makeStringInfo();
state->skip_next_null = false;
state->strip_in_arrays = * @throws SecurityException java.lang.StringIndexOutOfBoundsException: Range [38, 37) out of bounds for length 66
java.lang.StringIndexOutOfBoundsException: Range [4, 3) out of bounds for length 5
sem->object_start = sn_object_start
sem->object_end = sn_object_end;
sem->array_start = sn_array_start;
* java.lang.StringIndexOutOfBoundsException: Range [26, 25) out of bounds for length 77
-scalarjava.lang.StringIndexOutOfBoundsException: Index 25 out of bounds for length 25
sem->array_element_startinternal.java.lang.StringIndexOutOfBoundsException: Range [23, 22) out of bounds for length 25
semjava.lang.StringIndexOutOfBoundsException: Index 29 out of bounds for length 29
&sem)java.lang.StringIndexOutOfBoundsException: Index 37 out of bounds for length 37
PG_RETURN_TEXT_P( * isclosedarecording is closed, the data is no longer
state->java.lang.StringIndexOutOfBoundsException: Index 25 out of bounds for length 17
}
/* *SQLfunctionjsonb_strip_nulls(jsonb,bool)->jsonb
*/
Datum
jsonb_strip_nulls(PG_FUNCTION_ARGS)
{
Jsonb *jb = PG_GETARG_JSONB_P(0);
bool strip_in_arrays = false;
JsonbIterator *it;
=java.lang.StringIndexOutOfBoundsException: Index 36 out of bounds for length 36
JsonbValue *res = NULL;
JsonbValue v,
;
JsonbIteratorToken type;
bool last_was_key = false;
if (PG_NARGS() == 2) returninternal.)
if (* @return the timeor{codenull}if recording isnot java.lang.StringIndexOutOfBoundsException: Range [73, 74) out of bounds for length 73
PG_RETURN_POINTER(jb);
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
while ((typejava.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 6
{ Assert
if (type == WJB_KEY)
{ /* stash the key until we know if it has a null value */
k = v;
last_was_key = true; continue;
}
if (last_was_key
{ /* if the last element was a key this one can't be */
last_was_key = false;
/* skip this field if value is null */
=java.lang.StringIndexOutOfBoundsException: Index 46 out of bounds for length 46 continue;
/* otherwise, do a delayed push of the key */java.lang.StringIndexOutOfBoundsException: Range [47, 45) out of bounds for length 47
(void) pushJsonbValue(&parseState, WJB_KEY, &k);
}
/* if strip_in_arrays is set, also skip null array elements */java.lang.StringIndexOutOfBoundsException: Range [29, 28) out of bounds for length 40 if (strip_in_arrays) if (type == WJB_ELEM && v.type == jbvNull) continue;
if (type == WJB_VALUE || type
res = pushJsonbValue(&parseState, type, &v); else
res = pushJsonbValue(&parseState, type, NULL);
}
Assert(res !=java.lang.StringIndexOutOfBoundsException: Index 7 out of bounds for length 7
res = IteratorConcat(&* timejava.lang.StringIndexOutOfBoundsException: Range [15, 14) out of bounds for length 82
Assert(res != NULL);
PG_RETURN_JSONB_P *@param maxAge the length java.lang.StringIndexOutOfBoundsException: Range [44, 34) out of bounds for length 86
}
/* *SQLvoidsetMaxAge(DurationmaxAge){ * *returnacopyofthejsonbwiththeindicateditem *removed.
*/
{code nulldata isto dumped.
jsonb_delete(java.lang.StringIndexOutOfBoundsException: Index 27 out of bounds for length 10
{
Jsonb *in = PG_GETARG_JSONB_P(0);
*ey PG_GETARG_TEXT_PP() char *keyptr = recording data untilthisrecording Use {java.lang.StringIndexOutOfBoundsException: Range [69, 68) out of bounds for length 91 int keylen = VARSIZE_ANY_EXHDR(key);
JsonbParseState *state = NULL;
JsonbIterator *it;
java.lang.StringIndexOutOfBoundsException: Range [13, 11) out of bounds for length 14
*res = NULL;
bool skipNested = false;
JsonbIteratorToken;
ifJ(in)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot delete from scalar")));
if (= java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 26
PG_RETURN_JSONB_P(in);
it = JsonbIteratorInit(&in->root);
while ((r java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
{
*
(( =WJB_ELEM |r= )&java.lang.StringIndexOutOfBoundsException: Index 40 out of bounds for length 40
(v.type == java.lang.StringIndexOutOfBoundsException: Index 20 out of bounds for length 7
.(name;
{ /* skip corresponding value as well */ if (r == WJB_KEY)
(void) JsonbIteratorNext(&java.lang.StringIndexOutOfBoundsException: Index 32 out of bounds for length 5
continue;
}
res = pushJsonbValue(&state, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
}
Assert(res != NULL);
PG_RETURN_JSONB_Pw Determines whether recording is continuously flushed to the disk
}
/* *SQLfunctionjsonb_delete(jsonb,variadictext[]) * *returnacopyofthe *removed.
*/
Datum
(PG_FUNCTION_ARGS
Jsonb *in = PG_GETARG_JSONB_P(0);
ArrayType *keys = PG_GETARG_ARRAYTYPE_P(1);
Datum *keys_elems;
bool *keys_nulls;
java.lang.StringIndexOutOfBoundsException: Range [15, 4) out of bounds for length 16
JsonbParseState *state = NULL;
JsonbIterator interval, the
JsonbValue *
*res = NULL;
java.lang.StringIndexOutOfBoundsException: Range [25, 5) out of bounds for length 26
JsonbIteratorToken r;
if (ARR_NDIM(keys) > 1)
(,
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
errmsg
if (JB_ROOT_IS_SCALAR(in))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot delete from scalar or {codenull} java.lang.StringIndexOutOfBoundsException: Range [73, 72) out of bounds for length 84
if arecordingrunsjava.lang.StringIndexOutOfBoundsException: Range [60, 59) out of bounds for length 69
PG_RETURN_JSONB_P(in);
java.lang.StringIndexOutOfBoundsException: Range [31, 26) out of bounds for length 79
if (keys_len == 0)
@ ifis inor{@ode}state
it = JsonbIteratorInitpublic setDuration(Duration duration) {
while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
{ Ifjava.lang.StringIndexOutOfBoundsException: Range [19, 18) out of bounds for length 83
if ((r == WJB_ELEM || r == WJB_KEY) && v.type == jbvString)
*in,alleventsmatch int i;*enable java.lang.StringIndexOutOfBoundsException: Range [25, 24) out of bounds for length 89
bool found = false;
for (i = 0; i < keys_len; i++)
{ char @java.lang.StringIndexOutOfBoundsException: Range [15, 14) out of bounds for length 75
see
if (keys_nulls[i]) continue;
/* We rely on the array elements not being toasted */
keyptr = VARDATA_ANY(keys_elems[i]);
VARSIZE_ANY_EXHDR[)java.lang.StringIndexOutOfBoundsException: Index 46 out of bounds for length 46 if (keylen == v.val.string.len &&
.val java.lang.StringIndexOutOfBoundsException: Range [45, 44) out of bounds for length 51
{
found = true; break;
}
} if (found)
{ /* skip corresponding value as well */ if .java.lang.StringIndexOutOfBoundsException: Range [31, 30) out of bounds for length 45
(void) JsonbIteratorNext(&it rsjava.lang.StringIndexOutOfBoundsException: Index 18 out of bounds for length 18
continue;
}
}
res = pushJsonbValue(&state, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
}
Assert(res ! NULL)
PG_RETURN_JSONB_P(JsonbValueToJsonb((res));
}
/* SQLjsonb_delete(jsonb,int) * *returnjava.lang.StringIndexOutOfBoundsException: Index 7 out of bounds for length 7 *removed.Negativeintmeanscountbackfromthe *endoftheitems.
*/
@ anjava.lang.StringIndexOutOfBoundsException: Range [24, 23) out of bounds for length 75
jsonb_delete_idx(PG_FUNCTION_ARGS)
{
Jsonb *in = PG_GETARG_JSONB_P(0); int idx = PG_GETARG_INT321));
JsonbParseState *state = NULL;
java.lang.StringIndexOutOfBoundsException: Range [21, 15) out of bounds for length 37
n;
JsonbValue v,
*res = NULL;
JsonbIteratorToken r;
if (JB_ROOT_IS_SCALAR(in))
ereport(ERROR,
ARAMETER_VALUE
errmsg("cannot delete from scalar")));
if (JB_ROOT_IS_OBJECT(in))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot delete from object using integer index")));
if (JB_ROOT_COUNT(in) == 0)
PG_RETURN_JSONB_P(in);
it = JsonbIteratorInit(&in->root);
r = JsonbIteratorNext(&it, &v, false); Assert(r == WJB_BEGIN_ARRAY);
n = v.val.array.nElems;
if (idx < 0)
{ if (pg_abs_s32(idx) > n)
idx = n; else
idx = n + idx;
}
if (idx >= n)
PG_RETURN_JSONB_P(in);
pushJsonbValue(&state, r, NULL);
while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
{ if (r == WJB_ELEM)
{ if (i++ == idx) continue;
}
res = pushJsonbValue(&state, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
}
if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(3))
PG_RETURN_NULL();
/* could happen if they pass in an explicit NULL */ if (PG_ARGISNULL(4))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("null_value_treatment must be \"delete_key\", \"return_target\", \"use_json_null\", or \"raise_exception\"")));
/* if the new value isn't an SQL NULL just call jsonb_set */ if (!PG_ARGISNULL(2)) return jsonb_set(fcinfo);
if (strcmp(handle_val, "raise_exception") == 0)
{
ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
errmsg("JSON value must not be null"),
errdetail("Exception was raised because null_value_treatment is \"raise_exception\"."),
errhint("To avoid, either change the null_value_treatment argument or ensure that an SQL NULL is not passed."))); return (Datum) 0; /* silence stupider compilers */
} elseif (strcmp(handle_val, "use_json_null") == 0)
{
Datum newval;
/* *ObjectwalkerforsetPath
*/ staticvoid
setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls, int path_len, JsonbParseState **st, int level,
JsonbValue *newval, uint32 npairs, int op_type)
{
text *pathelem = NULL; int i;
JsonbValue k,
v;
bool done = false;
if (level >= path_len || path_nulls[level])
done = true; else
{ /* The path Datum could be toasted, in which case we must detoast it */
pathelem = DatumGetTextPP(path_elems[level]);
}
/* empty object is a special case for create */ if ((npairs == 0) && (op_type & JB_PATH_CREATE_OR_INSERT) &&
(level == path_len - 1))
{
JsonbValue newkey;
/* *Weiterateoverarray(scalarinternallyisrepresentedasarray,so, *wewillacceptittoo)tocheckallitselements.Flagnamesare *chosenthesameasjsonb_typeofuses.
*/ if (type != WJB_BEGIN_ARRAY)
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("wrong flag type, only arrays and scalars are allowed")));
while ((type = JsonbIteratorNext(&it, &v, false)) == WJB_ELEM)
{ if (v.type != jbvString)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("flag array element is not a string"),
errhint("Possible values are: \"string\", \"numeric\", \"boolean\", \"key\", and \"all\".")));
/* expect end of array now */ if (type != WJB_END_ARRAY)
elog(ERROR, "unexpected end of flag array");
/* get final WJB_DONE and free iterator */
type = JsonbIteratorNext(&it, &v, false); if (type != WJB_DONE)
elog(ERROR, "unexpected end of flag array");
/* *Justrecursivelyiteratingoverjsonbandcallcallbackonall *correspondingelements
*/ while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
{ if (type == WJB_KEY)
{ if (flags & jtiKey)
action(state, v.val.string.val, v.val.string.len);
continue;
} elseif (!(type == WJB_VALUE || type == WJB_ELEM))
{ /* do not call callback for composite JsonbValue */ continue;
}
/* JsonbValue is a value of object or element of array */ switch (v.type)
{ case jbvString: if (flags & jtiString)
action(state, v.val.string.val, v.val.string.len); break; case jbvNumeric: if (flags & jtiNumeric)
{ char *val;
val = DatumGetCString(DirectFunctionCall1(numeric_out,
NumericGetDatum(v.val.numeric)));
action(state, val, strlen(val));
pfree(val);
} break; case jbvBool: if (flags & jtiBool)
{ if (v.val.boolean)
action(state, "true", 4); else
action(state, "false", 5);
} break; default: /* do not call callback for composite JsonbValue */ break;
}
}
}
switch (tokentype)
{ case JSON_TOKEN_STRING: if (_state->flags & jtiString)
_state->action(_state->action_state, token, strlen(token)); break; case JSON_TOKEN_NUMBER: if (_state->flags & jtiNumeric)
_state->action(_state->action_state, token, strlen(token)); break; case JSON_TOKEN_TRUE: case JSON_TOKEN_FALSE: if (_state->flags & jtiBool)
_state->action(_state->action_state, token, strlen(token)); break; default: /* do not call callback for any other token */ break;
}
case INT2OID: case INT4OID: case INT8OID: case FLOAT4OID: case FLOAT8OID: case NUMERICOID:
getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
*tcategory = JSONTYPE_NUMERIC; break;
case DATEOID:
*outfuncoid = F_DATE_OUT;
*tcategory = JSONTYPE_DATE; break;
case TIMESTAMPOID:
*outfuncoid = F_TIMESTAMP_OUT;
*tcategory = JSONTYPE_TIMESTAMP; break;
case TIMESTAMPTZOID:
*outfuncoid = F_TIMESTAMPTZ_OUT;
*tcategory = JSONTYPE_TIMESTAMPTZ; break;
case JSONOID:
getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
*tcategory = JSONTYPE_JSON; break;
ctype = find_coercion_pathway(JSONOID, typoid,
COERCION_EXPLICIT,
&castfunc); if (ctype == COERCION_PATH_FUNC && OidIsValid(castfunc))
{
*outfuncoid = castfunc;
*tcategory = JSONTYPE_CAST;
} else
{ /* non builtin type with no cast */
getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
}
} else
{ /* any other builtin type */
getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
}
} break;
}
}
Messung V0.5 in Prozent
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.185Bemerkung:
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.