|
65 | 65 | #include "executor/nodeSubplan.h" |
66 | 66 | #include "funcapi.h" |
67 | 67 | #include "miscadmin.h" |
| 68 | +#include "nodes/makefuncs.h" |
68 | 69 | #include "nodes/nodeFuncs.h" |
69 | 70 | #include "parser/parsetree.h" |
| 71 | +#include "parser/parse_expr.h" |
70 | 72 | #include "pgstat.h" |
71 | 73 | #include "utils/builtins.h" |
72 | 74 | #include "utils/date.h" |
@@ -3697,6 +3699,126 @@ EvalJsonPathVar(void *cxt, bool *isnull) |
3697 | 3699 | return ecxt->value; |
3698 | 3700 | } |
3699 | 3701 |
|
| 3702 | +Datum |
| 3703 | +ExecPrepareJsonItemCoercion(JsonbValue *jbv, JsonReturning *returning, |
| 3704 | + struct JsonScalarCoercions *coercions, |
| 3705 | + MemoryContext mcxt, |
| 3706 | + struct JsonScalarCoercionExprState **pcestate) |
| 3707 | +{ |
| 3708 | + struct JsonScalarCoercionExprState *cestate; |
| 3709 | + Datum res; |
| 3710 | + Oid typid; |
| 3711 | + JsonbValue jbvbuf; |
| 3712 | + |
| 3713 | + if (jbv->type == jbvBinary && JsonContainerIsScalar(jbv->val.binary.data)) |
| 3714 | + jbv = JsonbExtractScalar(jbv->val.binary.data, &jbvbuf); |
| 3715 | + |
| 3716 | + switch (jbv->type) |
| 3717 | + { |
| 3718 | + case jbvNull: |
| 3719 | + cestate = &coercions->null; |
| 3720 | + typid = UNKNOWNOID; |
| 3721 | + res = (Datum) 0; |
| 3722 | + break; |
| 3723 | + |
| 3724 | + case jbvString: |
| 3725 | + cestate = &coercions->string; |
| 3726 | + typid = TEXTOID; |
| 3727 | + res = PointerGetDatum( |
| 3728 | + cstring_to_text_with_len(jbv->val.string.val, |
| 3729 | + jbv->val.string.len)); |
| 3730 | + break; |
| 3731 | + |
| 3732 | + case jbvNumeric: |
| 3733 | + cestate = &coercions->numeric; |
| 3734 | + typid = NUMERICOID; |
| 3735 | + res = NumericGetDatum(jbv->val.numeric); |
| 3736 | + break; |
| 3737 | + |
| 3738 | + case jbvBool: |
| 3739 | + cestate = &coercions->boolean; |
| 3740 | + typid = BOOLOID; |
| 3741 | + res = BoolGetDatum(jbv->val.boolean); |
| 3742 | + break; |
| 3743 | + |
| 3744 | + case jbvDatetime: |
| 3745 | + res = jbv->val.datetime.value; |
| 3746 | + typid = jbv->val.datetime.typid; |
| 3747 | + switch (jbv->val.datetime.typid) |
| 3748 | + { |
| 3749 | + case DATEOID: |
| 3750 | + cestate = &coercions->date; |
| 3751 | + break; |
| 3752 | + case TIMEOID: |
| 3753 | + cestate = &coercions->time; |
| 3754 | + break; |
| 3755 | + case TIMETZOID: |
| 3756 | + cestate = &coercions->timetz; |
| 3757 | + break; |
| 3758 | + case TIMESTAMPOID: |
| 3759 | + cestate = &coercions->timestamp; |
| 3760 | + break; |
| 3761 | + case TIMESTAMPTZOID: |
| 3762 | + cestate = &coercions->timestamptz; |
| 3763 | + break; |
| 3764 | + default: |
| 3765 | + elog(ERROR, "unexpected jsonb datetime type oid %d", |
| 3766 | + jbv->val.datetime.typid); |
| 3767 | + return (Datum) 0; |
| 3768 | + } |
| 3769 | + break; |
| 3770 | + |
| 3771 | + case jbvArray: |
| 3772 | + case jbvObject: |
| 3773 | + case jbvBinary: |
| 3774 | + cestate = &coercions->composite; |
| 3775 | + res = JsonbGetDatum(JsonbValueToJsonb(jbv)); |
| 3776 | + typid = JSONBOID; |
| 3777 | + break; |
| 3778 | + |
| 3779 | + default: |
| 3780 | + elog(ERROR, "unexpected jsonb value type %d", jbv->type); |
| 3781 | + return (Datum) 0; |
| 3782 | + } |
| 3783 | + |
| 3784 | + if (!cestate->initialized) |
| 3785 | + { |
| 3786 | + MemoryContext oldCxt = MemoryContextSwitchTo(mcxt); |
| 3787 | + Node *expr; |
| 3788 | + |
| 3789 | + if (jbv->type == jbvNull) |
| 3790 | + { |
| 3791 | + expr = (Node *) makeNullConst(UNKNOWNOID, -1, InvalidOid); |
| 3792 | + } |
| 3793 | + else |
| 3794 | + { |
| 3795 | + CaseTestExpr *placeholder = makeNode(CaseTestExpr); |
| 3796 | + |
| 3797 | + placeholder->typeId = typid; |
| 3798 | + placeholder->typeMod = -1; |
| 3799 | + placeholder->collation = InvalidOid; |
| 3800 | + |
| 3801 | + expr = (Node *) placeholder; |
| 3802 | + } |
| 3803 | + |
| 3804 | + cestate->result_expr = |
| 3805 | + coerceJsonExpr(NULL, expr, returning, |
| 3806 | + &cestate->coerce_via_io, |
| 3807 | + &cestate->coerce_via_populate); |
| 3808 | + |
| 3809 | + cestate->result_expr_state = |
| 3810 | + ExecInitExpr((Expr *) cestate->result_expr, NULL); |
| 3811 | + |
| 3812 | + MemoryContextSwitchTo(oldCxt); |
| 3813 | + |
| 3814 | + cestate->initialized = true; |
| 3815 | + } |
| 3816 | + |
| 3817 | + *pcestate = cestate; |
| 3818 | + |
| 3819 | + return res; |
| 3820 | +} |
| 3821 | + |
3700 | 3822 | /* ---------------------------------------------------------------- |
3701 | 3823 | * ExecEvalJson |
3702 | 3824 | * ---------------------------------------------------------------- |
@@ -3763,8 +3885,40 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext) |
3763 | 3885 | break; |
3764 | 3886 |
|
3765 | 3887 | case IS_JSON_VALUE: |
3766 | | - res = JsonbPathValue(item, path, &empty, op->d.jsonexpr.args); |
3767 | | - *op->resnull = !DatumGetPointer(res); |
| 3888 | + { |
| 3889 | + JsonbValue *jbv = JsonbPathValue(item, path, &empty, |
| 3890 | + op->d.jsonexpr.args); |
| 3891 | + struct JsonScalarCoercionExprState *cestate; |
| 3892 | + |
| 3893 | + if (!jbv) |
| 3894 | + break; |
| 3895 | + |
| 3896 | + *op->resnull = false; |
| 3897 | + |
| 3898 | + res = ExecPrepareJsonItemCoercion(jbv, |
| 3899 | + &op->d.jsonexpr.jsexpr->returning, |
| 3900 | + &op->d.jsonexpr.scalar, |
| 3901 | + econtext->ecxt_per_query_memory, |
| 3902 | + &cestate); |
| 3903 | + |
| 3904 | + if (cestate->coerce_via_io || |
| 3905 | + cestate->coerce_via_populate || /* ignored for scalars jsons */ |
| 3906 | + (cestate->result_expr && |
| 3907 | + IsA(cestate->result_expr, CoerceViaIO))) |
| 3908 | + { |
| 3909 | + res = JsonbGetDatum(JsonbValueToJsonb(jbv)); |
| 3910 | + res = ExecEvalJsonExprCoercion(op, econtext, |
| 3911 | + res, op->resnull); |
| 3912 | + } |
| 3913 | + else if (cestate->result_expr_state) |
| 3914 | + { |
| 3915 | + res = ExecEvalExprPassingCaseValue(cestate->result_expr_state, |
| 3916 | + econtext, |
| 3917 | + op->resnull, |
| 3918 | + res, false); |
| 3919 | + } |
| 3920 | + /* else no coercion */ |
| 3921 | + } |
3768 | 3922 | break; |
3769 | 3923 |
|
3770 | 3924 | case IS_JSON_EXISTS: |
@@ -3792,7 +3946,7 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext) |
3792 | 3946 | } |
3793 | 3947 |
|
3794 | 3948 | if (jexpr->op != IS_JSON_EXISTS && |
3795 | | - (!empty || |
| 3949 | + (!empty ? jexpr->op != IS_JSON_VALUE : |
3796 | 3950 | /* already coerced in DEFAULT case */ |
3797 | 3951 | jexpr->on_empty.btype != JSON_BEHAVIOR_DEFAULT)) |
3798 | 3952 | res = ExecEvalJsonExprCoercion(op, econtext, res, op->resnull); |
|
0 commit comments