Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * jsonb.c
4 : * I/O routines for jsonb type
5 : *
6 : * Copyright (c) 2014-2023, PostgreSQL Global Development Group
7 : *
8 : * IDENTIFICATION
9 : * src/backend/utils/adt/jsonb.c
10 : *
11 : *-------------------------------------------------------------------------
12 : */
13 : #include "postgres.h"
14 :
15 : #include "access/htup_details.h"
16 : #include "access/transam.h"
17 : #include "catalog/pg_proc.h"
18 : #include "catalog/pg_type.h"
19 : #include "funcapi.h"
20 : #include "libpq/pqformat.h"
21 : #include "miscadmin.h"
22 : #include "parser/parse_coerce.h"
23 : #include "utils/builtins.h"
24 : #include "utils/date.h"
25 : #include "utils/datetime.h"
26 : #include "utils/json.h"
27 : #include "utils/jsonb.h"
28 : #include "utils/jsonfuncs.h"
29 : #include "utils/lsyscache.h"
30 : #include "utils/syscache.h"
31 : #include "utils/typcache.h"
32 :
33 : typedef struct JsonbInState
34 : {
35 : JsonbParseState *parseState;
36 : JsonbValue *res;
37 : Node *escontext;
38 : } JsonbInState;
39 :
40 : /* unlike with json categories, we need to treat json and jsonb differently */
41 : typedef enum /* type categories for datum_to_jsonb */
42 : {
43 : JSONBTYPE_NULL, /* null, so we didn't bother to identify */
44 : JSONBTYPE_BOOL, /* boolean (built-in types only) */
45 : JSONBTYPE_NUMERIC, /* numeric (ditto) */
46 : JSONBTYPE_DATE, /* we use special formatting for datetimes */
47 : JSONBTYPE_TIMESTAMP, /* we use special formatting for timestamp */
48 : JSONBTYPE_TIMESTAMPTZ, /* ... and timestamptz */
49 : JSONBTYPE_JSON, /* JSON */
50 : JSONBTYPE_JSONB, /* JSONB */
51 : JSONBTYPE_ARRAY, /* array */
52 : JSONBTYPE_COMPOSITE, /* composite */
53 : JSONBTYPE_JSONCAST, /* something with an explicit cast to JSON */
54 : JSONBTYPE_OTHER /* all else */
55 : } JsonbTypeCategory;
56 :
57 : typedef struct JsonbAggState
58 : {
59 : JsonbInState *res;
60 : JsonbTypeCategory key_category;
61 : Oid key_output_func;
62 : JsonbTypeCategory val_category;
63 : Oid val_output_func;
64 : } JsonbAggState;
65 :
66 : static inline Datum jsonb_from_cstring(char *json, int len, Node *escontext);
67 : static bool checkStringLen(size_t len, Node *escontext);
68 : static JsonParseErrorType jsonb_in_object_start(void *pstate);
69 : static JsonParseErrorType jsonb_in_object_end(void *pstate);
70 : static JsonParseErrorType jsonb_in_array_start(void *pstate);
71 : static JsonParseErrorType jsonb_in_array_end(void *pstate);
72 : static JsonParseErrorType jsonb_in_object_field_start(void *pstate, char *fname, bool isnull);
73 : static void jsonb_put_escaped_value(StringInfo out, JsonbValue *scalarVal);
74 : static JsonParseErrorType jsonb_in_scalar(void *pstate, char *token, JsonTokenType tokentype);
75 : static void jsonb_categorize_type(Oid typoid,
76 : JsonbTypeCategory *tcategory,
77 : Oid *outfuncoid);
78 : static void composite_to_jsonb(Datum composite, JsonbInState *result);
79 : static void array_dim_to_jsonb(JsonbInState *result, int dim, int ndims, int *dims,
80 : Datum *vals, bool *nulls, int *valcount,
81 : JsonbTypeCategory tcategory, Oid outfuncoid);
82 : static void array_to_jsonb_internal(Datum array, JsonbInState *result);
83 : static void jsonb_categorize_type(Oid typoid,
84 : JsonbTypeCategory *tcategory,
85 : Oid *outfuncoid);
86 : static void datum_to_jsonb(Datum val, bool is_null, JsonbInState *result,
87 : JsonbTypeCategory tcategory, Oid outfuncoid,
88 : bool key_scalar);
89 : static void add_jsonb(Datum val, bool is_null, JsonbInState *result,
90 : Oid val_type, bool key_scalar);
91 : static JsonbParseState *clone_parse_state(JsonbParseState *state);
92 : static char *JsonbToCStringWorker(StringInfo out, JsonbContainer *in, int estimated_len, bool indent);
93 : static void add_indent(StringInfo out, bool indent, int level);
94 :
95 : /*
96 : * jsonb type input function
97 : */
98 : Datum
3304 andrew 99 GIC 10821 : jsonb_in(PG_FUNCTION_ARGS)
100 : {
3304 andrew 101 CBC 10821 : char *json = PG_GETARG_CSTRING(0);
102 :
119 tgl 103 GNC 10821 : return jsonb_from_cstring(json, strlen(json), fcinfo->context);
104 : }
3304 andrew 105 ECB :
106 : /*
107 : * jsonb type recv function
108 : *
109 : * The type is sent as text in binary mode, so this is almost the same
110 : * as the input function, but it's prefixed with a version number so we
111 : * can change the binary format sent in future if necessary. For now,
112 : * only version 1 is supported.
113 : */
114 : Datum
3304 andrew 115 UIC 0 : jsonb_recv(PG_FUNCTION_ARGS)
116 : {
3304 andrew 117 UBC 0 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
3304 andrew 118 UIC 0 : int version = pq_getmsgint(buf, 1);
3304 andrew 119 EUB : char *str;
120 : int nbytes;
121 :
3304 andrew 122 UIC 0 : if (version == 1)
123 0 : str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
3304 andrew 124 EUB : else
3259 heikki.linnakangas 125 UBC 0 : elog(ERROR, "unsupported jsonb version number %d", version);
126 :
119 tgl 127 UNC 0 : return jsonb_from_cstring(str, nbytes, NULL);
128 : }
3304 andrew 129 EUB :
130 : /*
131 : * jsonb type output function
132 : */
133 : Datum
3304 andrew 134 GIC 9383 : jsonb_out(PG_FUNCTION_ARGS)
135 : {
2029 tgl 136 CBC 9383 : Jsonb *jb = PG_GETARG_JSONB_P(0);
137 : char *out;
3304 andrew 138 ECB :
3259 heikki.linnakangas 139 GIC 9383 : out = JsonbToCString(NULL, &jb->root, VARSIZE(jb));
140 :
3304 andrew 141 CBC 9383 : PG_RETURN_CSTRING(out);
142 : }
3304 andrew 143 ECB :
144 : /*
145 : * jsonb type send function
146 : *
147 : * Just send jsonb as a version number, then a string of text
148 : */
149 : Datum
3304 andrew 150 UIC 0 : jsonb_send(PG_FUNCTION_ARGS)
151 : {
2029 tgl 152 UBC 0 : Jsonb *jb = PG_GETARG_JSONB_P(0);
153 : StringInfoData buf;
3304 andrew 154 0 : StringInfo jtext = makeStringInfo();
3304 andrew 155 UIC 0 : int version = 1;
3304 andrew 156 EUB :
3259 heikki.linnakangas 157 UBC 0 : (void) JsonbToCString(jtext, &jb->root, VARSIZE(jb));
158 :
3304 andrew 159 0 : pq_begintypsend(&buf);
2006 andres 160 UIC 0 : pq_sendint8(&buf, version);
3304 andrew 161 UBC 0 : pq_sendtext(&buf, jtext->data, jtext->len);
162 0 : pfree(jtext->data);
163 0 : pfree(jtext);
3304 andrew 164 EUB :
3304 andrew 165 UBC 0 : PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
166 : }
3304 andrew 167 EUB :
168 : /*
169 : * Get the type name of a jsonb container.
170 : */
171 : static const char *
1485 akorotkov 172 GIC 153 : JsonbContainerTypeName(JsonbContainer *jbc)
173 : {
1485 akorotkov 174 ECB : JsonbValue scalar;
175 :
1485 akorotkov 176 GIC 153 : if (JsonbExtractScalar(jbc, &scalar))
177 33 : return JsonbTypeName(&scalar);
1485 akorotkov 178 CBC 120 : else if (JsonContainerIsArray(jbc))
179 51 : return "array";
180 69 : else if (JsonContainerIsObject(jbc))
181 69 : return "object";
1485 akorotkov 182 ECB : else
183 : {
1485 akorotkov 184 UIC 0 : elog(ERROR, "invalid jsonb container type: 0x%08x", jbc->header);
185 : return "unknown";
1485 akorotkov 186 EUB : }
187 : }
188 :
189 : /*
190 : * Get the type name of a jsonb value.
191 : */
192 : const char *
201 pg 193 GNC 138 : JsonbTypeName(JsonbValue *val)
194 : {
195 138 : switch (val->type)
196 : {
1485 akorotkov 197 CBC 12 : case jbvBinary:
201 pg 198 GNC 12 : return JsonbContainerTypeName(val->val.binary.data);
1485 akorotkov 199 LBC 0 : case jbvObject:
200 0 : return "object";
1485 akorotkov 201 UBC 0 : case jbvArray:
202 0 : return "array";
1485 akorotkov 203 GBC 45 : case jbvNumeric:
204 45 : return "number";
1485 akorotkov 205 CBC 15 : case jbvString:
206 15 : return "string";
207 18 : case jbvBool:
208 18 : return "boolean";
209 12 : case jbvNull:
210 12 : return "null";
1292 211 36 : case jbvDatetime:
201 pg 212 GNC 36 : switch (val->val.datetime.typid)
1292 akorotkov 213 ECB : {
1292 akorotkov 214 CBC 6 : case DATEOID:
1292 akorotkov 215 GIC 6 : return "date";
1292 akorotkov 216 CBC 6 : case TIMEOID:
217 6 : return "time without time zone";
218 9 : case TIMETZOID:
219 9 : return "time with time zone";
220 6 : case TIMESTAMPOID:
221 6 : return "timestamp without time zone";
222 9 : case TIMESTAMPTZOID:
223 9 : return "timestamp with time zone";
1292 akorotkov 224 LBC 0 : default:
225 0 : elog(ERROR, "unrecognized jsonb value datetime type: %d",
226 : val->val.datetime.typid);
1292 akorotkov 227 EUB : }
228 : return "unknown";
1485 akorotkov 229 UIC 0 : default:
201 pg 230 UNC 0 : elog(ERROR, "unrecognized jsonb value type: %d", val->type);
1485 akorotkov 231 EUB : return "unknown";
232 : }
233 : }
234 :
235 : /*
236 : * SQL function jsonb_typeof(jsonb) -> text
237 : *
238 : * This function is here because the analog json function is in json.c, since
239 : * it uses the json parser internals not exposed elsewhere.
240 : */
241 : Datum
3304 andrew 242 GIC 141 : jsonb_typeof(PG_FUNCTION_ARGS)
243 : {
2029 tgl 244 CBC 141 : Jsonb *in = PG_GETARG_JSONB_P(0);
1485 akorotkov 245 GIC 141 : const char *result = JsonbContainerTypeName(&in->root);
3304 andrew 246 ECB :
3304 andrew 247 CBC 141 : PG_RETURN_TEXT_P(cstring_to_text(result));
248 : }
3304 andrew 249 ECB :
250 : /*
251 : * jsonb_from_cstring
252 : *
253 : * Turns json string into a jsonb Datum.
254 : *
255 : * Uses the json parser (with hooks) to construct a jsonb.
256 : *
257 : * If escontext points to an ErrorSaveContext, errors are reported there
258 : * instead of being thrown.
259 : */
260 : static inline Datum
119 tgl 261 GNC 10821 : jsonb_from_cstring(char *json, int len, Node *escontext)
262 : {
263 : JsonLexContext *lex;
264 : JsonbInState state;
265 : JsonSemAction sem;
3304 andrew 266 ECB :
3304 andrew 267 GIC 10821 : memset(&state, 0, sizeof(state));
268 10821 : memset(&sem, 0, sizeof(sem));
1166 rhaas 269 10821 : lex = makeJsonLexContextCstringLen(json, len, GetDatabaseEncoding(), true);
270 :
119 tgl 271 GNC 10821 : state.escontext = escontext;
3304 andrew 272 GIC 10821 : sem.semstate = (void *) &state;
3304 andrew 273 ECB :
3304 andrew 274 CBC 10821 : sem.object_start = jsonb_in_object_start;
275 10821 : sem.array_start = jsonb_in_array_start;
3304 andrew 276 GIC 10821 : sem.object_end = jsonb_in_object_end;
3304 andrew 277 CBC 10821 : sem.array_end = jsonb_in_array_end;
278 10821 : sem.scalar = jsonb_in_scalar;
3304 andrew 279 GIC 10821 : sem.object_field_start = jsonb_in_object_field_start;
3304 andrew 280 ECB :
119 tgl 281 GNC 10821 : if (!pg_parse_json_or_errsave(lex, &sem, escontext))
282 9 : return (Datum) 0;
3304 andrew 283 ECB :
284 : /* after parsing, the item member has the composed jsonb structure */
3304 andrew 285 CBC 10695 : PG_RETURN_POINTER(JsonbValueToJsonb(state.res));
3304 andrew 286 ECB : }
287 :
288 : static bool
119 tgl 289 GNC 35123 : checkStringLen(size_t len, Node *escontext)
290 : {
3114 tgl 291 GIC 35123 : if (len > JENTRY_OFFLENMASK)
119 tgl 292 UNC 0 : ereturn(escontext, false,
293 : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
294 : errmsg("string too long to represent as jsonb string"),
295 : errdetail("Due to an implementation restriction, jsonb strings cannot exceed %d bytes.",
3114 tgl 296 ECB : JENTRY_OFFLENMASK)));
297 :
119 tgl 298 GNC 35123 : return true;
3304 andrew 299 EUB : }
300 :
301 : static JsonParseErrorType
3304 andrew 302 GIC 12330 : jsonb_in_object_start(void *pstate)
303 : {
304 12330 : JsonbInState *_state = (JsonbInState *) pstate;
3304 andrew 305 ECB :
3304 andrew 306 GIC 12330 : _state->res = pushJsonbValue(&_state->parseState, WJB_BEGIN_OBJECT, NULL);
307 :
119 tgl 308 GNC 12330 : return JSON_SUCCESS;
309 : }
310 :
311 : static JsonParseErrorType
3304 andrew 312 GIC 10319 : jsonb_in_object_end(void *pstate)
3304 andrew 313 ECB : {
3304 andrew 314 GIC 10319 : JsonbInState *_state = (JsonbInState *) pstate;
3304 andrew 315 ECB :
3304 andrew 316 GIC 10319 : _state->res = pushJsonbValue(&_state->parseState, WJB_END_OBJECT, NULL);
317 :
119 tgl 318 GNC 10319 : return JSON_SUCCESS;
3304 andrew 319 ECB : }
320 :
321 : static JsonParseErrorType
3304 andrew 322 GIC 5185 : jsonb_in_array_start(void *pstate)
3304 andrew 323 ECB : {
3304 andrew 324 GIC 5185 : JsonbInState *_state = (JsonbInState *) pstate;
3304 andrew 325 ECB :
3304 andrew 326 GIC 5185 : _state->res = pushJsonbValue(&_state->parseState, WJB_BEGIN_ARRAY, NULL);
327 :
119 tgl 328 GNC 5185 : return JSON_SUCCESS;
3304 andrew 329 ECB : }
330 :
331 : static JsonParseErrorType
3304 andrew 332 GIC 2979 : jsonb_in_array_end(void *pstate)
333 : {
334 2979 : JsonbInState *_state = (JsonbInState *) pstate;
3304 andrew 335 ECB :
3304 andrew 336 GIC 2979 : _state->res = pushJsonbValue(&_state->parseState, WJB_END_ARRAY, NULL);
337 :
119 tgl 338 GNC 2979 : return JSON_SUCCESS;
3304 andrew 339 ECB : }
340 :
341 : static JsonParseErrorType
3304 andrew 342 GIC 23806 : jsonb_in_object_field_start(void *pstate, char *fname, bool isnull)
3304 andrew 343 ECB : {
3304 andrew 344 GIC 23806 : JsonbInState *_state = (JsonbInState *) pstate;
345 : JsonbValue v;
346 :
3260 bruce 347 CBC 23806 : Assert(fname != NULL);
3304 andrew 348 GIC 23806 : v.type = jbvString;
119 tgl 349 GNC 23806 : v.val.string.len = strlen(fname);
350 23806 : if (!checkStringLen(v.val.string.len, _state->escontext))
119 tgl 351 UNC 0 : return JSON_SEM_ACTION_FAILED;
3257 heikki.linnakangas 352 GIC 23806 : v.val.string.val = fname;
3304 andrew 353 ECB :
3304 andrew 354 GIC 23806 : _state->res = pushJsonbValue(&_state->parseState, WJB_KEY, &v);
355 :
119 tgl 356 GNC 23806 : return JSON_SUCCESS;
3304 andrew 357 ECB : }
358 :
359 : static void
3260 bruce 360 GIC 50532 : jsonb_put_escaped_value(StringInfo out, JsonbValue *scalarVal)
3304 andrew 361 ECB : {
3304 andrew 362 GIC 50532 : switch (scalarVal->type)
3304 andrew 363 ECB : {
3304 andrew 364 GIC 464 : case jbvNull:
365 464 : appendBinaryStringInfo(out, "null", 4);
3304 andrew 366 CBC 464 : break;
367 34323 : case jbvString:
3294 tgl 368 34323 : escape_json(out, pnstrdup(scalarVal->val.string.val, scalarVal->val.string.len));
3304 andrew 369 34323 : break;
3304 andrew 370 GBC 9645 : case jbvNumeric:
3304 andrew 371 CBC 9645 : appendStringInfoString(out,
2118 tgl 372 GIC 9645 : DatumGetCString(DirectFunctionCall1(numeric_out,
2118 tgl 373 ECB : PointerGetDatum(scalarVal->val.numeric))));
3304 andrew 374 GIC 9645 : break;
3304 andrew 375 CBC 6100 : case jbvBool:
3294 tgl 376 GIC 6100 : if (scalarVal->val.boolean)
3304 andrew 377 2876 : appendBinaryStringInfo(out, "true", 4);
378 : else
3304 andrew 379 CBC 3224 : appendBinaryStringInfo(out, "false", 5);
3304 andrew 380 GIC 6100 : break;
3304 andrew 381 LBC 0 : default:
3304 andrew 382 UIC 0 : elog(ERROR, "unknown jsonb scalar type");
3304 andrew 383 ECB : }
3304 andrew 384 CBC 50532 : }
3304 andrew 385 ECB :
386 : /*
387 : * For jsonb we always want the de-escaped value - that's what's in token
388 : */
389 : static JsonParseErrorType
3304 andrew 390 CBC 26289 : jsonb_in_scalar(void *pstate, char *token, JsonTokenType tokentype)
3304 andrew 391 ECB : {
3304 andrew 392 GIC 26289 : JsonbInState *_state = (JsonbInState *) pstate;
3304 andrew 393 ECB : JsonbValue v;
1803 tgl 394 : Datum numd;
3304 andrew 395 :
3304 andrew 396 CBC 26289 : switch (tokentype)
397 : {
3304 andrew 398 ECB :
3304 andrew 399 CBC 10822 : case JSON_TOKEN_STRING:
3260 bruce 400 GBC 10822 : Assert(token != NULL);
3304 andrew 401 10822 : v.type = jbvString;
119 tgl 402 GNC 10822 : v.val.string.len = strlen(token);
403 10822 : if (!checkStringLen(v.val.string.len, _state->escontext))
119 tgl 404 UNC 0 : return JSON_SEM_ACTION_FAILED;
3257 heikki.linnakangas 405 CBC 10822 : v.val.string.val = token;
3304 andrew 406 GIC 10822 : break;
407 11311 : case JSON_TOKEN_NUMBER:
408 :
409 : /*
410 : * No need to check size of numeric values, because maximum
3260 bruce 411 ECB : * numeric size is well below the JsonbValue restriction
412 : */
3260 bruce 413 CBC 11311 : Assert(token != NULL);
3304 andrew 414 GIC 11311 : v.type = jbvNumeric;
119 tgl 415 GNC 11311 : if (!DirectInputFunctionCallSafe(numeric_in, token,
416 : InvalidOid, -1,
417 11311 : _state->escontext,
418 : &numd))
419 3 : return JSON_SEM_ACTION_FAILED;
1803 tgl 420 GIC 11308 : v.val.numeric = DatumGetNumeric(numd);
3304 andrew 421 CBC 11308 : break;
422 1630 : case JSON_TOKEN_TRUE:
423 1630 : v.type = jbvBool;
3294 tgl 424 1630 : v.val.boolean = true;
3304 andrew 425 1630 : break;
3304 andrew 426 GBC 1616 : case JSON_TOKEN_FALSE:
3304 andrew 427 CBC 1616 : v.type = jbvBool;
3294 tgl 428 1616 : v.val.boolean = false;
3304 andrew 429 1616 : break;
3304 andrew 430 GIC 910 : case JSON_TOKEN_NULL:
431 910 : v.type = jbvNull;
432 910 : break;
3304 andrew 433 UIC 0 : default:
434 : /* should not be possible */
3304 andrew 435 LBC 0 : elog(ERROR, "invalid json token type");
3304 andrew 436 ECB : break;
437 : }
438 :
3304 andrew 439 CBC 26286 : if (_state->parseState == NULL)
440 : {
3304 andrew 441 ECB : /* single scalar */
442 : JsonbValue va;
443 :
3304 andrew 444 CBC 1139 : va.type = jbvArray;
3294 tgl 445 1139 : va.val.array.rawScalar = true;
446 1139 : va.val.array.nElems = 1;
3304 andrew 447 ECB :
3304 andrew 448 CBC 1139 : _state->res = pushJsonbValue(&_state->parseState, WJB_BEGIN_ARRAY, &va);
449 1139 : _state->res = pushJsonbValue(&_state->parseState, WJB_ELEM, &v);
450 1139 : _state->res = pushJsonbValue(&_state->parseState, WJB_END_ARRAY, NULL);
3304 andrew 451 ECB : }
452 : else
453 : {
3304 andrew 454 CBC 25147 : JsonbValue *o = &_state->parseState->contVal;
3304 andrew 455 EUB :
3304 andrew 456 GIC 25147 : switch (o->type)
3304 andrew 457 EUB : {
3304 andrew 458 GIC 5317 : case jbvArray:
459 5317 : _state->res = pushJsonbValue(&_state->parseState, WJB_ELEM, &v);
460 5317 : break;
3304 andrew 461 CBC 19830 : case jbvObject:
3304 andrew 462 GIC 19830 : _state->res = pushJsonbValue(&_state->parseState, WJB_VALUE, &v);
463 19830 : break;
3304 andrew 464 UIC 0 : default:
465 0 : elog(ERROR, "unexpected parent of nested structure");
3304 andrew 466 ECB : }
467 : }
468 :
119 tgl 469 GNC 26286 : return JSON_SUCCESS;
3304 andrew 470 ECB : }
471 :
472 : /*
473 : * JsonbToCString
474 : * Converts jsonb value to a C-string.
475 : *
476 : * If 'out' argument is non-null, the resulting C-string is stored inside the
477 : * StringBuffer. The resulting string is always returned.
478 : *
479 : * A typical case for passing the StringInfo in rather than NULL is where the
480 : * caller wants access to the len attribute without having to call strlen, e.g.
481 : * if they are converting it to a text* object.
482 : */
483 : char *
3259 heikki.linnakangas 484 CBC 9980 : JsonbToCString(StringInfo out, JsonbContainer *in, int estimated_len)
2889 andrew 485 ECB : {
2889 andrew 486 CBC 9980 : return JsonbToCStringWorker(out, in, estimated_len, false);
2889 andrew 487 ECB : }
2889 andrew 488 EUB :
489 : /*
490 : * same thing but with indentation turned on
491 : */
492 : char *
2889 andrew 493 CBC 18 : JsonbToCStringIndent(StringInfo out, JsonbContainer *in, int estimated_len)
494 : {
2889 andrew 495 GIC 18 : return JsonbToCStringWorker(out, in, estimated_len, true);
496 : }
497 :
498 : /*
499 : * common worker for above two functions
500 : */
501 : static char *
502 9998 : JsonbToCStringWorker(StringInfo out, JsonbContainer *in, int estimated_len, bool indent)
503 : {
3304 504 9998 : bool first = true;
505 : JsonbIterator *it;
506 : JsonbValue v;
2737 noah 507 9998 : JsonbIteratorToken type = WJB_DONE;
3304 andrew 508 CBC 9998 : int level = 0;
3304 andrew 509 GIC 9998 : bool redo_switch = false;
2878 bruce 510 ECB :
511 : /* If we are indenting, don't add a space after a comma */
2889 andrew 512 GIC 9998 : int ispaces = indent ? 1 : 2;
513 :
514 : /*
515 : * Don't indent the very first item. This gets set to the indent flag at
516 : * the bottom of the loop.
2889 andrew 517 ECB : */
2878 bruce 518 GIC 9998 : bool use_indent = false;
2878 bruce 519 CBC 9998 : bool raw_scalar = false;
2878 bruce 520 GIC 9998 : bool last_was_key = false;
521 :
3304 andrew 522 9998 : if (out == NULL)
523 9917 : out = makeStringInfo();
524 :
525 9998 : enlargeStringInfo(out, (estimated_len >= 0) ? estimated_len : 64);
3304 andrew 526 ECB :
3304 andrew 527 GIC 9998 : it = JsonbIteratorInit(in);
3304 andrew 528 ECB :
3304 andrew 529 GIC 122236 : while (redo_switch ||
530 60743 : ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE))
3304 andrew 531 ECB : {
3304 andrew 532 CBC 51495 : redo_switch = false;
533 51495 : switch (type)
534 : {
3304 andrew 535 GIC 5138 : case WJB_BEGIN_ARRAY:
3304 andrew 536 CBC 5138 : if (!first)
2889 andrew 537 GIC 54 : appendBinaryStringInfo(out, ", ", ispaces);
538 :
3294 tgl 539 5138 : if (!v.val.array.rawScalar)
540 : {
2889 andrew 541 1260 : add_indent(out, use_indent && !last_was_key, level);
2889 andrew 542 CBC 1260 : appendStringInfoCharMacro(out, '[');
2889 andrew 543 ECB : }
544 : else
2889 andrew 545 GIC 3878 : raw_scalar = true;
2889 andrew 546 ECB :
2889 andrew 547 CBC 5138 : first = true;
3304 andrew 548 GIC 5138 : level++;
3304 andrew 549 CBC 5138 : break;
3304 andrew 550 GIC 6276 : case WJB_BEGIN_OBJECT:
3304 andrew 551 CBC 6276 : if (!first)
2889 andrew 552 GIC 167 : appendBinaryStringInfo(out, ", ", ispaces);
2889 andrew 553 ECB :
2889 andrew 554 CBC 6276 : add_indent(out, use_indent && !last_was_key, level);
3304 andrew 555 GIC 6276 : appendStringInfoCharMacro(out, '{');
3304 andrew 556 ECB :
2889 andrew 557 CBC 6276 : first = true;
3304 andrew 558 GIC 6276 : level++;
3304 andrew 559 CBC 6276 : break;
560 22615 : case WJB_KEY:
561 22615 : if (!first)
2889 andrew 562 GIC 16882 : appendBinaryStringInfo(out, ", ", ispaces);
3304 andrew 563 CBC 22615 : first = true;
564 :
2889 565 22615 : add_indent(out, use_indent, level);
2889 andrew 566 ECB :
567 : /* json rules guarantee this is a string */
3304 andrew 568 GIC 22615 : jsonb_put_escaped_value(out, &v);
3304 andrew 569 CBC 22615 : appendBinaryStringInfo(out, ": ", 2);
570 :
571 22615 : type = JsonbIteratorNext(&it, &v, false);
572 22615 : if (type == WJB_VALUE)
3304 andrew 573 ECB : {
3304 andrew 574 CBC 21865 : first = false;
575 21865 : jsonb_put_escaped_value(out, &v);
3304 andrew 576 ECB : }
577 : else
578 : {
3304 andrew 579 CBC 750 : Assert(type == WJB_BEGIN_OBJECT || type == WJB_BEGIN_ARRAY);
580 :
3304 andrew 581 ECB : /*
582 : * We need to rerun the current switch() since we need to
583 : * output the object which we just got from the iterator
584 : * before calling the iterator again.
585 : */
3304 andrew 586 CBC 750 : redo_switch = true;
3304 andrew 587 ECB : }
3304 andrew 588 GIC 22615 : break;
3304 andrew 589 CBC 6052 : case WJB_ELEM:
3304 andrew 590 GIC 6052 : if (!first)
2889 591 1411 : appendBinaryStringInfo(out, ", ", ispaces);
2889 andrew 592 CBC 6052 : first = false;
3304 andrew 593 ECB :
2878 bruce 594 GIC 6052 : if (!raw_scalar)
2889 andrew 595 CBC 2174 : add_indent(out, use_indent, level);
3304 596 6052 : jsonb_put_escaped_value(out, &v);
3304 andrew 597 GIC 6052 : break;
3304 andrew 598 CBC 5138 : case WJB_END_ARRAY:
599 5138 : level--;
2878 bruce 600 GIC 5138 : if (!raw_scalar)
601 : {
2889 andrew 602 1260 : add_indent(out, use_indent, level);
2889 andrew 603 CBC 1260 : appendStringInfoCharMacro(out, ']');
604 : }
3304 andrew 605 GIC 5138 : first = false;
606 5138 : break;
607 6276 : case WJB_END_OBJECT:
608 6276 : level--;
2889 609 6276 : add_indent(out, use_indent, level);
3304 andrew 610 CBC 6276 : appendStringInfoCharMacro(out, '}');
3304 andrew 611 GIC 6276 : first = false;
3304 andrew 612 CBC 6276 : break;
3304 andrew 613 LBC 0 : default:
2963 alvherre 614 0 : elog(ERROR, "unknown jsonb iterator token type");
3304 andrew 615 ECB : }
2889 andrew 616 CBC 51495 : use_indent = indent;
2889 andrew 617 GIC 51495 : last_was_key = redo_switch;
3304 andrew 618 ECB : }
619 :
3304 andrew 620 CBC 9998 : Assert(level == 0);
3304 andrew 621 ECB :
3304 andrew 622 CBC 9998 : return out->data;
3304 andrew 623 ECB : }
3040 624 :
625 : static void
2889 andrew 626 CBC 39861 : add_indent(StringInfo out, bool indent, int level)
2889 andrew 627 ECB : {
2889 andrew 628 GIC 39861 : if (indent)
2889 andrew 629 ECB : {
2889 andrew 630 CBC 783 : appendStringInfoCharMacro(out, '\n');
79 drowley 631 GNC 783 : appendStringInfoSpaces(out, level * 4);
2889 andrew 632 ECB : }
2889 andrew 633 CBC 39861 : }
2889 andrew 634 EUB :
3040 635 :
636 : /*
3040 andrew 637 ECB : * Determine how we want to render values of a given type in datum_to_jsonb.
638 : *
639 : * Given the datatype OID, return its JsonbTypeCategory, as well as the type's
640 : * output function OID. If the returned category is JSONBTYPE_JSONCAST,
2877 tgl 641 : * we return the OID of the relevant cast function instead.
642 : */
220 andrew 643 : static void
3040 andrew 644 GIC 1148 : jsonb_categorize_type(Oid typoid,
645 : JsonbTypeCategory *tcategory,
646 : Oid *outfuncoid)
3040 andrew 647 ECB : {
648 : bool typisvarlena;
649 :
650 : /* Look through any domain */
3040 andrew 651 CBC 1148 : typoid = getBaseType(typoid);
3040 andrew 652 ECB :
3040 andrew 653 GIC 1148 : *outfuncoid = InvalidOid;
3040 andrew 654 ECB :
655 : /*
656 : * We need to get the output function for everything except date and
657 : * timestamp types, booleans, array and composite types, json and jsonb,
658 : * and non-builtin types where there's a cast to json. In this last case
659 : * we return the oid of the cast function instead.
660 : */
661 :
3040 andrew 662 GIC 1148 : switch (typoid)
663 : {
664 24 : case BOOLOID:
3040 andrew 665 CBC 24 : *tcategory = JSONBTYPE_BOOL;
3040 andrew 666 GIC 24 : break;
667 :
668 317 : case INT2OID:
669 : case INT4OID:
670 : case INT8OID:
671 : case FLOAT4OID:
3040 andrew 672 ECB : case FLOAT8OID:
673 : case NUMERICOID:
3040 andrew 674 CBC 317 : getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
3040 andrew 675 GIC 317 : *tcategory = JSONBTYPE_NUMERIC;
676 317 : break;
677 :
678 9 : case DATEOID:
679 9 : *tcategory = JSONBTYPE_DATE;
680 9 : break;
681 :
682 9 : case TIMESTAMPOID:
3040 andrew 683 CBC 9 : *tcategory = JSONBTYPE_TIMESTAMP;
3040 andrew 684 GIC 9 : break;
3040 andrew 685 ECB :
3040 andrew 686 CBC 12 : case TIMESTAMPTZOID:
687 12 : *tcategory = JSONBTYPE_TIMESTAMPTZ;
3040 andrew 688 GIC 12 : break;
3040 andrew 689 ECB :
3040 andrew 690 GIC 183 : case JSONBOID:
691 183 : *tcategory = JSONBTYPE_JSONB;
692 183 : break;
693 :
694 21 : case JSONOID:
3040 andrew 695 CBC 21 : *tcategory = JSONBTYPE_JSON;
696 21 : break;
3040 andrew 697 ECB :
3040 andrew 698 GIC 573 : default:
3040 andrew 699 ECB : /* Check for arrays and composites */
2237 andrew 700 CBC 573 : if (OidIsValid(get_element_type(typoid)) || typoid == ANYARRAYOID
1116 tgl 701 516 : || typoid == ANYCOMPATIBLEARRAYOID || typoid == RECORDARRAYOID)
3040 andrew 702 GIC 57 : *tcategory = JSONBTYPE_ARRAY;
2153 bruce 703 CBC 516 : else if (type_is_rowtype(typoid)) /* includes RECORDOID */
3040 andrew 704 36 : *tcategory = JSONBTYPE_COMPOSITE;
3040 andrew 705 ECB : else
706 : {
707 : /* It's probably the general case ... */
3040 andrew 708 CBC 480 : *tcategory = JSONBTYPE_OTHER;
3040 andrew 709 ECB :
710 : /*
2878 bruce 711 : * but first let's look for a cast to json (note: not to
712 : * jsonb) if it's not built-in.
3040 andrew 713 : */
3040 andrew 714 GIC 480 : if (typoid >= FirstNormalObjectId)
3040 andrew 715 ECB : {
2878 bruce 716 : Oid castfunc;
3040 andrew 717 : CoercionPathType ctype;
718 :
3040 andrew 719 LBC 0 : ctype = find_coercion_pathway(JSONOID, typoid,
720 : COERCION_EXPLICIT, &castfunc);
721 0 : if (ctype == COERCION_PATH_FUNC && OidIsValid(castfunc))
3040 andrew 722 ECB : {
3040 andrew 723 LBC 0 : *tcategory = JSONBTYPE_JSONCAST;
724 0 : *outfuncoid = castfunc;
3040 andrew 725 ECB : }
726 : else
727 : {
728 : /* not a cast type, so just get the usual output func */
3040 andrew 729 LBC 0 : getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
730 : }
731 : }
732 : else
733 : {
734 : /* any other builtin type */
3040 andrew 735 CBC 480 : getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
736 : }
3040 andrew 737 GIC 480 : break;
738 : }
739 : }
3040 andrew 740 GBC 1148 : }
741 :
3040 andrew 742 EUB : /*
743 : * Turn a Datum into jsonb, adding it to the result JsonbInState.
744 : *
745 : * tcategory and outfuncoid are from a previous call to json_categorize_type,
746 : * except that if is_null is true then they can be invalid.
747 : *
748 : * If key_scalar is true, the value is stored as a key, so insist
749 : * it's of an acceptable type, and force it to be a jbvString.
750 : *
751 : * Note: currently, we assume that result->escontext is NULL and errors
752 : * will be thrown.
753 : */
754 : static void
3040 andrew 755 GIC 1499 : datum_to_jsonb(Datum val, bool is_null, JsonbInState *result,
756 : JsonbTypeCategory tcategory, Oid outfuncoid,
757 : bool key_scalar)
758 : {
3040 andrew 759 ECB : char *outputstr;
760 : bool numeric_error;
761 : JsonbValue jb;
3040 andrew 762 GIC 1499 : bool scalar_jsonb = false;
763 :
2743 noah 764 CBC 1499 : check_stack_depth();
765 :
766 : /* Convert val to a JsonbValue in jb (in most cases) */
3040 andrew 767 GIC 1499 : if (is_null)
768 : {
2816 769 96 : Assert(!key_scalar);
3040 770 96 : jb.type = jbvNull;
771 : }
772 1403 : else if (key_scalar &&
773 397 : (tcategory == JSONBTYPE_ARRAY ||
774 394 : tcategory == JSONBTYPE_COMPOSITE ||
775 391 : tcategory == JSONBTYPE_JSON ||
776 391 : tcategory == JSONBTYPE_JSONB ||
777 : tcategory == JSONBTYPE_JSONCAST))
778 : {
3040 andrew 779 CBC 12 : ereport(ERROR,
780 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
781 : errmsg("key value must be scalar, not array, composite, or json")));
782 : }
783 : else
784 : {
3040 andrew 785 GIC 1391 : if (tcategory == JSONBTYPE_JSONCAST)
3040 andrew 786 LBC 0 : val = OidFunctionCall1(outfuncoid, val);
787 :
3040 andrew 788 CBC 1391 : switch (tcategory)
789 : {
3040 andrew 790 GIC 54 : case JSONBTYPE_ARRAY:
3040 andrew 791 CBC 54 : array_to_jsonb_internal(val, result);
3040 andrew 792 GIC 54 : break;
3040 andrew 793 CBC 96 : case JSONBTYPE_COMPOSITE:
794 96 : composite_to_jsonb(val, result);
3040 andrew 795 GIC 96 : break;
3040 andrew 796 CBC 24 : case JSONBTYPE_BOOL:
797 24 : if (key_scalar)
3040 andrew 798 ECB : {
3040 andrew 799 LBC 0 : outputstr = DatumGetBool(val) ? "true" : "false";
800 0 : jb.type = jbvString;
3040 andrew 801 UIC 0 : jb.val.string.len = strlen(outputstr);
802 0 : jb.val.string.val = outputstr;
3040 andrew 803 ECB : }
804 : else
805 : {
3040 andrew 806 GIC 24 : jb.type = jbvBool;
807 24 : jb.val.boolean = DatumGetBool(val);
808 : }
3040 andrew 809 CBC 24 : break;
3040 andrew 810 GBC 488 : case JSONBTYPE_NUMERIC:
3040 andrew 811 GIC 488 : outputstr = OidOutputFunctionCall(outfuncoid, val);
3040 andrew 812 CBC 488 : if (key_scalar)
813 : {
3040 andrew 814 ECB : /* always quote keys */
3040 andrew 815 CBC 106 : jb.type = jbvString;
816 106 : jb.val.string.len = strlen(outputstr);
817 106 : jb.val.string.val = outputstr;
3040 andrew 818 ECB : }
819 : else
820 : {
821 : /*
822 : * Make it numeric if it's a valid JSON number, otherwise
3040 andrew 823 EUB : * a string. Invalid numeric output will always have an
824 : * 'N' or 'n' in it (I think).
825 : */
3040 andrew 826 GBC 764 : numeric_error = (strchr(outputstr, 'N') != NULL ||
3040 andrew 827 GIC 382 : strchr(outputstr, 'n') != NULL);
828 382 : if (!numeric_error)
829 : {
1803 tgl 830 ECB : Datum numd;
3040 andrew 831 :
1803 tgl 832 GIC 382 : jb.type = jbvNumeric;
1803 tgl 833 CBC 382 : numd = DirectFunctionCall3(numeric_in,
1803 tgl 834 ECB : CStringGetDatum(outputstr),
835 : ObjectIdGetDatum(InvalidOid),
836 : Int32GetDatum(-1));
1803 tgl 837 GIC 382 : jb.val.numeric = DatumGetNumeric(numd);
3040 andrew 838 382 : pfree(outputstr);
3040 andrew 839 ECB : }
840 : else
841 : {
3040 andrew 842 UIC 0 : jb.type = jbvString;
843 0 : jb.val.string.len = strlen(outputstr);
844 0 : jb.val.string.val = outputstr;
845 : }
846 : }
3040 andrew 847 GIC 488 : break;
2878 bruce 848 9 : case JSONBTYPE_DATE:
1909 andrew 849 9 : jb.type = jbvString;
1292 akorotkov 850 CBC 9 : jb.val.string.val = JsonEncodeDateTime(NULL, val,
1292 akorotkov 851 ECB : DATEOID, NULL);
1909 andrew 852 CBC 9 : jb.val.string.len = strlen(jb.val.string.val);
2878 bruce 853 GIC 9 : break;
3040 andrew 854 9 : case JSONBTYPE_TIMESTAMP:
1909 855 9 : jb.type = jbvString;
1292 akorotkov 856 CBC 9 : jb.val.string.val = JsonEncodeDateTime(NULL, val,
1292 akorotkov 857 ECB : TIMESTAMPOID, NULL);
1909 andrew 858 GIC 9 : jb.val.string.len = strlen(jb.val.string.val);
3040 859 9 : break;
860 12 : case JSONBTYPE_TIMESTAMPTZ:
1909 andrew 861 CBC 12 : jb.type = jbvString;
1292 akorotkov 862 12 : jb.val.string.val = JsonEncodeDateTime(NULL, val,
863 : TIMESTAMPTZOID, NULL);
1909 andrew 864 GIC 12 : jb.val.string.len = strlen(jb.val.string.val);
3040 865 12 : break;
3040 andrew 866 GBC 18 : case JSONBTYPE_JSONCAST:
3040 andrew 867 EUB : case JSONBTYPE_JSON:
868 : {
869 : /* parse the json right into the existing result object */
870 : JsonLexContext *lex;
3040 andrew 871 ECB : JsonSemAction sem;
2219 noah 872 CBC 18 : text *json = DatumGetTextPP(val);
3040 andrew 873 ECB :
3040 andrew 874 CBC 18 : lex = makeJsonLexContext(json, true);
875 :
876 18 : memset(&sem, 0, sizeof(sem));
3040 andrew 877 ECB :
3040 andrew 878 CBC 18 : sem.semstate = (void *) result;
3040 andrew 879 ECB :
3040 andrew 880 CBC 18 : sem.object_start = jsonb_in_object_start;
3040 andrew 881 GIC 18 : sem.array_start = jsonb_in_array_start;
3040 andrew 882 CBC 18 : sem.object_end = jsonb_in_object_end;
883 18 : sem.array_end = jsonb_in_array_end;
884 18 : sem.scalar = jsonb_in_scalar;
885 18 : sem.object_field_start = jsonb_in_object_field_start;
3040 andrew 886 ECB :
1168 rhaas 887 GIC 18 : pg_parse_json_or_ereport(lex, &sem);
3040 andrew 888 ECB : }
3040 andrew 889 CBC 18 : break;
890 186 : case JSONBTYPE_JSONB:
891 : {
2029 tgl 892 GIC 186 : Jsonb *jsonb = DatumGetJsonbP(val);
893 : JsonbIterator *it;
894 :
3040 andrew 895 186 : it = JsonbIteratorInit(&jsonb->root);
3040 andrew 896 ECB :
3040 andrew 897 GIC 186 : if (JB_ROOT_IS_SCALAR(jsonb))
3040 andrew 898 ECB : {
3040 andrew 899 GIC 108 : (void) JsonbIteratorNext(&it, &jb, true);
3040 andrew 900 CBC 108 : Assert(jb.type == jbvArray);
3040 andrew 901 GIC 108 : (void) JsonbIteratorNext(&it, &jb, true);
3040 andrew 902 CBC 108 : scalar_jsonb = true;
903 : }
3040 andrew 904 ECB : else
905 : {
2737 noah 906 : JsonbIteratorToken type;
907 :
3040 andrew 908 CBC 3630 : while ((type = JsonbIteratorNext(&it, &jb, false))
909 3630 : != WJB_DONE)
910 : {
911 3552 : if (type == WJB_END_ARRAY || type == WJB_END_OBJECT ||
3040 andrew 912 GIC 2853 : type == WJB_BEGIN_ARRAY || type == WJB_BEGIN_OBJECT)
3040 andrew 913 CBC 930 : result->res = pushJsonbValue(&result->parseState,
3040 andrew 914 ECB : type, NULL);
915 : else
3040 andrew 916 CBC 2622 : result->res = pushJsonbValue(&result->parseState,
917 : type, &jb);
918 : }
3040 andrew 919 ECB : }
920 : }
3040 andrew 921 CBC 186 : break;
3040 andrew 922 GIC 495 : default:
3040 andrew 923 CBC 495 : outputstr = OidOutputFunctionCall(outfuncoid, val);
924 495 : jb.type = jbvString;
119 tgl 925 GNC 495 : jb.val.string.len = strlen(outputstr);
926 495 : (void) checkStringLen(jb.val.string.len, NULL);
3040 andrew 927 CBC 495 : jb.val.string.val = outputstr;
3040 andrew 928 GIC 495 : break;
929 : }
930 : }
931 :
932 : /* Now insert jb into result, unless we did it recursively */
2733 tgl 933 CBC 1487 : if (!is_null && !scalar_jsonb &&
934 741 : tcategory >= JSONBTYPE_JSON && tcategory <= JSONBTYPE_JSONCAST)
935 : {
3040 andrew 936 ECB : /* work has been done recursively */
3040 andrew 937 CBC 246 : return;
3040 andrew 938 ECB : }
3040 andrew 939 GIC 1241 : else if (result->parseState == NULL)
940 : {
3040 andrew 941 ECB : /* single root scalar */
942 : JsonbValue va;
943 :
3040 andrew 944 GIC 255 : va.type = jbvArray;
945 255 : va.val.array.rawScalar = true;
3040 andrew 946 CBC 255 : va.val.array.nElems = 1;
3040 andrew 947 ECB :
3040 andrew 948 CBC 255 : result->res = pushJsonbValue(&result->parseState, WJB_BEGIN_ARRAY, &va);
949 255 : result->res = pushJsonbValue(&result->parseState, WJB_ELEM, &jb);
950 255 : result->res = pushJsonbValue(&result->parseState, WJB_END_ARRAY, NULL);
3040 andrew 951 ECB : }
952 : else
953 : {
3040 andrew 954 GIC 986 : JsonbValue *o = &result->parseState->contVal;
955 :
956 986 : switch (o->type)
957 : {
3040 andrew 958 CBC 237 : case jbvArray:
959 237 : result->res = pushJsonbValue(&result->parseState, WJB_ELEM, &jb);
3040 andrew 960 GIC 237 : break;
961 749 : case jbvObject:
3040 andrew 962 CBC 749 : result->res = pushJsonbValue(&result->parseState,
963 : key_scalar ? WJB_KEY : WJB_VALUE,
3040 andrew 964 ECB : &jb);
3040 andrew 965 GIC 749 : break;
3040 andrew 966 UIC 0 : default:
967 0 : elog(ERROR, "unexpected parent of nested structure");
968 : }
3040 andrew 969 ECB : }
970 : }
971 :
972 : /*
973 : * Process a single dimension of an array.
974 : * If it's the innermost dimension, output the values, otherwise call
975 : * ourselves recursively to process the next dimension.
976 : */
977 : static void
3040 andrew 978 GIC 54 : array_dim_to_jsonb(JsonbInState *result, int dim, int ndims, int *dims, Datum *vals,
3040 andrew 979 ECB : bool *nulls, int *valcount, JsonbTypeCategory tcategory,
980 : Oid outfuncoid)
981 : {
982 : int i;
983 :
3040 andrew 984 CBC 54 : Assert(dim < ndims);
3040 andrew 985 ECB :
3040 andrew 986 CBC 54 : result->res = pushJsonbValue(&result->parseState, WJB_BEGIN_ARRAY, NULL);
3040 andrew 987 ECB :
3040 andrew 988 GIC 198 : for (i = 1; i <= dims[dim]; i++)
989 : {
3040 andrew 990 CBC 144 : if (dim + 1 == ndims)
3040 andrew 991 EUB : {
3040 andrew 992 GBC 144 : datum_to_jsonb(vals[*valcount], nulls[*valcount], result, tcategory,
993 : outfuncoid, false);
3040 andrew 994 GIC 144 : (*valcount)++;
995 : }
996 : else
997 : {
3040 andrew 998 UIC 0 : array_dim_to_jsonb(result, dim + 1, ndims, dims, vals, nulls,
999 : valcount, tcategory, outfuncoid);
1000 : }
1001 : }
1002 :
3040 andrew 1003 CBC 54 : result->res = pushJsonbValue(&result->parseState, WJB_END_ARRAY, NULL);
3040 andrew 1004 GIC 54 : }
1005 :
1006 : /*
1007 : * Turn an array into JSON.
1008 : */
3040 andrew 1009 ECB : static void
3040 andrew 1010 GIC 54 : array_to_jsonb_internal(Datum array, JsonbInState *result)
3040 andrew 1011 ECB : {
3040 andrew 1012 GIC 54 : ArrayType *v = DatumGetArrayTypeP(array);
3040 andrew 1013 CBC 54 : Oid element_type = ARR_ELEMTYPE(v);
1014 : int *dim;
3040 andrew 1015 ECB : int ndim;
1016 : int nitems;
3040 andrew 1017 CBC 54 : int count = 0;
1018 : Datum *elements;
3040 andrew 1019 ECB : bool *nulls;
1020 : int16 typlen;
1021 : bool typbyval;
1022 : char typalign;
3040 andrew 1023 EUB : JsonbTypeCategory tcategory;
1024 : Oid outfuncoid;
1025 :
3040 andrew 1026 GIC 54 : ndim = ARR_NDIM(v);
1027 54 : dim = ARR_DIMS(v);
3040 andrew 1028 CBC 54 : nitems = ArrayGetNItems(ndim, dim);
3040 andrew 1029 ECB :
3040 andrew 1030 GIC 54 : if (nitems <= 0)
1031 : {
3040 andrew 1032 UIC 0 : result->res = pushJsonbValue(&result->parseState, WJB_BEGIN_ARRAY, NULL);
1033 0 : result->res = pushJsonbValue(&result->parseState, WJB_END_ARRAY, NULL);
1034 0 : return;
3040 andrew 1035 ECB : }
1036 :
3040 andrew 1037 CBC 54 : get_typlenbyvalalign(element_type,
3040 andrew 1038 ECB : &typlen, &typbyval, &typalign);
1039 :
3040 andrew 1040 GIC 54 : jsonb_categorize_type(element_type,
1041 : &tcategory, &outfuncoid);
3040 andrew 1042 ECB :
3040 andrew 1043 GIC 54 : deconstruct_array(v, element_type, typlen, typbyval,
1044 : typalign, &elements, &nulls,
1045 : &nitems);
1046 :
1047 54 : array_dim_to_jsonb(result, 0, ndim, dim, elements, nulls, &count, tcategory,
1048 : outfuncoid);
1049 :
1050 54 : pfree(elements);
3040 andrew 1051 CBC 54 : pfree(nulls);
3040 andrew 1052 ECB : }
1053 :
1054 : /*
1055 : * Turn a composite / record into JSON.
1056 : */
3040 andrew 1057 EUB : static void
3040 andrew 1058 GBC 96 : composite_to_jsonb(Datum composite, JsonbInState *result)
3040 andrew 1059 EUB : {
1060 : HeapTupleHeader td;
1061 : Oid tupType;
3040 andrew 1062 ECB : int32 tupTypmod;
1063 : TupleDesc tupdesc;
1064 : HeapTupleData tmptup,
1065 : *tuple;
1066 : int i;
1067 :
3040 andrew 1068 CBC 96 : td = DatumGetHeapTupleHeader(composite);
1069 :
1070 : /* Extract rowtype info and find a tupdesc */
3040 andrew 1071 GIC 96 : tupType = HeapTupleHeaderGetTypeId(td);
3040 andrew 1072 CBC 96 : tupTypmod = HeapTupleHeaderGetTypMod(td);
3040 andrew 1073 GIC 96 : tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
1074 :
3040 andrew 1075 ECB : /* Build a temporary HeapTuple control structure */
3040 andrew 1076 CBC 96 : tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
3040 andrew 1077 GIC 96 : tmptup.t_data = td;
1078 96 : tuple = &tmptup;
1079 :
1080 96 : result->res = pushJsonbValue(&result->parseState, WJB_BEGIN_OBJECT, NULL);
1081 :
1082 294 : for (i = 0; i < tupdesc->natts; i++)
3040 andrew 1083 ECB : {
1084 : Datum val;
1085 : bool isnull;
1086 : char *attname;
1087 : JsonbTypeCategory tcategory;
1088 : Oid outfuncoid;
1089 : JsonbValue v;
2058 andres 1090 GIC 198 : Form_pg_attribute att = TupleDescAttr(tupdesc, i);
1091 :
1092 198 : if (att->attisdropped)
3040 andrew 1093 LBC 0 : continue;
1094 :
2058 andres 1095 GIC 198 : attname = NameStr(att->attname);
3040 andrew 1096 ECB :
3040 andrew 1097 CBC 198 : v.type = jbvString;
3040 andrew 1098 ECB : /* don't need checkStringLen here - can't exceed maximum name length */
3040 andrew 1099 GIC 198 : v.val.string.len = strlen(attname);
1100 198 : v.val.string.val = attname;
3040 andrew 1101 ECB :
3040 andrew 1102 CBC 198 : result->res = pushJsonbValue(&result->parseState, WJB_KEY, &v);
3040 andrew 1103 ECB :
3040 andrew 1104 GIC 198 : val = heap_getattr(tuple, i + 1, tupdesc, &isnull);
3040 andrew 1105 ECB :
3040 andrew 1106 GIC 198 : if (isnull)
3040 andrew 1107 ECB : {
3040 andrew 1108 GIC 15 : tcategory = JSONBTYPE_NULL;
1109 15 : outfuncoid = InvalidOid;
1110 : }
1111 : else
2058 andres 1112 183 : jsonb_categorize_type(att->atttypid, &tcategory, &outfuncoid);
1113 :
3040 andrew 1114 198 : datum_to_jsonb(val, isnull, result, tcategory, outfuncoid, false);
3040 andrew 1115 ECB : }
1116 :
3040 andrew 1117 CBC 96 : result->res = pushJsonbValue(&result->parseState, WJB_END_OBJECT, NULL);
3040 andrew 1118 GBC 96 : ReleaseTupleDesc(tupdesc);
3040 andrew 1119 GIC 96 : }
3040 andrew 1120 ECB :
1121 : /*
1122 : * Append JSON text for "val" to "result".
1123 : *
1124 : * This is just a thin wrapper around datum_to_jsonb. If the same type will be
1125 : * printed many times, avoid using this; better to do the jsonb_categorize_type
1126 : * lookups only once.
1127 : */
1128 :
1129 : static void
3040 andrew 1130 GIC 809 : add_jsonb(Datum val, bool is_null, JsonbInState *result,
3040 andrew 1131 ECB : Oid val_type, bool key_scalar)
1132 : {
1133 : JsonbTypeCategory tcategory;
1134 : Oid outfuncoid;
1135 :
3040 andrew 1136 GIC 809 : if (val_type == InvalidOid)
3040 andrew 1137 LBC 0 : ereport(ERROR,
1138 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3040 andrew 1139 ECB : errmsg("could not determine input data type")));
1140 :
3040 andrew 1141 GIC 809 : if (is_null)
3040 andrew 1142 ECB : {
3040 andrew 1143 CBC 39 : tcategory = JSONBTYPE_NULL;
1144 39 : outfuncoid = InvalidOid;
1145 : }
1146 : else
3040 andrew 1147 GIC 770 : jsonb_categorize_type(val_type,
1148 : &tcategory, &outfuncoid);
1149 :
1150 809 : datum_to_jsonb(val, is_null, result, tcategory, outfuncoid, key_scalar);
1151 797 : }
1152 :
1153 : /*
1154 : * Is the given type immutable when coming out of a JSONB context?
1155 : *
1156 : * At present, datetimes are all considered mutable, because they
1157 : * depend on timezone. XXX we should also drill down into objects and
1158 : * arrays, but do not.
1159 : */
1160 : bool
11 alvherre 1161 UNC 0 : to_jsonb_is_immutable(Oid typoid)
1162 : {
1163 : JsonbTypeCategory tcategory;
1164 : Oid outfuncoid;
1165 :
1166 0 : jsonb_categorize_type(typoid, &tcategory, &outfuncoid);
1167 :
1168 0 : switch (tcategory)
1169 : {
1170 0 : case JSONBTYPE_NULL:
1171 : case JSONBTYPE_BOOL:
1172 : case JSONBTYPE_JSON:
1173 : case JSONBTYPE_JSONB:
1174 0 : return true;
1175 :
1176 0 : case JSONBTYPE_DATE:
1177 : case JSONBTYPE_TIMESTAMP:
1178 : case JSONBTYPE_TIMESTAMPTZ:
1179 0 : return false;
1180 :
1181 0 : case JSONBTYPE_ARRAY:
1182 0 : return false; /* TODO recurse into elements */
1183 :
1184 0 : case JSONBTYPE_COMPOSITE:
1185 0 : return false; /* TODO recurse into fields */
1186 :
1187 0 : case JSONBTYPE_NUMERIC:
1188 : case JSONBTYPE_JSONCAST:
1189 : case JSONBTYPE_OTHER:
1190 0 : return func_volatile(outfuncoid) == PROVOLATILE_IMMUTABLE;
1191 : }
1192 :
1193 0 : return false; /* not reached */
1194 : }
1195 :
1196 : /*
1197 : * SQL function to_jsonb(anyvalue)
3040 andrew 1198 ECB : */
1199 : Datum
3040 andrew 1200 GIC 42 : to_jsonb(PG_FUNCTION_ARGS)
1201 : {
1202 42 : Datum val = PG_GETARG_DATUM(0);
1203 42 : Oid val_type = get_fn_expr_argtype(fcinfo->flinfo, 0);
220 andrew 1204 ECB : JsonbInState result;
3040 andrew 1205 EUB : JsonbTypeCategory tcategory;
1206 : Oid outfuncoid;
1207 :
3040 andrew 1208 GIC 42 : if (val_type == InvalidOid)
3040 andrew 1209 LBC 0 : ereport(ERROR,
1210 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3040 andrew 1211 ECB : errmsg("could not determine input data type")));
1212 :
3040 andrew 1213 GIC 42 : jsonb_categorize_type(val_type,
1214 : &tcategory, &outfuncoid);
3040 andrew 1215 ECB :
220 andrew 1216 GIC 42 : memset(&result, 0, sizeof(JsonbInState));
1217 :
220 andrew 1218 CBC 42 : datum_to_jsonb(val, false, &result, tcategory, outfuncoid, false);
220 andrew 1219 ECB :
220 andrew 1220 GIC 42 : PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
1221 : }
1222 :
1223 : Datum
11 alvherre 1224 GNC 199 : jsonb_build_object_worker(int nargs, Datum *args, bool *nulls, Oid *types,
1225 : bool absent_on_null, bool unique_keys)
1226 : {
1227 : int i;
1228 : JsonbInState result;
1229 :
3040 andrew 1230 GBC 199 : if (nargs % 2 != 0)
3040 andrew 1231 GIC 9 : ereport(ERROR,
3040 andrew 1232 EUB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1233 : errmsg("argument list must have even number of elements"),
1234 : /* translator: %s is a SQL function name */
1446 alvherre 1235 : errhint("The arguments of %s must consist of alternating keys and values.",
1236 : "jsonb_build_object()")));
3040 andrew 1237 :
3040 andrew 1238 GBC 190 : memset(&result, 0, sizeof(JsonbInState));
1239 :
1240 190 : result.res = pushJsonbValue(&result.parseState, WJB_BEGIN_OBJECT, NULL);
11 alvherre 1241 GNC 190 : result.parseState->unique_keys = unique_keys;
1242 190 : result.parseState->skip_nulls = absent_on_null;
3040 andrew 1243 EUB :
3040 andrew 1244 GIC 504 : for (i = 0; i < nargs; i += 2)
3040 andrew 1245 EUB : {
1246 : /* process key */
1247 : bool skip;
1248 :
1992 andrew 1249 GIC 335 : if (nulls[i])
3040 andrew 1250 GBC 9 : ereport(ERROR,
1251 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1252 : errmsg("argument %d: key must not be null", i + 1)));
3040 andrew 1253 EUB :
1254 : /* skip null values if absent_on_null */
11 alvherre 1255 GNC 326 : skip = absent_on_null && nulls[i + 1];
1256 :
1257 : /* we need to save skipped keys for the key uniqueness check */
1258 326 : if (skip && !unique_keys)
1259 4 : continue;
1260 :
1992 andrew 1261 GIC 322 : add_jsonb(args[i], false, &result, types[i], true);
1262 :
1263 : /* process value */
1264 310 : add_jsonb(args[i + 1], nulls[i + 1], &result, types[i + 1], false);
1265 : }
1266 :
3040 andrew 1267 CBC 169 : result.res = pushJsonbValue(&result.parseState, WJB_END_OBJECT, NULL);
1268 :
11 alvherre 1269 GNC 160 : return JsonbPGetDatum(JsonbValueToJsonb(result.res));
1270 : }
1271 :
1272 : /*
1273 : * SQL function jsonb_build_object(variadic "any")
1274 : */
1275 : Datum
1276 168 : jsonb_build_object(PG_FUNCTION_ARGS)
1277 : {
1278 : Datum *args;
1279 : bool *nulls;
1280 : Oid *types;
1281 :
1282 : /* build argument values to build the object */
1283 168 : int nargs = extract_variadic_args(fcinfo, 0, true,
1284 : &args, &types, &nulls);
1285 :
1286 168 : if (nargs < 0)
1287 3 : PG_RETURN_NULL();
1288 :
1289 165 : PG_RETURN_DATUM(jsonb_build_object_worker(nargs, args, nulls, types, false, false));
3040 andrew 1290 ECB : }
1291 :
1292 : /*
1293 : * degenerate case of jsonb_build_object where it gets 0 arguments.
1294 : */
1295 : Datum
3040 andrew 1296 GBC 3 : jsonb_build_object_noargs(PG_FUNCTION_ARGS)
1297 : {
1298 : JsonbInState result;
1299 :
3040 andrew 1300 CBC 3 : memset(&result, 0, sizeof(JsonbInState));
1301 :
3036 andrew 1302 GIC 3 : (void) pushJsonbValue(&result.parseState, WJB_BEGIN_OBJECT, NULL);
3040 andrew 1303 CBC 3 : result.res = pushJsonbValue(&result.parseState, WJB_END_OBJECT, NULL);
1304 :
1305 3 : PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
1306 : }
3040 andrew 1307 ECB :
402 1308 : Datum
11 alvherre 1309 GNC 88 : jsonb_build_array_worker(int nargs, Datum *args, bool *nulls, Oid *types,
1310 : bool absent_on_null)
1311 : {
1312 : int i;
1313 : JsonbInState result;
1314 :
220 andrew 1315 CBC 88 : memset(&result, 0, sizeof(JsonbInState));
220 andrew 1316 ECB :
220 andrew 1317 CBC 88 : result.res = pushJsonbValue(&result.parseState, WJB_BEGIN_ARRAY, NULL);
1318 :
1319 277 : for (i = 0; i < nargs; i++)
1320 : {
11 alvherre 1321 GNC 189 : if (absent_on_null && nulls[i])
1322 12 : continue;
1323 :
220 andrew 1324 GIC 177 : add_jsonb(args[i], nulls[i], &result, types[i], false);
1325 : }
1326 :
1327 88 : result.res = pushJsonbValue(&result.parseState, WJB_END_ARRAY, NULL);
1328 :
11 alvherre 1329 GNC 88 : return JsonbPGetDatum(JsonbValueToJsonb(result.res));
11 alvherre 1330 ECB : }
1331 :
1332 : /*
1333 : * SQL function jsonb_build_array(variadic "any")
1334 : */
1335 : Datum
11 alvherre 1336 GNC 75 : jsonb_build_array(PG_FUNCTION_ARGS)
1337 : {
1338 : Datum *args;
1339 : bool *nulls;
1340 : Oid *types;
1341 :
1342 : /* build argument values to build the object */
1343 75 : int nargs = extract_variadic_args(fcinfo, 0, true,
1344 : &args, &types, &nulls);
1345 :
1346 75 : if (nargs < 0)
1347 3 : PG_RETURN_NULL();
1348 :
1349 72 : PG_RETURN_DATUM(jsonb_build_array_worker(nargs, args, nulls, types, false));
1350 : }
1351 :
1352 :
1353 : /*
1354 : * degenerate case of jsonb_build_array where it gets 0 arguments.
1355 : */
3040 andrew 1356 ECB : Datum
3040 andrew 1357 GIC 3 : jsonb_build_array_noargs(PG_FUNCTION_ARGS)
1358 : {
3040 andrew 1359 ECB : JsonbInState result;
1360 :
3040 andrew 1361 GIC 3 : memset(&result, 0, sizeof(JsonbInState));
3040 andrew 1362 ECB :
3036 andrew 1363 GIC 3 : (void) pushJsonbValue(&result.parseState, WJB_BEGIN_ARRAY, NULL);
3040 1364 3 : result.res = pushJsonbValue(&result.parseState, WJB_END_ARRAY, NULL);
3040 andrew 1365 ECB :
3040 andrew 1366 GIC 3 : PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
1367 : }
3040 andrew 1368 ECB :
1369 :
1370 : /*
1371 : * SQL function jsonb_object(text[])
1372 : *
1373 : * take a one or two dimensional array of text as name value pairs
1374 : * for a jsonb object.
1375 : *
1376 : */
1377 : Datum
3040 andrew 1378 GIC 21 : jsonb_object(PG_FUNCTION_ARGS)
1379 : {
1380 21 : ArrayType *in_array = PG_GETARG_ARRAYTYPE_P(0);
1381 21 : int ndims = ARR_NDIM(in_array);
1382 : Datum *in_datums;
1383 : bool *in_nulls;
3040 andrew 1384 ECB : int in_count,
1385 : count,
1386 : i;
1387 : JsonbInState result;
1388 :
3040 andrew 1389 GIC 21 : memset(&result, 0, sizeof(JsonbInState));
3040 andrew 1390 ECB :
3036 andrew 1391 GIC 21 : (void) pushJsonbValue(&result.parseState, WJB_BEGIN_OBJECT, NULL);
1392 :
3040 1393 21 : switch (ndims)
1394 : {
1395 3 : case 0:
1396 3 : goto close_object;
3040 andrew 1397 ECB : break;
1398 :
3040 andrew 1399 GIC 6 : case 1:
1400 6 : if ((ARR_DIMS(in_array)[0]) % 2)
3040 andrew 1401 CBC 3 : ereport(ERROR,
1402 : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
3040 andrew 1403 ECB : errmsg("array must have even number of elements")));
3040 andrew 1404 CBC 3 : break;
1405 :
1406 9 : case 2:
3040 andrew 1407 GIC 9 : if ((ARR_DIMS(in_array)[1]) != 2)
1408 6 : ereport(ERROR,
1409 : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
3040 andrew 1410 ECB : errmsg("array must have two columns")));
3040 andrew 1411 GIC 3 : break;
1412 :
1413 3 : default:
1414 3 : ereport(ERROR,
1415 : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
3040 andrew 1416 ECB : errmsg("wrong number of array subscripts")));
1417 : }
1418 :
282 peter 1419 GNC 6 : deconstruct_array_builtin(in_array, TEXTOID, &in_datums, &in_nulls, &in_count);
3040 andrew 1420 ECB :
3040 andrew 1421 CBC 6 : count = in_count / 2;
1422 :
1423 30 : for (i = 0; i < count; ++i)
1424 : {
1425 : JsonbValue v;
3040 andrew 1426 ECB : char *str;
1427 : int len;
1428 :
3040 andrew 1429 GIC 24 : if (in_nulls[i * 2])
3040 andrew 1430 UIC 0 : ereport(ERROR,
1431 : (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
1432 : errmsg("null value not allowed for object key")));
1433 :
3040 andrew 1434 GIC 24 : str = TextDatumGetCString(in_datums[i * 2]);
3040 andrew 1435 CBC 24 : len = strlen(str);
1436 :
3040 andrew 1437 GIC 24 : v.type = jbvString;
1438 :
1439 24 : v.val.string.len = len;
1440 24 : v.val.string.val = str;
1441 :
3036 andrew 1442 CBC 24 : (void) pushJsonbValue(&result.parseState, WJB_KEY, &v);
1443 :
3040 andrew 1444 GIC 24 : if (in_nulls[i * 2 + 1])
3040 andrew 1445 ECB : {
3040 andrew 1446 CBC 6 : v.type = jbvNull;
1447 : }
3040 andrew 1448 ECB : else
1449 : {
3040 andrew 1450 GIC 18 : str = TextDatumGetCString(in_datums[i * 2 + 1]);
1451 18 : len = strlen(str);
1452 :
1453 18 : v.type = jbvString;
1454 :
1455 18 : v.val.string.len = len;
3040 andrew 1456 CBC 18 : v.val.string.val = str;
1457 : }
1458 :
3036 andrew 1459 GIC 24 : (void) pushJsonbValue(&result.parseState, WJB_VALUE, &v);
3040 andrew 1460 ECB : }
1461 :
3040 andrew 1462 CBC 6 : pfree(in_datums);
1463 6 : pfree(in_nulls);
1464 :
1465 9 : close_object:
3040 andrew 1466 GIC 9 : result.res = pushJsonbValue(&result.parseState, WJB_END_OBJECT, NULL);
1467 :
1468 9 : PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
1469 : }
1470 :
1471 : /*
1472 : * SQL function jsonb_object(text[], text[])
1473 : *
1474 : * take separate name and value arrays of text to construct a jsonb object
1475 : * pairwise.
1476 : */
3040 andrew 1477 ECB : Datum
3040 andrew 1478 GIC 21 : jsonb_object_two_arg(PG_FUNCTION_ARGS)
3040 andrew 1479 ECB : {
3040 andrew 1480 CBC 21 : ArrayType *key_array = PG_GETARG_ARRAYTYPE_P(0);
3040 andrew 1481 GIC 21 : ArrayType *val_array = PG_GETARG_ARRAYTYPE_P(1);
1482 21 : int nkdims = ARR_NDIM(key_array);
1483 21 : int nvdims = ARR_NDIM(val_array);
1484 : Datum *key_datums,
1485 : *val_datums;
1486 : bool *key_nulls,
1487 : *val_nulls;
3040 andrew 1488 ECB : int key_count,
1489 : val_count,
1490 : i;
1491 : JsonbInState result;
1492 :
3040 andrew 1493 GIC 21 : memset(&result, 0, sizeof(JsonbInState));
3040 andrew 1494 ECB :
3036 andrew 1495 CBC 21 : (void) pushJsonbValue(&result.parseState, WJB_BEGIN_OBJECT, NULL);
1496 :
3040 andrew 1497 GIC 21 : if (nkdims > 1 || nkdims != nvdims)
3040 andrew 1498 CBC 3 : ereport(ERROR,
3040 andrew 1499 ECB : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
1500 : errmsg("wrong number of array subscripts")));
1501 :
3040 andrew 1502 GIC 18 : if (nkdims == 0)
2604 andrew 1503 CBC 3 : goto close_object;
1504 :
282 peter 1505 GNC 15 : deconstruct_array_builtin(key_array, TEXTOID, &key_datums, &key_nulls, &key_count);
1506 15 : deconstruct_array_builtin(val_array, TEXTOID, &val_datums, &val_nulls, &val_count);
3040 andrew 1507 ECB :
3040 andrew 1508 CBC 15 : if (key_count != val_count)
3040 andrew 1509 GIC 6 : ereport(ERROR,
1510 : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
1511 : errmsg("mismatched array dimensions")));
1512 :
3040 andrew 1513 CBC 39 : for (i = 0; i < key_count; ++i)
1514 : {
3040 andrew 1515 ECB : JsonbValue v;
1516 : char *str;
1517 : int len;
1518 :
3040 andrew 1519 GIC 33 : if (key_nulls[i])
1520 3 : ereport(ERROR,
1521 : (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
1522 : errmsg("null value not allowed for object key")));
3040 andrew 1523 ECB :
3040 andrew 1524 GBC 30 : str = TextDatumGetCString(key_datums[i]);
3040 andrew 1525 GIC 30 : len = strlen(str);
1526 :
1527 30 : v.type = jbvString;
3040 andrew 1528 ECB :
3040 andrew 1529 CBC 30 : v.val.string.len = len;
3040 andrew 1530 GIC 30 : v.val.string.val = str;
3040 andrew 1531 ECB :
3036 andrew 1532 GIC 30 : (void) pushJsonbValue(&result.parseState, WJB_KEY, &v);
3040 andrew 1533 ECB :
3040 andrew 1534 CBC 30 : if (val_nulls[i])
1535 : {
3040 andrew 1536 LBC 0 : v.type = jbvNull;
1537 : }
3040 andrew 1538 ECB : else
1539 : {
3040 andrew 1540 CBC 30 : str = TextDatumGetCString(val_datums[i]);
3040 andrew 1541 GIC 30 : len = strlen(str);
1542 :
1543 30 : v.type = jbvString;
3040 andrew 1544 ECB :
3040 andrew 1545 CBC 30 : v.val.string.len = len;
3040 andrew 1546 GIC 30 : v.val.string.val = str;
3040 andrew 1547 ECB : }
1548 :
3036 andrew 1549 CBC 30 : (void) pushJsonbValue(&result.parseState, WJB_VALUE, &v);
3040 andrew 1550 ECB : }
1551 :
3040 andrew 1552 GIC 6 : pfree(key_datums);
3040 andrew 1553 CBC 6 : pfree(key_nulls);
3040 andrew 1554 GIC 6 : pfree(val_datums);
1555 6 : pfree(val_nulls);
3040 andrew 1556 ECB :
2604 andrew 1557 CBC 9 : close_object:
2604 andrew 1558 GIC 9 : result.res = pushJsonbValue(&result.parseState, WJB_END_OBJECT, NULL);
2604 andrew 1559 ECB :
3040 andrew 1560 CBC 9 : PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
1561 : }
3040 andrew 1562 ECB :
1563 :
1564 : /*
1565 : * shallow clone of a parse state, suitable for use in aggregate
1566 : * final functions that will only append to the values rather than
1567 : * change them.
1568 : */
1569 : static JsonbParseState *
2878 bruce 1570 GIC 57 : clone_parse_state(JsonbParseState *state)
1571 : {
2878 bruce 1572 ECB : JsonbParseState *result,
1573 : *icursor,
1574 : *ocursor;
3040 andrew 1575 :
3040 andrew 1576 CBC 57 : if (state == NULL)
3040 andrew 1577 LBC 0 : return NULL;
1578 :
3040 andrew 1579 GIC 57 : result = palloc(sizeof(JsonbParseState));
1580 57 : icursor = state;
1581 57 : ocursor = result;
1582 : for (;;)
1583 : {
1584 57 : ocursor->contVal = icursor->contVal;
1585 57 : ocursor->size = icursor->size;
11 alvherre 1586 GNC 57 : ocursor->unique_keys = icursor->unique_keys;
1587 57 : ocursor->skip_nulls = icursor->skip_nulls;
3040 andrew 1588 GIC 57 : icursor = icursor->next;
3040 andrew 1589 CBC 57 : if (icursor == NULL)
3040 andrew 1590 GIC 57 : break;
2878 bruce 1591 LBC 0 : ocursor->next = palloc(sizeof(JsonbParseState));
3040 andrew 1592 UIC 0 : ocursor = ocursor->next;
3040 andrew 1593 ECB : }
3040 andrew 1594 CBC 57 : ocursor->next = NULL;
1595 :
3040 andrew 1596 GIC 57 : return result;
1597 : }
3040 andrew 1598 ECB :
1599 : static Datum
11 alvherre 1600 GNC 183 : jsonb_agg_transfn_worker(FunctionCallInfo fcinfo, bool absent_on_null)
3040 andrew 1601 ECB : {
1602 : MemoryContext oldcontext,
1603 : aggcontext;
1604 : JsonbAggState *state;
1605 : JsonbInState elem;
1606 : Datum val;
1607 : JsonbInState *result;
3040 andrew 1608 GIC 183 : bool single_scalar = false;
1609 : JsonbIterator *it;
1610 : Jsonb *jbelem;
3040 andrew 1611 ECB : JsonbValue v;
2963 alvherre 1612 : JsonbIteratorToken type;
1613 :
3040 andrew 1614 GIC 183 : if (!AggCheckCallContext(fcinfo, &aggcontext))
1615 : {
3040 andrew 1616 ECB : /* cannot be called directly because of internal-type argument */
3040 andrew 1617 LBC 0 : elog(ERROR, "jsonb_agg_transfn called in non-aggregate context");
1618 : }
3040 andrew 1619 ECB :
1620 : /* set up the accumulator on the first go round */
1621 :
3040 andrew 1622 CBC 183 : if (PG_ARGISNULL(0))
1623 : {
2733 tgl 1624 33 : Oid arg_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
1625 :
2760 andrew 1626 33 : if (arg_type == InvalidOid)
2760 andrew 1627 UIC 0 : ereport(ERROR,
2760 andrew 1628 EUB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1629 : errmsg("could not determine input data type")));
1630 :
2760 andrew 1631 GIC 33 : oldcontext = MemoryContextSwitchTo(aggcontext);
2760 andrew 1632 CBC 33 : state = palloc(sizeof(JsonbAggState));
3040 1633 33 : result = palloc0(sizeof(JsonbInState));
2760 andrew 1634 GIC 33 : state->res = result;
3040 andrew 1635 CBC 33 : result->res = pushJsonbValue(&result->parseState,
1636 : WJB_BEGIN_ARRAY, NULL);
2760 1637 33 : MemoryContextSwitchTo(oldcontext);
3040 andrew 1638 ECB :
2760 andrew 1639 GIC 33 : jsonb_categorize_type(arg_type, &state->val_category,
1640 : &state->val_output_func);
3040 andrew 1641 ECB : }
1642 : else
1643 : {
2760 andrew 1644 CBC 150 : state = (JsonbAggState *) PG_GETARG_POINTER(0);
1645 150 : result = state->res;
3040 andrew 1646 ECB : }
1647 :
11 alvherre 1648 GNC 183 : if (absent_on_null && PG_ARGISNULL(1))
1649 39 : PG_RETURN_POINTER(state);
1650 :
1651 : /* turn the argument into jsonb in the normal function context */
2760 andrew 1652 ECB :
2760 andrew 1653 CBC 144 : val = PG_ARGISNULL(1) ? (Datum) 0 : PG_GETARG_DATUM(1);
1654 :
1655 144 : memset(&elem, 0, sizeof(JsonbInState));
1656 :
2760 andrew 1657 GIC 144 : datum_to_jsonb(val, PG_ARGISNULL(1), &elem, state->val_category,
1658 : state->val_output_func, false);
1659 :
1660 144 : jbelem = JsonbValueToJsonb(elem.res);
1661 :
1662 : /* switch to the aggregate context for accumulation operations */
1663 :
1664 144 : oldcontext = MemoryContextSwitchTo(aggcontext);
2760 andrew 1665 ECB :
3040 andrew 1666 GIC 144 : it = JsonbIteratorInit(&jbelem->root);
1667 :
1668 984 : while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
1669 : {
1670 840 : switch (type)
3040 andrew 1671 ECB : {
3040 andrew 1672 GBC 114 : case WJB_BEGIN_ARRAY:
3040 andrew 1673 GIC 114 : if (v.val.array.rawScalar)
3040 andrew 1674 CBC 72 : single_scalar = true;
3040 andrew 1675 ECB : else
3040 andrew 1676 CBC 42 : result->res = pushJsonbValue(&result->parseState,
1677 : type, NULL);
3040 andrew 1678 GIC 114 : break;
3040 andrew 1679 CBC 114 : case WJB_END_ARRAY:
1680 114 : if (!single_scalar)
1681 42 : result->res = pushJsonbValue(&result->parseState,
3040 andrew 1682 ECB : type, NULL);
3040 andrew 1683 CBC 114 : break;
1684 180 : case WJB_BEGIN_OBJECT:
3040 andrew 1685 ECB : case WJB_END_OBJECT:
3040 andrew 1686 GBC 180 : result->res = pushJsonbValue(&result->parseState,
3040 andrew 1687 EUB : type, NULL);
3040 andrew 1688 GIC 180 : break;
3040 andrew 1689 CBC 432 : case WJB_ELEM:
1690 : case WJB_KEY:
3040 andrew 1691 ECB : case WJB_VALUE:
3040 andrew 1692 GIC 432 : if (v.type == jbvString)
1693 : {
1694 : /* copy string values in the aggregate context */
2931 heikki.linnakangas 1695 CBC 186 : char *buf = palloc(v.val.string.len + 1);
1696 :
3040 andrew 1697 GIC 186 : snprintf(buf, v.val.string.len + 1, "%s", v.val.string.val);
1698 186 : v.val.string.val = buf;
1699 : }
1700 246 : else if (v.type == jbvNumeric)
1701 : {
1702 : /* same for numeric */
2878 bruce 1703 CBC 204 : v.val.numeric =
2118 tgl 1704 GIC 204 : DatumGetNumeric(DirectFunctionCall1(numeric_uplus,
1705 : NumericGetDatum(v.val.numeric)));
1706 : }
3040 andrew 1707 432 : result->res = pushJsonbValue(&result->parseState,
1708 : type, &v);
3040 andrew 1709 CBC 432 : break;
2963 alvherre 1710 UIC 0 : default:
1711 0 : elog(ERROR, "unknown jsonb iterator token type");
3040 andrew 1712 EUB : }
1713 : }
1714 :
3040 andrew 1715 GIC 144 : MemoryContextSwitchTo(oldcontext);
1716 :
2760 andrew 1717 CBC 144 : PG_RETURN_POINTER(state);
1718 : }
3040 andrew 1719 ECB :
1720 : /*
1721 : * jsonb_agg aggregate function
1722 : */
1723 : Datum
11 alvherre 1724 GNC 72 : jsonb_agg_transfn(PG_FUNCTION_ARGS)
1725 : {
1726 72 : return jsonb_agg_transfn_worker(fcinfo, false);
1727 : }
1728 :
1729 : /*
1730 : * jsonb_agg_strict aggregate function
1731 : */
1732 : Datum
1733 111 : jsonb_agg_strict_transfn(PG_FUNCTION_ARGS)
1734 : {
1735 111 : return jsonb_agg_transfn_worker(fcinfo, true);
1736 : }
1737 :
1738 : Datum
3040 andrew 1739 CBC 36 : jsonb_agg_finalfn(PG_FUNCTION_ARGS)
3040 andrew 1740 EUB : {
1741 : JsonbAggState *arg;
1742 : JsonbInState result;
1743 : Jsonb *out;
3040 andrew 1744 ECB :
1745 : /* cannot be called directly because of internal-type argument */
3040 andrew 1746 CBC 36 : Assert(AggCheckCallContext(fcinfo, NULL));
3040 andrew 1747 ECB :
3040 andrew 1748 CBC 36 : if (PG_ARGISNULL(0))
3040 andrew 1749 GIC 3 : PG_RETURN_NULL(); /* returns null iff no input values */
3040 andrew 1750 ECB :
2760 andrew 1751 GIC 33 : arg = (JsonbAggState *) PG_GETARG_POINTER(0);
3040 andrew 1752 ECB :
1753 : /*
1754 : * We need to do a shallow clone of the argument in case the final
1755 : * function is called more than once, so we avoid changing the argument. A
1756 : * shallow clone is sufficient as we aren't going to change any of the
1757 : * values, just add the final array end marker.
1758 : */
119 tgl 1759 GNC 33 : memset(&result, 0, sizeof(JsonbInState));
1760 :
2760 andrew 1761 GIC 33 : result.parseState = clone_parse_state(arg->res->parseState);
3040 andrew 1762 ECB :
3040 andrew 1763 CBC 33 : result.res = pushJsonbValue(&result.parseState,
1764 : WJB_END_ARRAY, NULL);
1765 :
3040 andrew 1766 GIC 33 : out = JsonbValueToJsonb(result.res);
3040 andrew 1767 ECB :
3040 andrew 1768 GIC 33 : PG_RETURN_POINTER(out);
3040 andrew 1769 ECB : }
1770 :
1771 : static Datum
11 alvherre 1772 GNC 96 : jsonb_object_agg_transfn_worker(FunctionCallInfo fcinfo,
1773 : bool absent_on_null, bool unique_keys)
1774 : {
1775 : MemoryContext oldcontext,
3040 andrew 1776 ECB : aggcontext;
1777 : JsonbInState elem;
2760 1778 : JsonbAggState *state;
1779 : Datum val;
3040 1780 : JsonbInState *result;
1781 : bool single_scalar;
1782 : JsonbIterator *it;
1783 : Jsonb *jbkey,
1784 : *jbval;
1785 : JsonbValue v;
2963 alvherre 1786 : JsonbIteratorToken type;
1787 : bool skip;
1788 :
3040 andrew 1789 CBC 96 : if (!AggCheckCallContext(fcinfo, &aggcontext))
1790 : {
3040 andrew 1791 ECB : /* cannot be called directly because of internal-type argument */
3040 andrew 1792 LBC 0 : elog(ERROR, "jsonb_object_agg_transfn called in non-aggregate context");
3040 andrew 1793 ECB : }
1794 :
1795 : /* set up the accumulator on the first go round */
1796 :
2760 andrew 1797 CBC 96 : if (PG_ARGISNULL(0))
1798 : {
2733 tgl 1799 ECB : Oid arg_type;
1800 :
2760 andrew 1801 CBC 33 : oldcontext = MemoryContextSwitchTo(aggcontext);
1802 33 : state = palloc(sizeof(JsonbAggState));
2760 andrew 1803 GIC 33 : result = palloc0(sizeof(JsonbInState));
1804 33 : state->res = result;
2760 andrew 1805 CBC 33 : result->res = pushJsonbValue(&result->parseState,
1806 : WJB_BEGIN_OBJECT, NULL);
11 alvherre 1807 GNC 33 : result->parseState->unique_keys = unique_keys;
1808 33 : result->parseState->skip_nulls = absent_on_null;
1809 :
2760 andrew 1810 GIC 33 : MemoryContextSwitchTo(oldcontext);
2760 andrew 1811 ECB :
2760 andrew 1812 GIC 33 : arg_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
2760 andrew 1813 ECB :
2760 andrew 1814 CBC 33 : if (arg_type == InvalidOid)
2760 andrew 1815 UIC 0 : ereport(ERROR,
2760 andrew 1816 ECB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1817 : errmsg("could not determine input data type")));
1818 :
2760 andrew 1819 CBC 33 : jsonb_categorize_type(arg_type, &state->key_category,
2760 andrew 1820 ECB : &state->key_output_func);
1821 :
2760 andrew 1822 GIC 33 : arg_type = get_fn_expr_argtype(fcinfo->flinfo, 2);
2760 andrew 1823 ECB :
2760 andrew 1824 GIC 33 : if (arg_type == InvalidOid)
2760 andrew 1825 LBC 0 : ereport(ERROR,
2760 andrew 1826 EUB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1827 : errmsg("could not determine input data type")));
1828 :
2760 andrew 1829 GIC 33 : jsonb_categorize_type(arg_type, &state->val_category,
1830 : &state->val_output_func);
2760 andrew 1831 ECB : }
1832 : else
1833 : {
2760 andrew 1834 GIC 63 : state = (JsonbAggState *) PG_GETARG_POINTER(0);
1835 63 : result = state->res;
1836 : }
1837 :
1838 : /* turn the argument into jsonb in the normal function context */
1839 :
2816 andrew 1840 CBC 96 : if (PG_ARGISNULL(1))
2816 andrew 1841 GIC 9 : ereport(ERROR,
2816 andrew 1842 ECB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1843 : errmsg("field name must not be null")));
1844 :
1845 : /*
1846 : * Skip null values if absent_on_null unless key uniqueness check is
1847 : * needed (because we must save keys in this case).
1848 : */
11 alvherre 1849 GNC 87 : skip = absent_on_null && PG_ARGISNULL(2);
1850 :
1851 87 : if (skip && !unique_keys)
1852 6 : PG_RETURN_POINTER(state);
1853 :
2816 andrew 1854 GIC 81 : val = PG_GETARG_DATUM(1);
1855 :
3040 1856 81 : memset(&elem, 0, sizeof(JsonbInState));
1857 :
2760 andrew 1858 CBC 81 : datum_to_jsonb(val, false, &elem, state->key_category,
1859 : state->key_output_func, true);
3040 andrew 1860 ECB :
3040 andrew 1861 GIC 81 : jbkey = JsonbValueToJsonb(elem.res);
1862 :
1863 81 : val = PG_ARGISNULL(2) ? (Datum) 0 : PG_GETARG_DATUM(2);
3040 andrew 1864 ECB :
3040 andrew 1865 GIC 81 : memset(&elem, 0, sizeof(JsonbInState));
1866 :
2760 1867 81 : datum_to_jsonb(val, PG_ARGISNULL(2), &elem, state->val_category,
1868 : state->val_output_func, false);
1869 :
3040 1870 81 : jbval = JsonbValueToJsonb(elem.res);
3040 andrew 1871 ECB :
2760 andrew 1872 GIC 81 : it = JsonbIteratorInit(&jbkey->root);
2760 andrew 1873 ECB :
3040 1874 : /* switch to the aggregate context for accumulation operations */
1875 :
3040 andrew 1876 CBC 81 : oldcontext = MemoryContextSwitchTo(aggcontext);
1877 :
1878 : /*
1879 : * keys should be scalar, and we should have already checked for that
1880 : * above when calling datum_to_jsonb, so we only need to look for these
1881 : * things.
1882 : */
1883 :
1884 318 : while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
1885 : {
1886 240 : switch (type)
1887 : {
1888 81 : case WJB_BEGIN_ARRAY:
3040 andrew 1889 GIC 81 : if (!v.val.array.rawScalar)
3040 andrew 1890 UIC 0 : elog(ERROR, "unexpected structure for key");
3040 andrew 1891 CBC 81 : break;
3040 andrew 1892 GIC 81 : case WJB_ELEM:
3040 andrew 1893 CBC 81 : if (v.type == jbvString)
1894 : {
1895 : /* copy string values in the aggregate context */
2931 heikki.linnakangas 1896 GIC 81 : char *buf = palloc(v.val.string.len + 1);
2878 bruce 1897 ECB :
3040 andrew 1898 GIC 81 : snprintf(buf, v.val.string.len + 1, "%s", v.val.string.val);
1899 81 : v.val.string.val = buf;
1900 : }
1901 : else
1902 : {
3040 andrew 1903 UIC 0 : ereport(ERROR,
1904 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1905 : errmsg("object keys must be strings")));
1906 : }
3040 andrew 1907 GIC 81 : result->res = pushJsonbValue(&result->parseState,
1908 : WJB_KEY, &v);
1909 :
11 alvherre 1910 GNC 81 : if (skip)
1911 : {
1912 3 : v.type = jbvNull;
1913 3 : result->res = pushJsonbValue(&result->parseState,
1914 : WJB_VALUE, &v);
1915 3 : MemoryContextSwitchTo(oldcontext);
1916 3 : PG_RETURN_POINTER(state);
1917 : }
1918 :
3040 andrew 1919 GIC 78 : break;
1920 78 : case WJB_END_ARRAY:
1921 78 : break;
3040 andrew 1922 UIC 0 : default:
1923 0 : elog(ERROR, "unexpected structure for key");
3040 andrew 1924 ECB : break;
1925 : }
1926 : }
3040 andrew 1927 EUB :
3040 andrew 1928 GIC 78 : it = JsonbIteratorInit(&jbval->root);
1929 :
1930 78 : single_scalar = false;
1931 :
3040 andrew 1932 ECB : /*
1933 : * values can be anything, including structured and null, so we treat them
1934 : * as in json_agg_transfn, except that single scalars are always pushed as
1935 : * WJB_VALUE items.
1936 : */
1937 :
3040 andrew 1938 CBC 339 : while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
3040 andrew 1939 ECB : {
3040 andrew 1940 CBC 261 : switch (type)
1941 : {
1942 69 : case WJB_BEGIN_ARRAY:
1943 69 : if (v.val.array.rawScalar)
3040 andrew 1944 GIC 69 : single_scalar = true;
3040 andrew 1945 ECB : else
3040 andrew 1946 UIC 0 : result->res = pushJsonbValue(&result->parseState,
3040 andrew 1947 ECB : type, NULL);
3040 andrew 1948 GIC 69 : break;
3040 andrew 1949 CBC 69 : case WJB_END_ARRAY:
3040 andrew 1950 GBC 69 : if (!single_scalar)
3040 andrew 1951 UIC 0 : result->res = pushJsonbValue(&result->parseState,
1952 : type, NULL);
3040 andrew 1953 GIC 69 : break;
3040 andrew 1954 CBC 18 : case WJB_BEGIN_OBJECT:
1955 : case WJB_END_OBJECT:
3040 andrew 1956 GIC 18 : result->res = pushJsonbValue(&result->parseState,
3040 andrew 1957 ECB : type, NULL);
3040 andrew 1958 GIC 18 : break;
3040 andrew 1959 CBC 105 : case WJB_ELEM:
3040 andrew 1960 EUB : case WJB_KEY:
1961 : case WJB_VALUE:
3040 andrew 1962 GIC 105 : if (v.type == jbvString)
1963 : {
2963 alvherre 1964 ECB : /* copy string values in the aggregate context */
2931 heikki.linnakangas 1965 GIC 54 : char *buf = palloc(v.val.string.len + 1);
1966 :
3040 andrew 1967 54 : snprintf(buf, v.val.string.len + 1, "%s", v.val.string.val);
1968 54 : v.val.string.val = buf;
3040 andrew 1969 ECB : }
3040 andrew 1970 CBC 51 : else if (v.type == jbvNumeric)
1971 : {
1972 : /* same for numeric */
3040 andrew 1973 GIC 39 : v.val.numeric =
2118 tgl 1974 39 : DatumGetNumeric(DirectFunctionCall1(numeric_uplus,
2118 tgl 1975 ECB : NumericGetDatum(v.val.numeric)));
3040 andrew 1976 : }
3040 andrew 1977 GIC 105 : result->res = pushJsonbValue(&result->parseState,
1978 : single_scalar ? WJB_VALUE : type,
1979 : &v);
1980 105 : break;
2963 alvherre 1981 UIC 0 : default:
1982 0 : elog(ERROR, "unknown jsonb iterator token type");
1983 : }
3040 andrew 1984 ECB : }
1985 :
3040 andrew 1986 CBC 78 : MemoryContextSwitchTo(oldcontext);
3040 andrew 1987 ECB :
2760 andrew 1988 GIC 78 : PG_RETURN_POINTER(state);
3040 andrew 1989 ECB : }
1990 :
1991 : /*
1992 : * jsonb_object_agg aggregate function
1993 : */
1994 : Datum
11 alvherre 1995 GNC 66 : jsonb_object_agg_transfn(PG_FUNCTION_ARGS)
1996 : {
1997 66 : return jsonb_object_agg_transfn_worker(fcinfo, false, false);
1998 : }
1999 :
2000 :
2001 : /*
2002 : * jsonb_object_agg_strict aggregate function
2003 : */
2004 : Datum
2005 12 : jsonb_object_agg_strict_transfn(PG_FUNCTION_ARGS)
2006 : {
2007 12 : return jsonb_object_agg_transfn_worker(fcinfo, true, false);
2008 : }
2009 :
2010 : /*
2011 : * jsonb_object_agg_unique aggregate function
2012 : */
2013 : Datum
2014 9 : jsonb_object_agg_unique_transfn(PG_FUNCTION_ARGS)
2015 : {
2016 9 : return jsonb_object_agg_transfn_worker(fcinfo, false, true);
2017 : }
2018 :
2019 : /*
2020 : * jsonb_object_agg_unique_strict aggregate function
2021 : */
2022 : Datum
2023 9 : jsonb_object_agg_unique_strict_transfn(PG_FUNCTION_ARGS)
2024 : {
2025 9 : return jsonb_object_agg_transfn_worker(fcinfo, true, true);
2026 : }
2027 :
3040 andrew 2028 ECB : Datum
3040 andrew 2029 GIC 27 : jsonb_object_agg_finalfn(PG_FUNCTION_ARGS)
3040 andrew 2030 ECB : {
2031 : JsonbAggState *arg;
2032 : JsonbInState result;
2033 : Jsonb *out;
2034 :
2035 : /* cannot be called directly because of internal-type argument */
3040 andrew 2036 GIC 27 : Assert(AggCheckCallContext(fcinfo, NULL));
3040 andrew 2037 ECB :
3040 andrew 2038 GIC 27 : if (PG_ARGISNULL(0))
3040 andrew 2039 CBC 3 : PG_RETURN_NULL(); /* returns null iff no input values */
2040 :
2760 andrew 2041 GIC 24 : arg = (JsonbAggState *) PG_GETARG_POINTER(0);
3040 andrew 2042 ECB :
2043 : /*
2760 2044 : * We need to do a shallow clone of the argument's res field in case the
2045 : * final function is called more than once, so we avoid changing the
2046 : * aggregate state value. A shallow clone is sufficient as we aren't
2047 : * going to change any of the values, just add the final object end
2733 tgl 2048 : * marker.
2049 : */
119 tgl 2050 GNC 24 : memset(&result, 0, sizeof(JsonbInState));
2051 :
2760 andrew 2052 GIC 24 : result.parseState = clone_parse_state(arg->res->parseState);
2053 :
3040 2054 24 : result.res = pushJsonbValue(&result.parseState,
2055 : WJB_END_OBJECT, NULL);
2056 :
3040 andrew 2057 CBC 18 : out = JsonbValueToJsonb(result.res);
2058 :
2059 18 : PG_RETURN_POINTER(out);
2060 : }
1837 teodor 2061 ECB :
2062 :
1837 teodor 2063 EUB : /*
1837 teodor 2064 ECB : * Extract scalar value from raw-scalar pseudo-array jsonb.
2065 : */
1485 akorotkov 2066 : bool
1837 teodor 2067 GIC 95340 : JsonbExtractScalar(JsonbContainer *jbc, JsonbValue *res)
2068 : {
1837 teodor 2069 ECB : JsonbIterator *it;
2070 : JsonbIteratorToken tok PG_USED_FOR_ASSERTS_ONLY;
2071 : JsonbValue tmp;
2072 :
1837 teodor 2073 GIC 95340 : if (!JsonContainerIsArray(jbc) || !JsonContainerIsScalar(jbc))
2074 : {
2075 : /* inform caller about actual type of container */
1796 teodor 2076 GBC 94890 : res->type = (JsonContainerIsArray(jbc)) ? jbvArray : jbvObject;
1796 teodor 2077 GIC 94890 : return false;
2078 : }
2079 :
1837 teodor 2080 ECB : /*
2081 : * A root scalar is stored as an array of one element, so we get the array
2082 : * and then its first (and only) member.
2083 : */
1837 teodor 2084 GIC 450 : it = JsonbIteratorInit(jbc);
1837 teodor 2085 ECB :
1837 teodor 2086 CBC 450 : tok = JsonbIteratorNext(&it, &tmp, true);
1837 teodor 2087 GIC 450 : Assert(tok == WJB_BEGIN_ARRAY);
1837 teodor 2088 CBC 450 : Assert(tmp.val.array.nElems == 1 && tmp.val.array.rawScalar);
1837 teodor 2089 ECB :
1837 teodor 2090 GIC 450 : tok = JsonbIteratorNext(&it, res, true);
1809 tgl 2091 450 : Assert(tok == WJB_ELEM);
1837 teodor 2092 CBC 450 : Assert(IsAJsonbScalar(res));
1837 teodor 2093 ECB :
1837 teodor 2094 CBC 450 : tok = JsonbIteratorNext(&it, &tmp, true);
1809 tgl 2095 GBC 450 : Assert(tok == WJB_END_ARRAY);
1837 teodor 2096 EUB :
1837 teodor 2097 GIC 450 : tok = JsonbIteratorNext(&it, &tmp, true);
2098 450 : Assert(tok == WJB_DONE);
2099 :
1796 2100 450 : return true;
1796 teodor 2101 ECB : }
2102 :
2103 : /*
2104 : * Emit correct, translatable cast error message
2105 : */
2106 : static void
1796 teodor 2107 GIC 12 : cannotCastJsonbValue(enum jbvType type, const char *sqltype)
2108 : {
2109 : static const struct
2110 : {
1744 andrew 2111 ECB : enum jbvType type;
2112 : const char *msg;
1796 teodor 2113 : }
2114 : messages[] =
2115 : {
1744 andrew 2116 : {jbvNull, gettext_noop("cannot cast jsonb null to type %s")},
2117 : {jbvString, gettext_noop("cannot cast jsonb string to type %s")},
2118 : {jbvNumeric, gettext_noop("cannot cast jsonb numeric to type %s")},
1744 andrew 2119 EUB : {jbvBool, gettext_noop("cannot cast jsonb boolean to type %s")},
2120 : {jbvArray, gettext_noop("cannot cast jsonb array to type %s")},
1744 andrew 2121 ECB : {jbvObject, gettext_noop("cannot cast jsonb object to type %s")},
2122 : {jbvBinary, gettext_noop("cannot cast jsonb array or object to type %s")}
1796 teodor 2123 : };
1744 andrew 2124 EUB : int i;
2125 :
1744 andrew 2126 CBC 54 : for (i = 0; i < lengthof(messages); i++)
1796 teodor 2127 54 : if (messages[i].type == type)
1796 teodor 2128 GIC 12 : ereport(ERROR,
1796 teodor 2129 ECB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2130 : errmsg(messages[i].msg, sqltype)));
2131 :
2132 : /* should be unreachable */
1744 andrew 2133 UIC 0 : elog(ERROR, "unknown jsonb type: %d", (int) type);
2134 : }
1837 teodor 2135 ECB :
2136 : Datum
1837 teodor 2137 GIC 6 : jsonb_bool(PG_FUNCTION_ARGS)
1837 teodor 2138 ECB : {
1837 teodor 2139 GIC 6 : Jsonb *in = PG_GETARG_JSONB_P(0);
1837 teodor 2140 ECB : JsonbValue v;
2141 :
1837 teodor 2142 GIC 6 : if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvBool)
1796 teodor 2143 CBC 3 : cannotCastJsonbValue(v.type, "boolean");
2144 :
1837 teodor 2145 GIC 3 : PG_FREE_IF_COPY(in, 0);
1837 teodor 2146 ECB :
1837 teodor 2147 CBC 3 : PG_RETURN_BOOL(v.val.boolean);
2148 : }
2149 :
1837 teodor 2150 ECB : Datum
1837 teodor 2151 GIC 12 : jsonb_numeric(PG_FUNCTION_ARGS)
2152 : {
1837 teodor 2153 CBC 12 : Jsonb *in = PG_GETARG_JSONB_P(0);
1837 teodor 2154 EUB : JsonbValue v;
2155 : Numeric retValue;
2156 :
1837 teodor 2157 GIC 12 : if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvNumeric)
1796 2158 3 : cannotCastJsonbValue(v.type, "numeric");
1837 teodor 2159 ECB :
2160 : /*
1809 tgl 2161 : * v.val.numeric points into jsonb body, so we need to make a copy to
2162 : * return
2163 : */
1837 teodor 2164 GIC 9 : retValue = DatumGetNumericCopy(NumericGetDatum(v.val.numeric));
2165 :
2166 9 : PG_FREE_IF_COPY(in, 0);
2167 :
1837 teodor 2168 CBC 9 : PG_RETURN_NUMERIC(retValue);
2169 : }
1837 teodor 2170 ECB :
2171 : Datum
1837 teodor 2172 GIC 6 : jsonb_int2(PG_FUNCTION_ARGS)
2173 : {
2174 6 : Jsonb *in = PG_GETARG_JSONB_P(0);
2175 : JsonbValue v;
2176 : Datum retValue;
2177 :
1837 teodor 2178 CBC 6 : if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvNumeric)
1796 teodor 2179 UIC 0 : cannotCastJsonbValue(v.type, "smallint");
1837 teodor 2180 ECB :
1837 teodor 2181 GIC 6 : retValue = DirectFunctionCall1(numeric_int2,
2182 : NumericGetDatum(v.val.numeric));
2183 :
2184 6 : PG_FREE_IF_COPY(in, 0);
2185 :
2186 6 : PG_RETURN_DATUM(retValue);
1837 teodor 2187 ECB : }
2188 :
2189 : Datum
1837 teodor 2190 GIC 12 : jsonb_int4(PG_FUNCTION_ARGS)
2191 : {
2192 12 : Jsonb *in = PG_GETARG_JSONB_P(0);
2193 : JsonbValue v;
2194 : Datum retValue;
2195 :
1837 teodor 2196 CBC 12 : if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvNumeric)
1796 teodor 2197 GIC 3 : cannotCastJsonbValue(v.type, "integer");
1837 teodor 2198 ECB :
1837 teodor 2199 GIC 9 : retValue = DirectFunctionCall1(numeric_int4,
2200 : NumericGetDatum(v.val.numeric));
2201 :
1837 teodor 2202 CBC 9 : PG_FREE_IF_COPY(in, 0);
2203 :
1837 teodor 2204 GIC 9 : PG_RETURN_DATUM(retValue);
2205 : }
2206 :
2207 : Datum
2208 24 : jsonb_int8(PG_FUNCTION_ARGS)
1837 teodor 2209 ECB : {
1837 teodor 2210 GIC 24 : Jsonb *in = PG_GETARG_JSONB_P(0);
1809 tgl 2211 ECB : JsonbValue v;
1837 teodor 2212 : Datum retValue;
2213 :
1837 teodor 2214 CBC 24 : if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvNumeric)
1796 teodor 2215 UIC 0 : cannotCastJsonbValue(v.type, "bigint");
2216 :
1837 teodor 2217 GIC 24 : retValue = DirectFunctionCall1(numeric_int8,
2218 : NumericGetDatum(v.val.numeric));
2219 :
2220 24 : PG_FREE_IF_COPY(in, 0);
2221 :
2222 24 : PG_RETURN_DATUM(retValue);
1837 teodor 2223 ECB : }
2224 :
2225 : Datum
1837 teodor 2226 GIC 6 : jsonb_float4(PG_FUNCTION_ARGS)
1837 teodor 2227 ECB : {
1837 teodor 2228 GIC 6 : Jsonb *in = PG_GETARG_JSONB_P(0);
2229 : JsonbValue v;
1837 teodor 2230 ECB : Datum retValue;
2231 :
1837 teodor 2232 CBC 6 : if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvNumeric)
1796 teodor 2233 UIC 0 : cannotCastJsonbValue(v.type, "real");
2234 :
1837 teodor 2235 GIC 6 : retValue = DirectFunctionCall1(numeric_float4,
2236 : NumericGetDatum(v.val.numeric));
2237 :
2238 6 : PG_FREE_IF_COPY(in, 0);
2239 :
1837 teodor 2240 CBC 6 : PG_RETURN_DATUM(retValue);
2241 : }
2242 :
2243 : Datum
1837 teodor 2244 GIC 12 : jsonb_float8(PG_FUNCTION_ARGS)
2245 : {
1837 teodor 2246 CBC 12 : Jsonb *in = PG_GETARG_JSONB_P(0);
2247 : JsonbValue v;
2248 : Datum retValue;
1837 teodor 2249 ECB :
1837 teodor 2250 CBC 12 : if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvNumeric)
1796 teodor 2251 GIC 3 : cannotCastJsonbValue(v.type, "double precision");
2252 :
1837 2253 9 : retValue = DirectFunctionCall1(numeric_float8,
2254 : NumericGetDatum(v.val.numeric));
2255 :
2256 9 : PG_FREE_IF_COPY(in, 0);
1837 teodor 2257 ECB :
1837 teodor 2258 GIC 9 : PG_RETURN_DATUM(retValue);
1837 teodor 2259 ECB : }
|