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