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