66package eval
77
88import (
9+ "github.com/cockroachdb/apd/v3"
10+ "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode"
11+ "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror"
12+ "github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
913 "github.com/cockroachdb/cockroach/pkg/util/json"
1014 "github.com/cockroachdb/cockroach/pkg/util/jsonpath"
1115 "github.com/cockroachdb/errors"
@@ -28,14 +32,14 @@ func isBool(j json.JSON) bool {
2832 }
2933}
3034
31- func convertFromBool (b jsonpathBool ) [] json.JSON {
35+ func convertFromBool (b jsonpathBool ) json.JSON {
3236 switch b {
3337 case jsonpathBoolTrue :
34- return [] json.JSON { json . TrueJSONValue }
38+ return json .TrueJSONValue
3539 case jsonpathBoolFalse :
36- return [] json.JSON { json . FalseJSONValue }
40+ return json .FalseJSONValue
3741 case jsonpathBoolUnknown :
38- return [] json.JSON { json . NullJSONValue }
42+ return json .NullJSONValue
3943 default :
4044 panic (errors .AssertionFailedf ("unhandled jsonpath boolean type" ))
4145 }
@@ -54,22 +58,25 @@ func convertToBool(j json.JSON) jsonpathBool {
5458
5559func (ctx * jsonpathCtx ) evalOperation (
5660 op jsonpath.Operation , jsonValue json.JSON ,
57- ) (jsonpathBool , error ) {
61+ ) (json. JSON , error ) {
5862 switch op .Type {
5963 case jsonpath .OpLogicalAnd , jsonpath .OpLogicalOr , jsonpath .OpLogicalNot :
6064 res , err := ctx .evalLogical (op , jsonValue )
6165 if err != nil {
62- return jsonpathBoolUnknown , err
66+ return convertFromBool ( jsonpathBoolUnknown ) , err
6367 }
64- return res , nil
68+ return convertFromBool ( res ) , nil
6569 case jsonpath .OpCompEqual , jsonpath .OpCompNotEqual ,
6670 jsonpath .OpCompLess , jsonpath .OpCompLessEqual ,
6771 jsonpath .OpCompGreater , jsonpath .OpCompGreaterEqual :
6872 res , err := ctx .evalComparison (op , jsonValue , true /* unwrapRight */ )
6973 if err != nil {
70- return jsonpathBoolUnknown , err
74+ return convertFromBool ( jsonpathBoolUnknown ) , err
7175 }
72- return res , nil
76+ return convertFromBool (res ), nil
77+ case jsonpath .OpAdd , jsonpath .OpSub , jsonpath .OpMult ,
78+ jsonpath .OpDiv , jsonpath .OpMod :
79+ return ctx .evalArithmetic (op , jsonValue )
7380 default :
7481 panic (errors .AssertionFailedf ("unhandled operation type" ))
7582 }
@@ -234,3 +241,54 @@ func execComparison(l, r json.JSON, op jsonpath.OperationType) (jsonpathBool, er
234241 }
235242 return jsonpathBoolFalse , nil
236243}
244+
245+ func (ctx * jsonpathCtx ) evalArithmetic (
246+ op jsonpath.Operation , jsonValue json.JSON ,
247+ ) (json.JSON , error ) {
248+ left , err := ctx .evalAndUnwrapResult (op .Left , jsonValue , true /* unwrap */ )
249+ if err != nil {
250+ return nil , err
251+ }
252+ right , err := ctx .evalAndUnwrapResult (op .Right , jsonValue , true /* unwrap */ )
253+ if err != nil {
254+ return nil , err
255+ }
256+
257+ if len (left ) != 1 || left [0 ].Type () != json .NumberJSONType {
258+ return nil , pgerror .Newf (pgcode .SingletonSQLJSONItemRequired ,
259+ "left operand of jsonpath operator %s is not a single numeric value" ,
260+ jsonpath .OperationTypeStrings [op .Type ])
261+ }
262+ if len (right ) != 1 || right [0 ].Type () != json .NumberJSONType {
263+ return nil , pgerror .Newf (pgcode .SingletonSQLJSONItemRequired ,
264+ "right operand of jsonpath operator %s is not a single numeric value" ,
265+ jsonpath .OperationTypeStrings [op .Type ])
266+ }
267+
268+ leftNum , _ := left [0 ].AsDecimal ()
269+ rightNum , _ := right [0 ].AsDecimal ()
270+ var res apd.Decimal
271+ var cond apd.Condition
272+ switch op .Type {
273+ case jsonpath .OpAdd :
274+ _ , err = tree .DecimalCtx .Add (& res , leftNum , rightNum )
275+ case jsonpath .OpSub :
276+ _ , err = tree .DecimalCtx .Sub (& res , leftNum , rightNum )
277+ case jsonpath .OpMult :
278+ _ , err = tree .DecimalCtx .Mul (& res , leftNum , rightNum )
279+ case jsonpath .OpDiv :
280+ cond , err = tree .DecimalCtx .Quo (& res , leftNum , rightNum )
281+ // Division by zero or 0 / 0.
282+ if cond .DivisionByZero () || cond .DivisionUndefined () {
283+ return nil , tree .ErrDivByZero
284+ }
285+ case jsonpath .OpMod :
286+ _ , err = tree .DecimalCtx .Rem (& res , leftNum , rightNum )
287+ default :
288+ panic (errors .AssertionFailedf ("unhandled jsonpath arithmetic type" ))
289+ }
290+ if err != nil {
291+ return nil , err
292+ }
293+ return json .FromDecimal (res ), nil
294+ }
0 commit comments