1/*-------------------------------------------------------------------------
4 * Subscripting support functions for jsonb.
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/utils/adt/jsonbsubs.c
13 *-------------------------------------------------------------------------
26/* SubscriptingRefState.workspace for jsonb subscripting execution */
31 * be only integer or text */
37 * Finish parse analysis of a SubscriptingRef expression for a jsonb.
39 * Transform the subscript expressions, coerce them to text,
40 * and determine the result type of the SubscriptingRef node.
53 * Transform and convert the subscript expressions. Jsonb subscripting
54 * does not support slices, look only at the upper index.
56 foreach(
idx, indirection)
66 (
errcode(ERRCODE_DATATYPE_MISMATCH),
67 errmsg(
"jsonb subscript does not support slices"),
74 targetType = UNKNOWNOID;
79 if (subExprType != UNKNOWNOID)
81 Oid targets[2] = {INT4OID, TEXTOID};
84 * Jsonb can handle multiple subscript types, but cases when a
85 * subscript could be coerced to multiple target types must be
86 * avoided, similar to overloaded functions. It could be
87 * possibly extend with jsonpath in the future.
89 for (
int i = 0;
i < 2;
i++)
94 * One type has already succeeded, it means there are
95 * two coercion targets possible, failure.
97 if (targetType != UNKNOWNOID)
99 (
errcode(ERRCODE_DATATYPE_MISMATCH),
101 errhint(
"jsonb subscript must be coercible to only one type, integer or text."),
104 targetType = targets[
i];
109 * No suitable types were found, failure.
111 if (targetType == UNKNOWNOID)
113 (
errcode(ERRCODE_DATATYPE_MISMATCH),
115 errhint(
"jsonb subscript must be coercible to either integer or text."),
119 targetType = TEXTOID;
122 * We known from can_coerce_type that coercion will succeed, so
123 * coerce_type could be used. Note the implicit coercion context,
124 * which is required to handle subscripts of different types,
125 * similar to overloaded functions.
128 subExpr, subExprType,
135 (
errcode(ERRCODE_DATATYPE_MISMATCH),
136 errmsg(
"jsonb subscript must have text type"),
142 * Slice with omitted upper bound. Should not happen as we already
143 * errored out on slice earlier, but handle this just in case.
147 (
errcode(ERRCODE_DATATYPE_MISMATCH),
148 errmsg(
"jsonb subscript does not support slices"),
152 upperIndexpr =
lappend(upperIndexpr, subExpr);
155 /* store the transformed lists into the SubscriptRef node */
159 /* Determine the result type of the subscripting operation; always jsonb */
160 sbsref->refrestype = JSONBOID;
161 sbsref->reftypmod = -1;
165 * During execution, process the subscripts in a SubscriptingRef expression.
167 * The subscript expressions are already evaluated in Datum form in the
168 * SubscriptingRefState's arrays. Check and convert them as necessary.
170 * If any subscript is NULL, we throw error in assignment cases, or in fetch
171 * cases set result to NULL and return false (instructing caller to skip the
172 * rest of the SubscriptingRef sequence).
183 * In case if the first subscript is an integer, the source jsonb is
184 * expected to be an array. This information is not used directly, all
185 * such cases are handled within corresponding jsonb assign functions. But
186 * if the source jsonb is NULL the expected type will be used to construct
193 /* Process upper subscripts */
198 /* If any index expr yields NULL, result is NULL or error */
203 (
errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
204 errmsg(
"jsonb subscript in assignment must not be null")));
210 * For jsonb fetch and assign functions we need to provide path in
211 * text format. Convert if it's not already text.
229 * Evaluate SubscriptingRef fetch for a jsonb element.
231 * Source container is in step's result variable (it's known not NULL, since
232 * we set fetch_strict to true).
243 /* Should not get here if source jsonb (or any subscript) is null */
255 * Evaluate SubscriptingRef assignment for a jsonb element assignment.
257 * Input container (possibly null) is in result area, replacement value is in
258 * SubscriptingRefState's replacevalue/replacenull.
277 * In case if the input container is null, set up an empty jsonb and
278 * proceed with the assignment.
285 * To avoid any surprising results, set up an empty jsonb array in
286 * case of an array is expected (i.e. the first subscript is integer),
287 * otherwise jsonb object.
292 newSource.
val.array.nElems = 0;
293 newSource.
val.array.rawScalar =
false;
298 newSource.
val.object.nPairs = 0;
311 /* The result is never NULL, so no need to change *op->resnull */
315 * Compute old jsonb element value for a SubscriptingRef assignment
316 * expression. Will only be called if the new-value subexpression
317 * contains SubscriptingRef or FieldStore. This is the same as the
318 * regular fetch case, except that we have to handle a null jsonb,
319 * and the value should be stored into the SubscriptingRefState's
320 * prevvalue/prevnull fields.
331 /* whole jsonb is null, so any element is too */
348 * Set up execution state for a jsonb subscript operation. Opposite to the
349 * arrays subscription, there is no limit for number of subscripts as jsonb
350 * type itself doesn't have nesting limits.
362 /* Allocate type-specific workspace with space for per-subscript data */
364 nupper * (
sizeof(
Datum) +
sizeof(
Oid)));
369 * This coding assumes sizeof(Datum) >= sizeof(Oid), else we might
370 * misalign the indexOid pointer
373 ptr += nupper *
sizeof(
Datum);
378 /* Collect subscript data types necessary at execution time */
388 * Pass back pointers to appropriate step execution functions.
397 * jsonb_subscript_handler
398 * Subscripting handler for jsonb.
407 .fetch_strict =
true,
/* fetch returns NULL for NULL inputs */
408 .fetch_leakproof =
true,
/* fetch returns NULL for bad subscript */
409 .store_leakproof =
false /* ... but assignment throws error */
Datum idx(PG_FUNCTION_ARGS)
#define CStringGetTextDatum(s)
int errhint(const char *fmt,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
#define DirectFunctionCall1(func, arg1)
#define PG_RETURN_POINTER(x)
Assert(PointerIsAligned(start, uint64))
Datum int4out(PG_FUNCTION_ARGS)
if(TABLE==NULL||TABLE_index==NULL)
static Jsonb * DatumGetJsonbP(Datum d)
void JsonbToJsonbValue(Jsonb *jsonb, JsonbValue *val)
Jsonb * JsonbValueToJsonb(JsonbValue *val)
static bool jsonb_subscript_check_subscripts(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
static void jsonb_subscript_transform(SubscriptingRef *sbsref, List *indirection, ParseState *pstate, bool isSlice, bool isAssignment)
Datum jsonb_subscript_handler(PG_FUNCTION_ARGS)
static void jsonb_subscript_assign(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
static void jsonb_subscript_fetch(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
static void jsonb_exec_setup(const SubscriptingRef *sbsref, SubscriptingRefState *sbsrefstate, SubscriptExecSteps *methods)
struct JsonbSubWorkspace JsonbSubWorkspace
static void jsonb_subscript_fetch_old(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
Datum jsonb_set_element(Jsonb *jb, Datum *path, int path_len, JsonbValue *newval)
Datum jsonb_get_element(Jsonb *jb, Datum *path, int npath, bool *isnull, bool as_text)
List * lappend(List *list, void *datum)
void * palloc0(Size size)
Oid exprType(const Node *expr)
int exprLocation(const Node *expr)
Node * coerce_type(ParseState *pstate, Node *node, Oid inputTypeId, Oid targetTypeId, int32 targetTypeMod, CoercionContext ccontext, CoercionForm cformat, int location)
bool can_coerce_type(int nargs, const Oid *input_typeids, const Oid *target_typeids, CoercionContext ccontext)
Node * transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)
int parser_errposition(ParseState *pstate, int location)
#define lfirst_node(type, lc)
#define foreach_current_index(var_or_cell)
static char * DatumGetCString(Datum X)
struct ExprEvalStep::@57::@85 sbsref_subscript
struct ExprEvalStep::@57::@86 sbsref
struct SubscriptingRefState * state
union ExprEvalStep::@57 d
ParseExprKind p_expr_kind
ExecEvalSubroutine sbs_fetch_old
ExecEvalBoolSubroutine sbs_check_subscripts
ExecEvalSubroutine sbs_assign
ExecEvalSubroutine sbs_fetch
SubscriptTransform transform