|
34 | 34 | #include "parser/parse_type.h" |
35 | 35 | #include "utils/builtins.h" |
36 | 36 | #include "utils/date.h" |
| 37 | +#include "utils/fmgroids.h" |
37 | 38 | #include "utils/lsyscache.h" |
38 | 39 | #include "utils/timestamp.h" |
39 | 40 | #include "utils/xml.h" |
@@ -3569,3 +3570,159 @@ ParseExprKindName(ParseExprKind exprKind) |
3569 | 3570 | } |
3570 | 3571 | return "unrecognized expression kind"; |
3571 | 3572 | } |
| 3573 | + |
| 3574 | +/* |
| 3575 | + * Make string Const node from JSON encoding name. |
| 3576 | + * |
| 3577 | + * UTF8 is default encoding. |
| 3578 | + */ |
| 3579 | +static Const * |
| 3580 | +getJsonEncodingConst(JsonFormat *format) |
| 3581 | +{ |
| 3582 | + JsonEncoding encoding; |
| 3583 | + const char *enc; |
| 3584 | + Name encname = palloc(sizeof(NameData)); |
| 3585 | + |
| 3586 | + if (!format || |
| 3587 | + format->type == JS_FORMAT_DEFAULT || |
| 3588 | + format->encoding == JS_ENC_DEFAULT) |
| 3589 | + encoding = JS_ENC_UTF8; |
| 3590 | + else |
| 3591 | + encoding = format->encoding; |
| 3592 | + |
| 3593 | + switch (encoding) |
| 3594 | + { |
| 3595 | + case JS_ENC_UTF16: |
| 3596 | + enc = "UTF16"; |
| 3597 | + break; |
| 3598 | + case JS_ENC_UTF32: |
| 3599 | + enc = "UTF32"; |
| 3600 | + break; |
| 3601 | + case JS_ENC_UTF8: |
| 3602 | + default: |
| 3603 | + enc = "UTF8"; |
| 3604 | + break; |
| 3605 | + } |
| 3606 | + |
| 3607 | + namestrcpy(encname, enc); |
| 3608 | + |
| 3609 | + return makeConst(NAMEOID, -1, InvalidOid, NAMEDATALEN, |
| 3610 | + NameGetDatum(encname), false, false); |
| 3611 | +} |
| 3612 | + |
| 3613 | +/* |
| 3614 | + * Make bytea => text conversion using specified JSON format encoding. |
| 3615 | + */ |
| 3616 | +static Node * |
| 3617 | +makeJsonByteaToTextConversion(Node *expr, JsonFormat *format, int location) |
| 3618 | +{ |
| 3619 | + Const *encoding = getJsonEncodingConst(format); |
| 3620 | + FuncExpr *fexpr = makeFuncExpr(F_PG_CONVERT_FROM, TEXTOID, |
| 3621 | + list_make2(expr, encoding), |
| 3622 | + InvalidOid, InvalidOid, |
| 3623 | + COERCE_INTERNAL_CAST); |
| 3624 | + |
| 3625 | + fexpr->location = location; |
| 3626 | + |
| 3627 | + return (Node *) fexpr; |
| 3628 | +} |
| 3629 | + |
| 3630 | +/* |
| 3631 | + * Transform JSON value expression using specified input JSON format or |
| 3632 | + * default format otherwise. |
| 3633 | + */ |
| 3634 | +static Node * |
| 3635 | +transformJsonValueExpr(ParseState *pstate, JsonValueExpr *ve, |
| 3636 | + JsonFormatType default_format) |
| 3637 | +{ |
| 3638 | + Node *expr = transformExprRecurse(pstate, (Node *) ve->expr); |
| 3639 | + JsonFormatType format; |
| 3640 | + Oid exprtype; |
| 3641 | + int location; |
| 3642 | + char typcategory; |
| 3643 | + bool typispreferred; |
| 3644 | + |
| 3645 | + if (exprType(expr) == UNKNOWNOID) |
| 3646 | + expr = coerce_to_specific_type(pstate, expr, TEXTOID, "JSON_VALUE_EXPR"); |
| 3647 | + |
| 3648 | + exprtype = exprType(expr); |
| 3649 | + location = exprLocation(expr); |
| 3650 | + |
| 3651 | + get_type_category_preferred(exprtype, &typcategory, &typispreferred); |
| 3652 | + |
| 3653 | + if (ve->format.type != JS_FORMAT_DEFAULT) |
| 3654 | + { |
| 3655 | + if (ve->format.encoding != JS_ENC_DEFAULT && exprtype != BYTEAOID) |
| 3656 | + ereport(ERROR, |
| 3657 | + (errcode(ERRCODE_DATATYPE_MISMATCH), |
| 3658 | + errmsg("JSON ENCODING clause is only allowed for bytea input type"), |
| 3659 | + parser_errposition(pstate, ve->format.location))); |
| 3660 | + |
| 3661 | + if (exprtype == JSONOID || exprtype == JSONBOID) |
| 3662 | + { |
| 3663 | + format = JS_FORMAT_DEFAULT; /* do not format json[b] types */ |
| 3664 | + ereport(WARNING, |
| 3665 | + (errmsg("FORMAT JSON has no effect for json and jsonb types"), |
| 3666 | + parser_errposition(pstate, ve->format->location))); |
| 3667 | + } |
| 3668 | + else |
| 3669 | + format = ve->format.type; |
| 3670 | + } |
| 3671 | + else if (exprtype == JSONOID || exprtype == JSONBOID) |
| 3672 | + format = JS_FORMAT_DEFAULT; /* do not format json[b] types */ |
| 3673 | + else |
| 3674 | + format = default_format; |
| 3675 | + |
| 3676 | + if (format != JS_FORMAT_DEFAULT) |
| 3677 | + { |
| 3678 | + Oid targettype = format == JS_FORMAT_JSONB ? JSONBOID : JSONOID; |
| 3679 | + Node *coerced; |
| 3680 | + FuncExpr *fexpr; |
| 3681 | + |
| 3682 | + if (exprtype != BYTEAOID && typcategory != TYPCATEGORY_STRING) |
| 3683 | + ereport(ERROR, |
| 3684 | + (errcode(ERRCODE_DATATYPE_MISMATCH), |
| 3685 | + errmsg(ve->format.type == JS_FORMAT_DEFAULT ? |
| 3686 | + "cannot use non-string types with implicit FORMAT JSON clause" : |
| 3687 | + "cannot use non-string types with explicit FORMAT JSON clause"), |
| 3688 | + parser_errposition(pstate, ve->format.location >= 0 ? |
| 3689 | + ve->format.location : location))); |
| 3690 | + |
| 3691 | + /* Convert encoded JSON text from bytea. */ |
| 3692 | + if (format == JS_FORMAT_JSON && exprtype == BYTEAOID) |
| 3693 | + { |
| 3694 | + expr = makeJsonByteaToTextConversion(expr, &ve->format, location); |
| 3695 | + exprtype = TEXTOID; |
| 3696 | + } |
| 3697 | + |
| 3698 | + /* Try to coerce to the target type. */ |
| 3699 | + coerced = coerce_to_target_type(pstate, expr, exprtype, |
| 3700 | + targettype, -1, |
| 3701 | + COERCION_EXPLICIT, |
| 3702 | + COERCE_INTERNAL_CAST, |
| 3703 | + location); |
| 3704 | + |
| 3705 | + if (coerced) |
| 3706 | + expr = coerced; |
| 3707 | + else |
| 3708 | + { |
| 3709 | + /* If coercion failed, use to_json()/to_jsonb() functions. */ |
| 3710 | + Oid fnoid = targettype == JSONOID ? F_TO_JSON : F_TO_JSONB; |
| 3711 | + |
| 3712 | + fexpr = makeFuncExpr(fnoid, targettype, list_make1(expr), |
| 3713 | + InvalidOid, InvalidOid, |
| 3714 | + COERCE_INTERNAL_CAST); |
| 3715 | + fexpr->location = location; |
| 3716 | + |
| 3717 | + expr = (Node *) fexpr; |
| 3718 | + } |
| 3719 | + |
| 3720 | + ve = copyObject(ve); |
| 3721 | + ve->expr = (Expr *) expr; |
| 3722 | + |
| 3723 | + expr = (Node *) ve; |
| 3724 | + } |
| 3725 | + |
| 3726 | + return expr; |
| 3727 | +} |
| 3728 | + |
0 commit comments