PostgreSQL Source Code git master
Loading...
Searching...
No Matches
jsonbsubs.c File Reference
#include "postgres.h"
#include "catalog/pg_type_d.h"
#include "executor/execExpr.h"
#include "nodes/nodeFuncs.h"
#include "nodes/subscripting.h"
#include "parser/parse_coerce.h"
#include "parser/parse_expr.h"
#include "utils/builtins.h"
#include "utils/jsonb.h"
Include dependency graph for jsonbsubs.c:

Go to the source code of this file.

Data Structures

struct  JsonbSubWorkspace
 

Typedefs

typedef struct JsonbSubWorkspace JsonbSubWorkspace
 

Functions

static void jsonb_subscript_transform (SubscriptingRef *sbsref, List *indirection, ParseState *pstate, bool isSlice, bool isAssignment)
 
static bool jsonb_subscript_check_subscripts (ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 
static void jsonb_subscript_fetch (ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 
static void jsonb_subscript_assign (ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 
static void jsonb_subscript_fetch_old (ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 
static void jsonb_exec_setup (const SubscriptingRef *sbsref, SubscriptingRefState *sbsrefstate, SubscriptExecSteps *methods)
 
Datum jsonb_subscript_handler (PG_FUNCTION_ARGS)
 

Typedef Documentation

◆ JsonbSubWorkspace

Function Documentation

◆ jsonb_exec_setup()

static void jsonb_exec_setup ( const SubscriptingRef sbsref,
SubscriptingRefState sbsrefstate,
SubscriptExecSteps methods 
)
static

Definition at line 354 of file jsonbsubs.c.

357{
358 JsonbSubWorkspace *workspace;
359 ListCell *lc;
360 int nupper = sbsref->refupperindexpr->length;
361 char *ptr;
362
363 /* Allocate type-specific workspace with space for per-subscript data */
364 workspace = palloc0(MAXALIGN(sizeof(JsonbSubWorkspace)) +
365 nupper * (sizeof(Datum) + sizeof(Oid)));
366 workspace->expectArray = false;
367 ptr = ((char *) workspace) + MAXALIGN(sizeof(JsonbSubWorkspace));
368
369 /*
370 * This coding assumes sizeof(Datum) >= sizeof(Oid), else we might
371 * misalign the indexOid pointer
372 */
373 workspace->index = (Datum *) ptr;
374 ptr += nupper * sizeof(Datum);
375 workspace->indexOid = (Oid *) ptr;
376
377 sbsrefstate->workspace = workspace;
378
379 /* Collect subscript data types necessary at execution time */
380 foreach(lc, sbsref->refupperindexpr)
381 {
382 Node *expr = lfirst(lc);
384
385 workspace->indexOid[i] = exprType(expr);
386 }
387
388 /*
389 * Pass back pointers to appropriate step execution functions.
390 */
395}
#define MAXALIGN(LEN)
Definition c.h:898
int i
Definition isn.c:77
static bool jsonb_subscript_check_subscripts(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
Definition jsonbsubs.c:176
static void jsonb_subscript_assign(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
Definition jsonbsubs.c:262
static void jsonb_subscript_fetch(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
Definition jsonbsubs.c:236
static void jsonb_subscript_fetch_old(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
Definition jsonbsubs.c:324
void * palloc0(Size size)
Definition mcxt.c:1417
Oid exprType(const Node *expr)
Definition nodeFuncs.c:42
#define lfirst(lc)
Definition pg_list.h:172
#define foreach_current_index(var_or_cell)
Definition pg_list.h:403
uint64_t Datum
Definition postgres.h:70
unsigned int Oid
static int fb(int x)
int length
Definition pg_list.h:56
Definition nodes.h:135
ExecEvalSubroutine sbs_fetch_old
Definition execExpr.h:817
ExecEvalBoolSubroutine sbs_check_subscripts
Definition execExpr.h:814
ExecEvalSubroutine sbs_assign
Definition execExpr.h:816
ExecEvalSubroutine sbs_fetch
Definition execExpr.h:815
List * refupperindexpr
Definition primnodes.h:726

References JsonbSubWorkspace::expectArray, exprType(), fb(), foreach_current_index, i, JsonbSubWorkspace::index, JsonbSubWorkspace::indexOid, jsonb_subscript_assign(), jsonb_subscript_check_subscripts(), jsonb_subscript_fetch(), jsonb_subscript_fetch_old(), List::length, lfirst, MAXALIGN, palloc0(), SubscriptingRef::refupperindexpr, SubscriptExecSteps::sbs_assign, SubscriptExecSteps::sbs_check_subscripts, SubscriptExecSteps::sbs_fetch, and SubscriptExecSteps::sbs_fetch_old.

Referenced by jsonb_subscript_handler().

◆ jsonb_subscript_assign()

static void jsonb_subscript_assign ( ExprState state,
ExprEvalStep op,
ExprContext econtext 
)
static

Definition at line 262 of file jsonbsubs.c.

265{
267 JsonbSubWorkspace *workspace = (JsonbSubWorkspace *) sbsrefstate->workspace;
269 JsonbValue replacevalue;
270
271 if (sbsrefstate->replacenull)
272 replacevalue.type = jbvNull;
273 else
275 &replacevalue);
276
277 /*
278 * In case if the input container is null, set up an empty jsonb and
279 * proceed with the assignment.
280 */
281 if (*op->resnull)
282 {
284
285 /*
286 * To avoid any surprising results, set up an empty jsonb array in
287 * case of an array is expected (i.e. the first subscript is integer),
288 * otherwise jsonb object.
289 */
290 if (workspace->expectArray)
291 {
293 newSource.val.array.nElems = 0;
294 newSource.val.array.rawScalar = false;
295 }
296 else
297 {
298 newSource.type = jbvObject;
299 newSource.val.object.nPairs = 0;
300 }
301
303 *op->resnull = false;
304 }
305 else
307
309 workspace->index,
310 sbsrefstate->numupper,
311 &replacevalue);
312 /* The result is never NULL, so no need to change *op->resnull */
313}
@ jbvObject
Definition jsonb.h:236
@ jbvArray
Definition jsonb.h:235
@ jbvNull
Definition jsonb.h:230
static Jsonb * DatumGetJsonbP(Datum d)
Definition jsonb.h:401
void JsonbToJsonbValue(Jsonb *jsonb, JsonbValue *val)
Definition jsonb_util.c:76
Jsonb * JsonbValueToJsonb(JsonbValue *val)
Definition jsonb_util.c:96
Datum jsonb_set_element(Jsonb *jb, const Datum *path, int path_len, JsonbValue *newval)
Definition jsonfuncs.c:1682
union ExprEvalStep::@60 d
struct SubscriptingRefState * state
Definition execExpr.h:570
Datum * resvalue
Definition execExpr.h:310
bool * resnull
Definition execExpr.h:311
struct ExprEvalStep::@60::@89 sbsref
enum jbvType type
Definition jsonb.h:257
Definition jsonb.h:215

References ExprEvalStep::d, DatumGetJsonbP(), JsonbSubWorkspace::expectArray, fb(), JsonbSubWorkspace::index, jbvArray, jbvNull, jbvObject, jsonb_set_element(), JsonbToJsonbValue(), JsonbValueToJsonb(), ExprEvalStep::resnull, ExprEvalStep::resvalue, ExprEvalStep::sbsref, ExprEvalStep::state, and JsonbValue::type.

Referenced by jsonb_exec_setup().

◆ jsonb_subscript_check_subscripts()

static bool jsonb_subscript_check_subscripts ( ExprState state,
ExprEvalStep op,
ExprContext econtext 
)
static

Definition at line 176 of file jsonbsubs.c.

179{
181 JsonbSubWorkspace *workspace = (JsonbSubWorkspace *) sbsrefstate->workspace;
182
183 /*
184 * In case if the first subscript is an integer, the source jsonb is
185 * expected to be an array. This information is not used directly, all
186 * such cases are handled within corresponding jsonb assign functions. But
187 * if the source jsonb is NULL the expected type will be used to construct
188 * an empty source.
189 */
190 if (sbsrefstate->numupper > 0 && sbsrefstate->upperprovided[0] &&
191 !sbsrefstate->upperindexnull[0] && workspace->indexOid[0] == INT4OID)
192 workspace->expectArray = true;
193
194 /* Process upper subscripts */
195 for (int i = 0; i < sbsrefstate->numupper; i++)
196 {
197 if (sbsrefstate->upperprovided[i])
198 {
199 /* If any index expr yields NULL, result is NULL or error */
200 if (sbsrefstate->upperindexnull[i])
201 {
202 if (sbsrefstate->isassignment)
205 errmsg("jsonb subscript in assignment must not be null")));
206 *op->resnull = true;
207 return false;
208 }
209
210 /*
211 * For jsonb fetch and assign functions we need to provide path in
212 * text format. Convert if it's not already text.
213 */
214 if (workspace->indexOid[i] == INT4OID)
215 {
216 Datum datum = sbsrefstate->upperindex[i];
217 char *cs = DatumGetCString(DirectFunctionCall1(int4out, datum));
218
219 workspace->index[i] = CStringGetTextDatum(cs);
220 }
221 else
222 workspace->index[i] = sbsrefstate->upperindex[i];
223 }
224 }
225
226 return true;
227}
#define CStringGetTextDatum(s)
Definition builtins.h:98
int errcode(int sqlerrcode)
Definition elog.c:874
#define ERROR
Definition elog.h:39
#define ereport(elevel,...)
Definition elog.h:150
#define DirectFunctionCall1(func, arg1)
Definition fmgr.h:684
Datum int4out(PG_FUNCTION_ARGS)
Definition int.c:327
static char * errmsg
static char * DatumGetCString(Datum X)
Definition postgres.h:355
struct ExprEvalStep::@60::@88 sbsref_subscript

References CStringGetTextDatum, ExprEvalStep::d, DatumGetCString(), DirectFunctionCall1, ereport, errcode(), errmsg, ERROR, JsonbSubWorkspace::expectArray, fb(), i, JsonbSubWorkspace::index, JsonbSubWorkspace::indexOid, int4out(), ExprEvalStep::resnull, ExprEvalStep::sbsref_subscript, and ExprEvalStep::state.

Referenced by jsonb_exec_setup().

◆ jsonb_subscript_fetch()

static void jsonb_subscript_fetch ( ExprState state,
ExprEvalStep op,
ExprContext econtext 
)
static

Definition at line 236 of file jsonbsubs.c.

239{
241 JsonbSubWorkspace *workspace = (JsonbSubWorkspace *) sbsrefstate->workspace;
243
244 /* Should not get here if source jsonb (or any subscript) is null */
245 Assert(!(*op->resnull));
246
249 workspace->index,
250 sbsrefstate->numupper,
251 op->resnull,
252 false);
253}
#define Assert(condition)
Definition c.h:945
Datum jsonb_get_element(Jsonb *jb, const Datum *path, int npath, bool *isnull, bool as_text)
Definition jsonfuncs.c:1534

References Assert, ExprEvalStep::d, DatumGetJsonbP(), fb(), JsonbSubWorkspace::index, jsonb_get_element(), ExprEvalStep::resnull, ExprEvalStep::resvalue, ExprEvalStep::sbsref, and ExprEvalStep::state.

Referenced by jsonb_exec_setup().

◆ jsonb_subscript_fetch_old()

static void jsonb_subscript_fetch_old ( ExprState state,
ExprEvalStep op,
ExprContext econtext 
)
static

Definition at line 324 of file jsonbsubs.c.

327{
329
330 if (*op->resnull)
331 {
332 /* whole jsonb is null, so any element is too */
334 sbsrefstate->prevnull = true;
335 }
336 else
337 {
339
341 sbsrefstate->upperindex,
342 sbsrefstate->numupper,
343 &sbsrefstate->prevnull,
344 false);
345 }
346}

References ExprEvalStep::d, DatumGetJsonbP(), fb(), jsonb_get_element(), SubscriptingRefState::prevvalue, ExprEvalStep::resnull, ExprEvalStep::resvalue, ExprEvalStep::sbsref, and ExprEvalStep::state.

Referenced by jsonb_exec_setup().

◆ jsonb_subscript_handler()

Datum jsonb_subscript_handler ( PG_FUNCTION_ARGS  )

Definition at line 403 of file jsonbsubs.c.

404{
405 static const SubscriptRoutines sbsroutines = {
407 .exec_setup = jsonb_exec_setup,
408 .fetch_strict = true, /* fetch returns NULL for NULL inputs */
409 .fetch_leakproof = true, /* fetch returns NULL for bad subscript */
410 .store_leakproof = false /* ... but assignment throws error */
411 };
412
414}
#define PG_RETURN_POINTER(x)
Definition fmgr.h:363
static void jsonb_subscript_transform(SubscriptingRef *sbsref, List *indirection, ParseState *pstate, bool isSlice, bool isAssignment)
Definition jsonbsubs.c:44
static void jsonb_exec_setup(const SubscriptingRef *sbsref, SubscriptingRefState *sbsrefstate, SubscriptExecSteps *methods)
Definition jsonbsubs.c:354
SubscriptTransform transform

References fb(), jsonb_exec_setup(), jsonb_subscript_transform(), PG_RETURN_POINTER, and SubscriptRoutines::transform.

◆ jsonb_subscript_transform()

static void jsonb_subscript_transform ( SubscriptingRef sbsref,
List indirection,
ParseState pstate,
bool  isSlice,
bool  isAssignment 
)
static

Definition at line 44 of file jsonbsubs.c.

49{
52
53 /*
54 * Transform and convert the subscript expressions. Jsonb subscripting
55 * does not support slices, look only at the upper index.
56 */
57 foreach(idx, indirection)
58 {
61
62 if (isSlice)
63 {
64 Node *expr = ai->uidx ? ai->uidx : ai->lidx;
65
68 errmsg("jsonb subscript does not support slices"),
69 parser_errposition(pstate, exprLocation(expr))));
70 }
71
72 if (ai->uidx)
73 {
76
77 subExpr = transformExpr(pstate, ai->uidx, pstate->p_expr_kind);
79
81 {
82 Oid targets[2] = {INT4OID, TEXTOID};
83
84 /*
85 * Jsonb can handle multiple subscript types, but cases when a
86 * subscript could be coerced to multiple target types must be
87 * avoided, similar to overloaded functions. It could be
88 * possibly extend with jsonpath in the future.
89 */
90 for (int i = 0; i < 2; i++)
91 {
93 {
94 /*
95 * One type has already succeeded, it means there are
96 * two coercion targets possible, failure.
97 */
101 errmsg("subscript type %s is not supported", format_type_be(subExprType)),
102 errhint("jsonb subscript must be coercible to only one type, integer or text."),
104
105 targetType = targets[i];
106 }
107 }
108
109 /*
110 * No suitable types were found, failure.
111 */
112 if (targetType == UNKNOWNOID)
115 errmsg("subscript type %s is not supported", format_type_be(subExprType)),
116 errhint("jsonb subscript must be coercible to either integer or text."),
118 }
119 else
121
122 /*
123 * We known from can_coerce_type that coercion will succeed, so
124 * coerce_type could be used. Note the implicit coercion context,
125 * which is required to handle subscripts of different types,
126 * similar to overloaded functions.
127 */
128 subExpr = coerce_type(pstate,
130 targetType, -1,
133 -1);
134 if (subExpr == NULL)
137 errmsg("jsonb subscript must have text type"),
139 }
140 else
141 {
142 /*
143 * Slice with omitted upper bound. Should not happen as we already
144 * errored out on slice earlier, but handle this just in case.
145 */
146 Assert(isSlice && ai->is_slice);
149 errmsg("jsonb subscript does not support slices"),
150 parser_errposition(pstate, exprLocation(ai->uidx))));
151 }
152
154 }
155
156 /* store the transformed lists into the SubscriptingRef node */
158 sbsref->reflowerindexpr = NIL;
159
160 /* Determine the result type of the subscripting operation; always jsonb */
161 sbsref->refrestype = JSONBOID;
162 sbsref->reftypmod = -1;
163}
Datum idx(PG_FUNCTION_ARGS)
Definition _int_op.c:262
int errhint(const char *fmt,...) pg_attribute_printf(1
char * format_type_be(Oid type_oid)
List * lappend(List *list, void *datum)
Definition list.c:339
int exprLocation(const Node *expr)
Definition nodeFuncs.c:1392
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)
Definition parse_expr.c:121
int parser_errposition(ParseState *pstate, int location)
Definition parse_node.c:106
#define lfirst_node(type, lc)
Definition pg_list.h:176
#define NIL
Definition pg_list.h:68
#define InvalidOid
@ COERCE_IMPLICIT_CAST
Definition primnodes.h:769
@ COERCION_IMPLICIT
Definition primnodes.h:747
Definition pg_list.h:54
ParseExprKind p_expr_kind
Definition parse_node.h:228
List * reflowerindexpr
Definition primnodes.h:732

References Assert, can_coerce_type(), COERCE_IMPLICIT_CAST, coerce_type(), COERCION_IMPLICIT, ereport, errcode(), errhint(), errmsg, ERROR, exprLocation(), exprType(), fb(), format_type_be(), i, idx(), InvalidOid, lappend(), lfirst_node, NIL, ParseState::p_expr_kind, parser_errposition(), SubscriptingRef::reflowerindexpr, SubscriptingRef::refupperindexpr, and transformExpr().

Referenced by jsonb_subscript_handler().