|
73 | 73 | #include "utils/expandedrecord.h"
|
74 | 74 | #include "utils/json.h"
|
75 | 75 | #include "utils/jsonb.h"
|
| 76 | +#include "utils/jsonfuncs.h" |
76 | 77 | #include "utils/lsyscache.h"
|
77 | 78 | #include "utils/memutils.h"
|
78 | 79 | #include "utils/timestamp.h"
|
@@ -477,6 +478,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
|
477 | 478 | &&CASE_EEOP_HASHED_SCALARARRAYOP,
|
478 | 479 | &&CASE_EEOP_XMLEXPR,
|
479 | 480 | &&CASE_EEOP_JSON_CONSTRUCTOR,
|
| 481 | +&&CASE_EEOP_IS_JSON, |
480 | 482 | &&CASE_EEOP_AGGREF,
|
481 | 483 | &&CASE_EEOP_GROUPING_FUNC,
|
482 | 484 | &&CASE_EEOP_WINDOW_FUNC,
|
@@ -1521,6 +1523,14 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
|
1521 | 1523 | EEO_NEXT();
|
1522 | 1524 | }
|
1523 | 1525 |
|
| 1526 | +EEO_CASE(EEOP_IS_JSON) |
| 1527 | +{ |
| 1528 | +/* too complex for an inline implementation */ |
| 1529 | +ExecEvalJsonIsPredicate(state, op); |
| 1530 | + |
| 1531 | +EEO_NEXT(); |
| 1532 | +} |
| 1533 | + |
1524 | 1534 | EEO_CASE(EEOP_AGGREF)
|
1525 | 1535 | {
|
1526 | 1536 | /*
|
@@ -3921,6 +3931,95 @@ ExecEvalJsonConstructor(ExprState *state, ExprEvalStep *op,
|
3921 | 3931 | *op->resnull = isnull;
|
3922 | 3932 | }
|
3923 | 3933 |
|
| 3934 | +/* |
| 3935 | +* Evaluate a IS JSON predicate. |
| 3936 | +*/ |
| 3937 | +void |
| 3938 | +ExecEvalJsonIsPredicate(ExprState *state, ExprEvalStep *op) |
| 3939 | +{ |
| 3940 | +JsonIsPredicate *pred = op->d.is_json.pred; |
| 3941 | +Datum js = *op->resvalue; |
| 3942 | +Oid exprtype; |
| 3943 | +bool res; |
| 3944 | + |
| 3945 | +if (*op->resnull) |
| 3946 | +{ |
| 3947 | +*op->resvalue = BoolGetDatum(false); |
| 3948 | +return; |
| 3949 | +} |
| 3950 | + |
| 3951 | +exprtype = exprType(pred->expr); |
| 3952 | + |
| 3953 | +if (exprtype == TEXTOID || exprtype == JSONOID) |
| 3954 | +{ |
| 3955 | +text *json = DatumGetTextP(js); |
| 3956 | + |
| 3957 | +if (pred->item_type == JS_TYPE_ANY) |
| 3958 | +res = true; |
| 3959 | +else |
| 3960 | +{ |
| 3961 | +switch (json_get_first_token(json, false)) |
| 3962 | +{ |
| 3963 | +case JSON_TOKEN_OBJECT_START: |
| 3964 | +res = pred->item_type == JS_TYPE_OBJECT; |
| 3965 | +break; |
| 3966 | +case JSON_TOKEN_ARRAY_START: |
| 3967 | +res = pred->item_type == JS_TYPE_ARRAY; |
| 3968 | +break; |
| 3969 | +case JSON_TOKEN_STRING: |
| 3970 | +case JSON_TOKEN_NUMBER: |
| 3971 | +case JSON_TOKEN_TRUE: |
| 3972 | +case JSON_TOKEN_FALSE: |
| 3973 | +case JSON_TOKEN_NULL: |
| 3974 | +res = pred->item_type == JS_TYPE_SCALAR; |
| 3975 | +break; |
| 3976 | +default: |
| 3977 | +res = false; |
| 3978 | +break; |
| 3979 | +} |
| 3980 | +} |
| 3981 | + |
| 3982 | +/* |
| 3983 | +* Do full parsing pass only for uniqueness check or for JSON text |
| 3984 | +* validation. |
| 3985 | +*/ |
| 3986 | +if (res && (pred->unique_keys || exprtype == TEXTOID)) |
| 3987 | +res = json_validate(json, pred->unique_keys, false); |
| 3988 | +} |
| 3989 | +else if (exprtype == JSONBOID) |
| 3990 | +{ |
| 3991 | +if (pred->item_type == JS_TYPE_ANY) |
| 3992 | +res = true; |
| 3993 | +else |
| 3994 | +{ |
| 3995 | +Jsonb *jb = DatumGetJsonbP(js); |
| 3996 | + |
| 3997 | +switch (pred->item_type) |
| 3998 | +{ |
| 3999 | +case JS_TYPE_OBJECT: |
| 4000 | +res = JB_ROOT_IS_OBJECT(jb); |
| 4001 | +break; |
| 4002 | +case JS_TYPE_ARRAY: |
| 4003 | +res = JB_ROOT_IS_ARRAY(jb) && !JB_ROOT_IS_SCALAR(jb); |
| 4004 | +break; |
| 4005 | +case JS_TYPE_SCALAR: |
| 4006 | +res = JB_ROOT_IS_ARRAY(jb) && JB_ROOT_IS_SCALAR(jb); |
| 4007 | +break; |
| 4008 | +default: |
| 4009 | +res = false; |
| 4010 | +break; |
| 4011 | +} |
| 4012 | +} |
| 4013 | + |
| 4014 | +/* Key uniqueness check is redundant for jsonb */ |
| 4015 | +} |
| 4016 | +else |
| 4017 | +res = false; |
| 4018 | + |
| 4019 | +*op->resvalue = BoolGetDatum(res); |
| 4020 | +} |
| 4021 | + |
| 4022 | + |
3924 | 4023 | /*
|
3925 | 4024 | * ExecEvalGroupingFunc
|
3926 | 4025 | *
|
|
0 commit comments