1 /*------------------------------------------------------------------------- 2 * 3 * json.c 4 * JSON data type support. 5 * 6 * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group 7 * Portions Copyright (c) 1994, Regents of the University of California 8 * 9 * IDENTIFICATION MidiSequenceHandlerImpl(MidiSequencerImpl seq,int tracks)10 * src/backend/utils/adt/json.c 11 * 12 *------------------------------------------------------------------------- 13 */ 14 #include "postgres.h" 15 16 #include "catalog/pg_type.h" 17 #include "funcapi.h" 18 #include "libpq/pqformat.h" 19 #include "miscadmin.h" 20 #include "parser/parse_coerce.h" 21 #include "utils/array.h" 22 #include "utils/builtins.h" 23 #include "utils/date.h" 24 #include "utils/datetime.h" 25 #include "utils/json.h" 26 #include "utils/jsonfuncs.h" 27 #include "utils/lsyscache.h" 28 #include "utils/typcache.h" 29 30 typedef enum /* type categories for datum_to_json */ 31 { 32 JSONTYPE_NULL, /* null, so we didn't bother to identify */ 33 JSONTYPE_BOOL, /* boolean (built-in types only) */ 34 JSONTYPE_NUMERIC, /* numeric (ditto) */ 35 JSONTYPE_DATE, /* we use special formatting for datetimes */ 36 JSONTYPE_TIMESTAMP, 37 JSONTYPE_TIMESTAMPTZ, 38 JSONTYPE_JSON, /* JSON itself (and JSONB) */ 39 JSONTYPE_ARRAY, /* array */ 40 JSONTYPE_COMPOSITE, /* composite */ 41 JSONTYPE_CAST, /* something with an explicit cast to JSON */ 42 JSONTYPE_OTHER /* all else */ 43 } JsonTypeCategory; notifyFinish()44 45 typedef struct JsonAggState 46 { 47 StringInfo str; 48 JsonTypeCategory key_category; 49 Oid key_output_func; 50 JsonTypeCategory val_category; 51 Oid val_output_func; 52 } JsonAggState; 53 54 static void composite_to_json(Datum composite, StringInfo result, 55 bool use_line_feeds); 56 static void array_dim_to_json(StringInfo result, int dim, int ndims, int *dims, 57 Datum *vals, bool *nulls, int *valcount, 58 JsonTypeCategory tcategory, Oid outfuncoid, 59 bool use_line_feeds); 60 static void array_to_json_internal(Datum array, StringInfo result, 61 bool use_line_feeds); 62 static void json_categorize_type(Oid typoid, 63 JsonTypeCategory *tcategory, 64 Oid *outfuncoid); 65 static void datum_to_json(Datum val, bool is_null, StringInfo result, 66 JsonTypeCategory tcategory, Oid outfuncoid, 67 bool key_scalar); 68 static void add_json(Datum val, bool is_null, StringInfo result, 69 Oid val_type, bool key_scalar); 70 static text *catenate_stringinfo_string(StringInfo buffer, const char *addon); 71 72 /* 73 * Input. 74 */ 75 Datum 76 json_in(PG_FUNCTION_ARGS) 77 { 78 char *json = PG_GETARG_CSTRING(0); 79 text *result = cstring_to_text(json); 80 JsonLexContext *lex; 81 82 /* validate it */ 83 lex = makeJsonLexContext(result, false); 84 pg_parse_json_or_ereport(lex, &nullSemAction); 85 86 /* Internal representation is the same as text, for now */ 87 PG_RETURN_TEXT_P(result); 88 } 89 90 /* 91 * Output. 92 */ 93 Datum 94 json_out(PG_FUNCTION_ARGS) 95 { 96 /* we needn't detoast because text_to_cstring will handle that */ 97 Datum txt = PG_GETARG_DATUM(0); 98 99 PG_RETURN_CSTRING(TextDatumGetCString(txt)); 100 } 101 102 /* 103 * Binary send. 104 */ 105 Datum 106 json_send(PG_FUNCTION_ARGS) 107 { 108 text *t = PG_GETARG_TEXT_PP(0); 109 StringInfoData buf; 110 111 pq_begintypsend(&buf); 112 pq_sendtext(&buf, VARDATA_ANY(t), VARSIZE_ANY_EXHDR(t)); 113 PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); 114 } 115 116 /* 117 * Binary receive. 118 */ 119 Datum 120 json_recv(PG_FUNCTION_ARGS) 121 { 122 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); 123 char *str; 124 int nbytes; 125 JsonLexContext *lex; 126 127 str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes); 128 129 /* Validate it. */ 130 lex = makeJsonLexContextCstringLen(str, nbytes, GetDatabaseEncoding(), false); 131 pg_parse_json_or_ereport(lex, &nullSemAction); 132 133 PG_RETURN_TEXT_P(cstring_to_text_with_len(str, nbytes)); 134 } 135 136 /* 137 * Determine how we want to print values of a given type in datum_to_json. 138 * 139 * Given the datatype OID, return its JsonTypeCategory, as well as the type's 140 * output function OID. If the returned category is JSONTYPE_CAST, we 141 * return the OID of the type->JSON cast function instead. 142 */ 143 static void 144 json_categorize_type(Oid typoid, 145 JsonTypeCategory *tcategory, 146 Oid *outfuncoid) 147 { 148 bool typisvarlena; 149 150 /* Look through any domain */ 151 typoid = getBaseType(typoid); 152 153 *outfuncoid = InvalidOid; 154 155 /* 156 * We need to get the output function for everything except date and 157 * timestamp types, array and composite types, booleans, and non-builtin 158 * types where there's a cast to json. 159 */ 160 161 switch (typoid) 162 { 163 case BOOLOID: 164 *tcategory = JSONTYPE_BOOL; 165 break; 166 167 case INT2OID: 168 case INT4OID: 169 case INT8OID: 170 case FLOAT4OID: 171 case FLOAT8OID: 172 case NUMERICOID: 173 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena); 174 *tcategory = JSONTYPE_NUMERIC; 175 break; 176 177 case DATEOID: 178 *tcategory = JSONTYPE_DATE; 179 break; 180 181 case TIMESTAMPOID: 182 *tcategory = JSONTYPE_TIMESTAMP; 183 break; 184 185 case TIMESTAMPTZOID: 186 *tcategory = JSONTYPE_TIMESTAMPTZ; 187 break; 188 189 case JSONOID: 190 case JSONBOID: 191 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena); 192 *tcategory = JSONTYPE_JSON; 193 break; 194 195 default: 196 /* Check for arrays and composites */ 197 if (OidIsValid(get_element_type(typoid)) || typoid == ANYARRAYOID 198 || typoid == ANYCOMPATIBLEARRAYOID || typoid == RECORDARRAYOID) 199 *tcategory = JSONTYPE_ARRAY; 200 else if (type_is_rowtype(typoid)) /* includes RECORDOID */ 201 *tcategory = JSONTYPE_COMPOSITE; 202 else 203 { 204 /* It's probably the general case ... */ 205 *tcategory = JSONTYPE_OTHER; 206 /* but let's look for a cast to json, if it's not built-in */ 207 if (typoid >= FirstNormalObjectId) 208 { 209 Oid castfunc; 210 CoercionPathType ctype; 211 212 ctype = find_coercion_pathway(JSONOID, typoid, 213 COERCION_EXPLICIT, 214 &castfunc); 215 if (ctype == COERCION_PATH_FUNC && OidIsValid(castfunc)) 216 { 217 *tcategory = JSONTYPE_CAST; 218 *outfuncoid = castfunc; 219 } 220 else 221 { 222 /* non builtin type with no cast */ 223 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena); 224 } 225 } 226 else 227 { 228 /* any other builtin type */ 229 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena); 230 } 231 } 232 break; 233 } 234 } 235 236 /* 237 * Turn a Datum into JSON text, appending the string to "result". 238 * 239 * tcategory and outfuncoid are from a previous call to json_categorize_type, 240 * except that if is_null is true then they can be invalid. 241 * 242 * If key_scalar is true, the value is being printed as a key, so insist 243 * it's of an acceptable type, and force it to be quoted. 244 */ 245 static void 246 datum_to_json(Datum val, bool is_null, StringInfo result, 247 JsonTypeCategory tcategory, Oid outfuncoid, 248 bool key_scalar) 249 { 250 char *outputstr; 251 text *jsontext; 252 253 check_stack_depth(); 254 255 /* callers are expected to ensure that null keys are not passed in */ 256 Assert(!(key_scalar && is_null)); 257 258 if (is_null) 259 { 260 appendStringInfoString(result, "null"); 261 return; 262 } 263 264 if (key_scalar && 265 (tcategory == JSONTYPE_ARRAY || 266 tcategory == JSONTYPE_COMPOSITE || 267 tcategory == JSONTYPE_JSON || 268 tcategory == JSONTYPE_CAST)) 269 ereport(ERROR, 270 (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 271 errmsg("key value must be scalar, not array, composite, or json"))); 272 273 switch (tcategory) 274 { 275 case JSONTYPE_ARRAY: 276 array_to_json_internal(val, result, false); 277 break; 278 case JSONTYPE_COMPOSITE: 279 composite_to_json(val, result, false); 280 break; 281 case JSONTYPE_BOOL: 282 outputstr = DatumGetBool(val) ? "true" : "false"; 283 if (key_scalar) 284 escape_json(result, outputstr); 285 else 286 appendStringInfoString(result, outputstr); 287 break; 288 case JSONTYPE_NUMERIC: 289 outputstr = OidOutputFunctionCall(outfuncoid, val); 290 291 /* 292 * Don't call escape_json for a non-key if it's a valid JSON 293 * number. 294 */ 295 if (!key_scalar && IsValidJsonNumber(outputstr, strlen(outputstr))) 296 appendStringInfoString(result, outputstr); 297 else 298 escape_json(result, outputstr); 299 pfree(outputstr); 300 break; 301 case JSONTYPE_DATE: 302 { 303 char buf[MAXDATELEN + 1]; 304 305 JsonEncodeDateTime(buf, val, DATEOID, NULL); 306 appendStringInfo(result, "\"%s\"", buf); 307 } 308 break; 309 case JSONTYPE_TIMESTAMP: 310 { 311 char buf[MAXDATELEN + 1]; 312 313 JsonEncodeDateTime(buf, val, TIMESTAMPOID, NULL); 314 appendStringInfo(result, "\"%s\"", buf); 315 } 316 break; 317 case JSONTYPE_TIMESTAMPTZ: 318 { 319 char buf[MAXDATELEN + 1]; 320 321 JsonEncodeDateTime(buf, val, TIMESTAMPTZOID, NULL); 322 appendStringInfo(result, "\"%s\"", buf); 323 } 324 break; 325 case JSONTYPE_JSON: 326 /* JSON and JSONB output will already be escaped */ 327 outputstr = OidOutputFunctionCall(outfuncoid, val); 328 appendStringInfoString(result, outputstr); 329 pfree(outputstr); 330 break; 331 case JSONTYPE_CAST: 332 /* outfuncoid refers to a cast function, not an output function */ 333 jsontext = DatumGetTextPP(OidFunctionCall1(outfuncoid, val)); 334 outputstr = text_to_cstring(jsontext); 335 appendStringInfoString(result, outputstr); 336 pfree(outputstr); 337 pfree(jsontext); 338 break; 339 default: 340 outputstr = OidOutputFunctionCall(outfuncoid, val); 341 escape_json(result, outputstr); 342 pfree(outputstr); 343 break; 344 } 345 } 346 347 /* 348 * Encode 'value' of datetime type 'typid' into JSON string in ISO format using 349 * optionally preallocated buffer 'buf'. Optional 'tzp' determines time-zone 350 * offset (in seconds) in which we want to show timestamptz. 351 */ 352 char * 353 JsonEncodeDateTime(char *buf, Datum value, Oid typid, const int *tzp) 354 { 355 if (!buf) 356 buf = palloc(MAXDATELEN + 1); 357 358 switch (typid) 359 { 360 case DATEOID: 361 { 362 DateADT date; 363 struct pg_tm tm; 364 365 date = DatumGetDateADT(value); 366 367 /* Same as date_out(), but forcing DateStyle */ 368 if (DATE_NOT_FINITE(date)) 369 EncodeSpecialDate(date, buf); 370 else 371 { 372 j2date(date + POSTGRES_EPOCH_JDATE, 373 &(tm.tm_year), &(tm.tm_mon), &(tm.tm_mday)); 374 EncodeDateOnly(&tm, USE_XSD_DATES, buf); 375 } 376 } 377 break; 378 case TIMEOID: 379 { 380 TimeADT time = DatumGetTimeADT(value); 381 struct pg_tm tt, 382 *tm = &tt; 383 fsec_t fsec; 384 385 /* Same as time_out(), but forcing DateStyle */ 386 time2tm(time, tm, &fsec); 387 EncodeTimeOnly(tm, fsec, false, 0, USE_XSD_DATES, buf); 388 } 389 break; 390 case TIMETZOID: 391 { 392 TimeTzADT *time = DatumGetTimeTzADTP(value); 393 struct pg_tm tt, 394 *tm = &tt; 395 fsec_t fsec; 396 int tz; 397 398 /* Same as timetz_out(), but forcing DateStyle */ 399 timetz2tm(time, tm, &fsec, &tz); 400 EncodeTimeOnly(tm, fsec, true, tz, USE_XSD_DATES, buf); 401 } 402 break; 403 case TIMESTAMPOID: 404 { 405 Timestamp timestamp; 406 struct pg_tm tm; 407 fsec_t fsec; 408 409 timestamp = DatumGetTimestamp(value); 410 /* Same as timestamp_out(), but forcing DateStyle */ 411 if (TIMESTAMP_NOT_FINITE(timestamp)) 412 EncodeSpecialTimestamp(timestamp, buf); 413 else if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, NULL) == 0) 414 EncodeDateTime(&tm, fsec, false, 0, NULL, USE_XSD_DATES, buf); 415 else 416 ereport(ERROR, 417 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), 418 errmsg("timestamp out of range"))); 419 } 420 break; 421 case TIMESTAMPTZOID: 422 { 423 TimestampTz timestamp; 424 struct pg_tm tm; 425 int tz; 426 fsec_t fsec; 427 const char *tzn = NULL; 428 429 timestamp = DatumGetTimestampTz(value); 430 431 /* 432 * If a time zone is specified, we apply the time-zone shift, 433 * convert timestamptz to pg_tm as if it were without a time 434 * zone, and then use the specified time zone for converting 435 * the timestamp into a string. 436 */ 437 if (tzp) 438 { 439 tz = *tzp; 440 timestamp -= (TimestampTz) tz * USECS_PER_SEC; 441 } 442 443 /* Same as timestamptz_out(), but forcing DateStyle */ 444 if (TIMESTAMP_NOT_FINITE(timestamp)) 445 EncodeSpecialTimestamp(timestamp, buf); 446 else if (timestamp2tm(timestamp, tzp ? NULL : &tz, &tm, &fsec, 447 tzp ? NULL : &tzn, NULL) == 0) 448 { 449 if (tzp) 450 tm.tm_isdst = 1; /* set time-zone presence flag */ 451 452 EncodeDateTime(&tm, fsec, true, tz, tzn, USE_XSD_DATES, buf); 453 } 454 else 455 ereport(ERROR, 456 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), 457 errmsg("timestamp out of range"))); 458 } 459 break; 460 default: 461 elog(ERROR, "unknown jsonb value datetime type oid %d", typid); 462 return NULL; 463 } 464 465 return buf; 466 } 467 468 /* 469 * Process a single dimension of an array. 470 * If it's the innermost dimension, output the values, otherwise call 471 * ourselves recursively to process the next dimension. 472 */ 473 static void 474 array_dim_to_json(StringInfo result, int dim, int ndims, int *dims, Datum *vals, 475 bool *nulls, int *valcount, JsonTypeCategory tcategory, 476 Oid outfuncoid, bool use_line_feeds) 477 { 478 int i; 479 const char *sep; 480 481 Assert(dim < ndims); 482 483 sep = use_line_feeds ? ",\n " : ","; 484 485 appendStringInfoChar(result, '['); 486 487 for (i = 1; i <= dims[dim]; i++) 488 { 489 if (i > 1) 490 appendStringInfoString(result, sep); 491 492 if (dim + 1 == ndims) 493 { 494 datum_to_json(vals[*valcount], nulls[*valcount], result, tcategory, 495 outfuncoid, false); 496 (*valcount)++; 497 } 498 else 499 { 500 /* 501 * Do we want line feeds on inner dimensions of arrays? For now 502 * we'll say no. 503 */ 504 array_dim_to_json(result, dim + 1, ndims, dims, vals, nulls, 505 valcount, tcategory, outfuncoid, false); 506 } 507 } 508 509 appendStringInfoChar(result, ']'); 510 } 511 512 /* 513 * Turn an array into JSON. 514 */ 515 static void 516 array_to_json_internal(Datum array, StringInfo result, bool use_line_feeds) 517 { 518 ArrayType *v = DatumGetArrayTypeP(array); 519 Oid element_type = ARR_ELEMTYPE(v); 520 int *dim; 521 int ndim; 522 int nitems; 523 int count = 0; 524 Datum *elements; 525 bool *nulls; 526 int16 typlen; 527 bool typbyval; 528 char typalign; 529 JsonTypeCategory tcategory; 530 Oid outfuncoid; 531 532 ndim = ARR_NDIM(v); 533 dim = ARR_DIMS(v); 534 nitems = ArrayGetNItems(ndim, dim); 535 536 if (nitems <= 0) 537 { 538 appendStringInfoString(result, "[]"); 539 return; 540 } 541 542 get_typlenbyvalalign(element_type, 543 &typlen, &typbyval, &typalign); 544 545 json_categorize_type(element_type, 546 &tcategory, &outfuncoid); 547 548 deconstruct_array(v, element_type, typlen, typbyval, 549 typalign, &elements, &nulls, 550 &nitems); 551 552 array_dim_to_json(result, 0, ndim, dim, elements, nulls, &count, tcategory, 553 outfuncoid, use_line_feeds); 554 555 pfree(elements); 556 pfree(nulls); 557 } 558 559 /* 560 * Turn a composite / record into JSON. 561 */ 562 static void 563 composite_to_json(Datum composite, StringInfo result, bool use_line_feeds) 564 { 565 HeapTupleHeader td; 566 Oid tupType; 567 int32 tupTypmod; 568 TupleDesc tupdesc; 569 HeapTupleData tmptup, 570 *tuple; 571 int i; 572 bool needsep = false; 573 const char *sep; 574 575 sep = use_line_feeds ? ",\n " : ","; 576 577 td = DatumGetHeapTupleHeader(composite); 578 579 /* Extract rowtype info and find a tupdesc */ 580 tupType = HeapTupleHeaderGetTypeId(td); 581 tupTypmod = HeapTupleHeaderGetTypMod(td); 582 tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod); 583 584 /* Build a temporary HeapTuple control structure */ 585 tmptup.t_len = HeapTupleHeaderGetDatumLength(td); 586 tmptup.t_data = td; 587 tuple = &tmptup; 588 589 appendStringInfoChar(result, '{'); 590 591 for (i = 0; i < tupdesc->natts; i++) 592 { 593 Datum val; 594 bool isnull; 595 char *attname; 596 JsonTypeCategory tcategory; 597 Oid outfuncoid; 598 Form_pg_attribute att = TupleDescAttr(tupdesc, i); 599 600 if (att->attisdropped) 601 continue; 602 603 if (needsep) 604 appendStringInfoString(result, sep); 605 needsep = true; 606 607 attname = NameStr(att->attname); 608 escape_json(result, attname); 609 appendStringInfoChar(result, ':'); 610 611 val = heap_getattr(tuple, i + 1, tupdesc, &isnull); 612 613 if (isnull) 614 { 615 tcategory = JSONTYPE_NULL; 616 outfuncoid = InvalidOid; 617 } 618 else 619 json_categorize_type(att->atttypid, &tcategory, &outfuncoid); 620 621 datum_to_json(val, isnull, result, tcategory, outfuncoid, false); 622 } 623 624 appendStringInfoChar(result, '}'); 625 ReleaseTupleDesc(tupdesc); 626 } 627 628 /* 629 * Append JSON text for "val" to "result". 630 * 631 * This is just a thin wrapper around datum_to_json. If the same type will be 632 * printed many times, avoid using this; better to do the json_categorize_type 633 * lookups only once. 634 */ 635 static void 636 add_json(Datum val, bool is_null, StringInfo result, 637 Oid val_type, bool key_scalar) 638 { 639 JsonTypeCategory tcategory; 640 Oid outfuncoid; 641 642 if (val_type == InvalidOid) 643 ereport(ERROR, 644 (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 645 errmsg("could not determine input data type"))); 646 647 if (is_null) 648 { 649 tcategory = JSONTYPE_NULL; 650 outfuncoid = InvalidOid; 651 } 652 else 653 json_categorize_type(val_type, 654 &tcategory, &outfuncoid); 655 656 datum_to_json(val, is_null, result, tcategory, outfuncoid, key_scalar); 657 } 658 659 /* 660 * SQL function array_to_json(row) 661 */ 662 Datum 663 array_to_json(PG_FUNCTION_ARGS) 664 { 665 Datum array = PG_GETARG_DATUM(0); 666 StringInfo result; 667 668 result = makeStringInfo(); 669 670 array_to_json_internal(array, result, false); 671 672 PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len)); 673 } 674 675 /* 676 * SQL function array_to_json(row, prettybool) 677 */ 678 Datum 679 array_to_json_pretty(PG_FUNCTION_ARGS) 680 { 681 Datum array = PG_GETARG_DATUM(0); 682 bool use_line_feeds = PG_GETARG_BOOL(1); 683 StringInfo result; 684 685 result = makeStringInfo(); 686 687 array_to_json_internal(array, result, use_line_feeds); 688 689 PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len)); 690 } 691 692 /* 693 * SQL function row_to_json(row) 694 */ 695 Datum 696 row_to_json(PG_FUNCTION_ARGS) 697 { 698 Datum array = PG_GETARG_DATUM(0); 699 StringInfo result; 700 701 result = makeStringInfo(); 702 703 composite_to_json(array, result, false); 704 705 PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len)); 706 } 707 708 /* 709 * SQL function row_to_json(row, prettybool) 710 */ 711 Datum 712 row_to_json_pretty(PG_FUNCTION_ARGS) 713 { 714 Datum array = PG_GETARG_DATUM(0); 715 bool use_line_feeds = PG_GETARG_BOOL(1); 716 StringInfo result; 717 718 result = makeStringInfo(); 719 720 composite_to_json(array, result, use_line_feeds); 721 722 PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len)); 723 } 724 725 /* 726 * SQL function to_json(anyvalue) 727 */ 728 Datum 729 to_json(PG_FUNCTION_ARGS) 730 { 731 Datum val = PG_GETARG_DATUM(0); 732 Oid val_type = get_fn_expr_argtype(fcinfo->flinfo, 0); 733 StringInfo result; 734 JsonTypeCategory tcategory; 735 Oid outfuncoid; 736 737 if (val_type == InvalidOid) 738 ereport(ERROR, 739 (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 740 errmsg("could not determine input data type"))); 741 742 json_categorize_type(val_type, 743 &tcategory, &outfuncoid); 744 745 result = makeStringInfo(); 746 747 datum_to_json(val, false, result, tcategory, outfuncoid, false); 748 749 PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len)); 750 } 751 752 /* 753 * json_agg transition function 754 * 755 * aggregate input column as a json array value. 756 */ 757 Datum 758 json_agg_transfn(PG_FUNCTION_ARGS) 759 { 760 MemoryContext aggcontext, 761 oldcontext; 762 JsonAggState *state; 763 Datum val; 764 765 if (!AggCheckCallContext(fcinfo, &aggcontext)) 766 { 767 /* cannot be called directly because of internal-type argument */ 768 elog(ERROR, "json_agg_transfn called in non-aggregate context"); 769 } 770 771 if (PG_ARGISNULL(0)) 772 { 773 Oid arg_type = get_fn_expr_argtype(fcinfo->flinfo, 1); 774 775 if (arg_type == InvalidOid) 776 ereport(ERROR, 777 (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 778 errmsg("could not determine input data type"))); 779 780 /* 781 * Make this state object in a context where it will persist for the 782 * duration of the aggregate call. MemoryContextSwitchTo is only 783 * needed the first time, as the StringInfo routines make sure they 784 * use the right context to enlarge the object if necessary. 785 */ 786 oldcontext = MemoryContextSwitchTo(aggcontext); 787 state = (JsonAggState *) palloc(sizeof(JsonAggState)); 788 state->str = makeStringInfo(); 789 MemoryContextSwitchTo(oldcontext); 790 791 appendStringInfoChar(state->str, '['); 792 json_categorize_type(arg_type, &state->val_category, 793 &state->val_output_func); 794 } 795 else 796 { 797 state = (JsonAggState *) PG_GETARG_POINTER(0); 798 appendStringInfoString(state->str, ", "); 799 } 800 801 /* fast path for NULLs */ 802 if (PG_ARGISNULL(1)) 803 { 804 datum_to_json((Datum) 0, true, state->str, JSONTYPE_NULL, 805 InvalidOid, false); 806 PG_RETURN_POINTER(state); 807 } 808 809 val = PG_GETARG_DATUM(1); 810 811 /* add some whitespace if structured type and not first item */ 812 if (!PG_ARGISNULL(0) && 813 (state->val_category == JSONTYPE_ARRAY || 814 state->val_category == JSONTYPE_COMPOSITE)) 815 { 816 appendStringInfoString(state->str, "\n "); 817 } 818 819 datum_to_json(val, false, state->str, state->val_category, 820 state->val_output_func, false); 821 822 /* 823 * The transition type for json_agg() is declared to be "internal", which 824 * is a pass-by-value type the same size as a pointer. So we can safely 825 * pass the JsonAggState pointer through nodeAgg.c's machinations. 826 */ 827 PG_RETURN_POINTER(state); 828 } 829 830 /* 831 * json_agg final function 832 */ 833 Datum 834 json_agg_finalfn(PG_FUNCTION_ARGS) 835 { 836 JsonAggState *state; 837 838 /* cannot be called directly because of internal-type argument */ 839 Assert(AggCheckCallContext(fcinfo, NULL)); 840 841 state = PG_ARGISNULL(0) ? 842 NULL : 843 (JsonAggState *) PG_GETARG_POINTER(0); 844 845 /* NULL result for no rows in, as is standard with aggregates */ 846 if (state == NULL) 847 PG_RETURN_NULL(); 848 849 /* Else return state with appropriate array terminator added */ 850 PG_RETURN_TEXT_P(catenate_stringinfo_string(state->str, "]")); 851 } 852 853 /* 854 * json_object_agg transition function. 855 * 856 * aggregate two input columns as a single json object value. 857 */ 858 Datum 859 json_object_agg_transfn(PG_FUNCTION_ARGS) 860 { 861 MemoryContext aggcontext, 862 oldcontext; 863 JsonAggState *state; 864 Datum arg; 865 866 if (!AggCheckCallContext(fcinfo, &aggcontext)) 867 { 868 /* cannot be called directly because of internal-type argument */ 869 elog(ERROR, "json_object_agg_transfn called in non-aggregate context"); 870 } 871 872 if (PG_ARGISNULL(0)) 873 { 874 Oid arg_type; 875 876 /* 877 * Make the StringInfo in a context where it will persist for the 878 * duration of the aggregate call. Switching context is only needed 879 * for this initial step, as the StringInfo routines make sure they 880 * use the right context to enlarge the object if necessary. 881 */ 882 oldcontext = MemoryContextSwitchTo(aggcontext); 883 state = (JsonAggState *) palloc(sizeof(JsonAggState)); 884 state->str = makeStringInfo(); 885 MemoryContextSwitchTo(oldcontext); 886 887 arg_type = get_fn_expr_argtype(fcinfo->flinfo, 1); 888 889 if (arg_type == InvalidOid) 890 ereport(ERROR, 891 (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 892 errmsg("could not determine data type for argument %d", 1))); 893 894 json_categorize_type(arg_type, &state->key_category, 895 &state->key_output_func); 896 897 arg_type = get_fn_expr_argtype(fcinfo->flinfo, 2); 898 899 if (arg_type == InvalidOid) 900 ereport(ERROR, 901 (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 902 errmsg("could not determine data type for argument %d", 2))); 903 904 json_categorize_type(arg_type, &state->val_category, 905 &state->val_output_func); 906 907 appendStringInfoString(state->str, "{ "); 908 } 909 else 910 { 911 state = (JsonAggState *) PG_GETARG_POINTER(0); 912 appendStringInfoString(state->str, ", "); 913 } 914 915 /* 916 * Note: since json_object_agg() is declared as taking type "any", the 917 * parser will not do any type conversion on unknown-type literals (that 918 * is, undecorated strings or NULLs). Such values will arrive here as 919 * type UNKNOWN, which fortunately does not matter to us, since 920 * unknownout() works fine. 921 */ 922 923 if (PG_ARGISNULL(1)) 924 ereport(ERROR, 925 (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 926 errmsg("field name must not be null"))); 927 928 arg = PG_GETARG_DATUM(1); 929 930 datum_to_json(arg, false, state->str, state->key_category, 931 state->key_output_func, true); 932 933 appendStringInfoString(state->str, " : "); 934 935 if (PG_ARGISNULL(2)) 936 arg = (Datum) 0; 937 else 938 arg = PG_GETARG_DATUM(2); 939 940 datum_to_json(arg, PG_ARGISNULL(2), state->str, state->val_category, 941 state->val_output_func, false); 942 943 PG_RETURN_POINTER(state); 944 } 945 946 /* 947 * json_object_agg final function. 948 */ 949 Datum 950 json_object_agg_finalfn(PG_FUNCTION_ARGS) 951 { 952 JsonAggState *state; 953 954 /* cannot be called directly because of internal-type argument */ 955 Assert(AggCheckCallContext(fcinfo, NULL)); 956 957 state = PG_ARGISNULL(0) ? NULL : (JsonAggState *) PG_GETARG_POINTER(0); 958 959 /* NULL result for no rows in, as is standard with aggregates */ 960 if (state == NULL) 961 PG_RETURN_NULL(); 962 963 /* Else return state with appropriate object terminator added */ 964 PG_RETURN_TEXT_P(catenate_stringinfo_string(state->str, " }")); 965 } 966 967 /* 968 * Helper function for aggregates: return given StringInfo's contents plus 969 * specified trailing string, as a text datum. We need this because aggregate 970 * final functions are not allowed to modify the aggregate state. 971 */ 972 static text * 973 catenate_stringinfo_string(StringInfo buffer, const char *addon) 974 { 975 /* custom version of cstring_to_text_with_len */ 976 int buflen = buffer->len; 977 int addlen = strlen(addon); 978 text *result = (text *) palloc(buflen + addlen + VARHDRSZ); 979 980 SET_VARSIZE(result, buflen + addlen + VARHDRSZ); 981 memcpy(VARDATA(result), buffer->data, buflen); 982 memcpy(VARDATA(result) + buflen, addon, addlen); 983 984 return result; 985 } 986 987 /* 988 * SQL function json_build_object(variadic "any") 989 */ 990 Datum 991 json_build_object(PG_FUNCTION_ARGS) 992 { 993 int nargs = PG_NARGS(); 994 int i; 995 const char *sep = ""; 996 StringInfo result; 997 Datum *args; 998 bool *nulls; 999 Oid *types; 1000 1001 /* fetch argument values to build the object */ 1002 nargs = extract_variadic_args(fcinfo, 0, false, &args, &types, &nulls); 1003 1004 if (nargs < 0) 1005 PG_RETURN_NULL(); 1006 1007 if (nargs % 2 != 0) 1008 ereport(ERROR, 1009 (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 1010 errmsg("argument list must have even number of elements"), 1011 /* translator: %s is a SQL function name */ 1012 errhint("The arguments of %s must consist of alternating keys and values.", 1013 "json_build_object()"))); 1014 1015 result = makeStringInfo(); 1016 1017 appendStringInfoChar(result, '{'); 1018 1019 for (i = 0; i < nargs; i += 2) 1020 { 1021 appendStringInfoString(result, sep); 1022 sep = ", "; 1023 1024 /* process key */ 1025 if (nulls[i]) 1026 ereport(ERROR, 1027 (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 1028 errmsg("argument %d cannot be null", i + 1), 1029 errhint("Object keys should be text."))); 1030 1031 add_json(args[i], false, result, types[i], true); 1032 1033 appendStringInfoString(result, " : "); 1034 1035 /* process value */ 1036 add_json(args[i + 1], nulls[i + 1], result, types[i + 1], false); 1037 } 1038 1039 appendStringInfoChar(result, '}'); 1040 1041 PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len)); 1042 } 1043 1044 /* 1045 * degenerate case of json_build_object where it gets 0 arguments. 1046 */ 1047 Datum 1048 json_build_object_noargs(PG_FUNCTION_ARGS) 1049 { 1050 PG_RETURN_TEXT_P(cstring_to_text_with_len("{}", 2)); 1051 } 1052 1053 /* 1054 * SQL function json_build_array(variadic "any") 1055 */ 1056 Datum 1057 json_build_array(PG_FUNCTION_ARGS) 1058 { 1059 int nargs; 1060 int i; 1061 const char *sep = ""; 1062 StringInfo result; 1063 Datum *args; 1064 bool *nulls; 1065 Oid *types; 1066 1067 /* fetch argument values to build the array */ 1068 nargs = extract_variadic_args(fcinfo, 0, false, &args, &types, &nulls); 1069 1070 if (nargs < 0) 1071 PG_RETURN_NULL(); 1072 1073 result = makeStringInfo(); 1074 1075 appendStringInfoChar(result, '['); 1076 1077 for (i = 0; i < nargs; i++) 1078 { 1079 appendStringInfoString(result, sep); 1080 sep = ", "; 1081 add_json(args[i], nulls[i], result, types[i], false); 1082 } 1083 1084 appendStringInfoChar(result, ']'); 1085 1086 PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len)); 1087 } 1088 1089 /* 1090 * degenerate case of json_build_array where it gets 0 arguments. 1091 */ 1092 Datum 1093 json_build_array_noargs(PG_FUNCTION_ARGS) 1094 { 1095 PG_RETURN_TEXT_P(cstring_to_text_with_len("[]", 2)); 1096 } 1097 1098 /* 1099 * SQL function json_object(text[]) 1100 * 1101 * take a one or two dimensional array of text as key/value pairs 1102 * for a json object. 1103 */ 1104 Datum 1105 json_object(PG_FUNCTION_ARGS) 1106 { 1107 ArrayType *in_array = PG_GETARG_ARRAYTYPE_P(0); 1108 int ndims = ARR_NDIM(in_array); 1109 StringInfoData result; 1110 Datum *in_datums; 1111 bool *in_nulls; 1112 int in_count, 1113 count, 1114 i; 1115 text *rval; 1116 char *v; 1117 1118 switch (ndims) 1119 { 1120 case 0: 1121 PG_RETURN_DATUM(CStringGetTextDatum("{}")); 1122 break; 1123 1124 case 1: 1125 if ((ARR_DIMS(in_array)[0]) % 2) 1126 ereport(ERROR, 1127 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), 1128 errmsg("array must have even number of elements"))); 1129 break; 1130 1131 case 2: 1132 if ((ARR_DIMS(in_array)[1]) != 2) 1133 ereport(ERROR, 1134 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), 1135 errmsg("array must have two columns"))); 1136 break; 1137 1138 default: 1139 ereport(ERROR, 1140 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), 1141 errmsg("wrong number of array subscripts"))); 1142 } 1143 1144 deconstruct_array(in_array, 1145 TEXTOID, -1, false, TYPALIGN_INT, 1146 &in_datums, &in_nulls, &in_count); 1147 1148 count = in_count / 2; 1149 1150 initStringInfo(&result); 1151 1152 appendStringInfoChar(&result, '{'); 1153 1154 for (i = 0; i < count; ++i) 1155 { 1156 if (in_nulls[i * 2]) 1157 ereport(ERROR, 1158 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), 1159 errmsg("null value not allowed for object key"))); 1160 1161 v = TextDatumGetCString(in_datums[i * 2]); 1162 if (i > 0) 1163 appendStringInfoString(&result, ", "); 1164 escape_json(&result, v); 1165 appendStringInfoString(&result, " : "); 1166 pfree(v); 1167 if (in_nulls[i * 2 + 1]) 1168 appendStringInfoString(&result, "null"); 1169 else 1170 { 1171 v = TextDatumGetCString(in_datums[i * 2 + 1]); 1172 escape_json(&result, v); 1173 pfree(v); 1174 } 1175 } 1176 1177 appendStringInfoChar(&result, '}'); 1178 1179 pfree(in_datums); 1180 pfree(in_nulls); 1181 1182 rval = cstring_to_text_with_len(result.data, result.len); 1183 pfree(result.data); 1184 1185 PG_RETURN_TEXT_P(rval); 1186 1187 } 1188 1189 /* 1190 * SQL function json_object(text[], text[]) 1191 * 1192 * take separate key and value arrays of text to construct a json object 1193 * pairwise. 1194 */ 1195 Datum 1196 json_object_two_arg(PG_FUNCTION_ARGS) 1197 { 1198 ArrayType *key_array = PG_GETARG_ARRAYTYPE_P(0); 1199 ArrayType *val_array = PG_GETARG_ARRAYTYPE_P(1); 1200 int nkdims = ARR_NDIM(key_array); 1201 int nvdims = ARR_NDIM(val_array); 1202 StringInfoData result; 1203 Datum *key_datums, 1204 *val_datums; 1205 bool *key_nulls, 1206 *val_nulls; 1207 int key_count, 1208 val_count, 1209 i; 1210 text *rval; 1211 char *v; 1212 1213 if (nkdims > 1 || nkdims != nvdims) 1214 ereport(ERROR, 1215 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), 1216 errmsg("wrong number of array subscripts"))); 1217 1218 if (nkdims == 0) 1219 PG_RETURN_DATUM(CStringGetTextDatum("{}")); 1220 1221 deconstruct_array(key_array, 1222 TEXTOID, -1, false, TYPALIGN_INT, 1223 &key_datums, &key_nulls, &key_count); 1224 1225 deconstruct_array(val_array, 1226 TEXTOID, -1, false, TYPALIGN_INT, 1227 &val_datums, &val_nulls, &val_count); 1228 1229 if (key_count != val_count) 1230 ereport(ERROR, 1231 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), 1232 errmsg("mismatched array dimensions"))); 1233 1234 initStringInfo(&result); 1235 1236 appendStringInfoChar(&result, '{'); 1237 1238 for (i = 0; i < key_count; ++i) 1239 { 1240 if (key_nulls[i]) 1241 ereport(ERROR, 1242 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), 1243 errmsg("null value not allowed for object key"))); 1244 1245 v = TextDatumGetCString(key_datums[i]); 1246 if (i > 0) 1247 appendStringInfoString(&result, ", "); 1248 escape_json(&result, v); 1249 appendStringInfoString(&result, " : "); 1250 pfree(v); 1251 if (val_nulls[i]) 1252 appendStringInfoString(&result, "null"); 1253 else 1254 { 1255 v = TextDatumGetCString(val_datums[i]); 1256 escape_json(&result, v); 1257 pfree(v); 1258 } 1259 } 1260 1261 appendStringInfoChar(&result, '}'); 1262 1263 pfree(key_datums); 1264 pfree(key_nulls); 1265 pfree(val_datums); 1266 pfree(val_nulls); 1267 1268 rval = cstring_to_text_with_len(result.data, result.len); 1269 pfree(result.data); 1270 1271 PG_RETURN_TEXT_P(rval); 1272 } 1273 1274 1275 /* 1276 * Produce a JSON string literal, properly escaping characters in the text. 1277 */ 1278 void 1279 escape_json(StringInfo buf, const char *str) 1280 { 1281 const char *p; 1282 1283 appendStringInfoCharMacro(buf, '"'); 1284 for (p = str; *p; p++) 1285 { 1286 switch (*p) 1287 { 1288 case '\b': 1289 appendStringInfoString(buf, "\\b"); 1290 break; 1291 case '\f': 1292 appendStringInfoString(buf, "\\f"); 1293 break; 1294 case '\n': 1295 appendStringInfoString(buf, "\\n"); 1296 break; 1297 case '\r': 1298 appendStringInfoString(buf, "\\r"); 1299 break; 1300 case '\t': 1301 appendStringInfoString(buf, "\\t"); 1302 break; 1303 case '"': 1304 appendStringInfoString(buf, "\\\""); 1305 break; 1306 case '\\': 1307 appendStringInfoString(buf, "\\\\"); 1308 break; 1309 default: 1310 if ((unsigned char) *p < ' ') 1311 appendStringInfo(buf, "\\u%04x", (int) *p); 1312 else 1313 appendStringInfoCharMacro(buf, *p); 1314 break; 1315 } 1316 } 1317 appendStringInfoCharMacro(buf, '"'); 1318 } 1319 1320 /* 1321 * SQL function json_typeof(json) -> text 1322 * 1323 * Returns the type of the outermost JSON value as TEXT. Possible types are 1324 * "object", "array", "string", "number", "boolean", and "null". 1325 * 1326 * Performs a single call to json_lex() to get the first token of the supplied 1327 * value. This initial token uniquely determines the value's type. As our 1328 * input must already have been validated by json_in() or json_recv(), the 1329 * initial token should never be JSON_TOKEN_OBJECT_END, JSON_TOKEN_ARRAY_END, 1330 * JSON_TOKEN_COLON, JSON_TOKEN_COMMA, or JSON_TOKEN_END. 1331 */ 1332 Datum 1333 json_typeof(PG_FUNCTION_ARGS) 1334 { 1335 text *json; 1336 1337 JsonLexContext *lex; 1338 JsonTokenType tok; 1339 char *type; 1340 JsonParseErrorType result; 1341 1342 json = PG_GETARG_TEXT_PP(0); 1343 lex = makeJsonLexContext(json, false); 1344 1345 /* Lex exactly one token from the input and check its type. */ 1346 result = json_lex(lex); 1347 if (result != JSON_SUCCESS) 1348 json_ereport_error(result, lex); 1349 tok = lex->token_type; 1350 switch (tok) 1351 { 1352 case JSON_TOKEN_OBJECT_START: 1353 type = "object"; 1354 break; 1355 case JSON_TOKEN_ARRAY_START: 1356 type = "array"; 1357 break; 1358 case JSON_TOKEN_STRING: 1359 type = "string"; 1360 break; 1361 case JSON_TOKEN_NUMBER: 1362 type = "number"; 1363 break; 1364 case JSON_TOKEN_TRUE: 1365 case JSON_TOKEN_FALSE: 1366 type = "boolean"; 1367 break; 1368 case JSON_TOKEN_NULL: 1369 type = "null"; 1370 break; 1371 default: 1372 elog(ERROR, "unexpected json token: %d", tok); 1373 } 1374 1375 PG_RETURN_TEXT_P(cstring_to_text(type)); 1376 } 1377