@@ -18,6 +18,7 @@ import (
18
18
"fmt"
19
19
"testing"
20
20
21
+ "github.com/pingcap/failpoint"
21
22
"github.com/pingcap/tidb/pkg/parser/ast"
22
23
"github.com/pingcap/tidb/pkg/parser/mysql"
23
24
"github.com/pingcap/tidb/pkg/parser/terror"
@@ -1342,3 +1343,100 @@ func TestJSONMergePatch(t *testing.T) {
1342
1343
}
1343
1344
}
1344
1345
}
1346
+
1347
+ func TestJSONSchemaValid (t * testing.T ) {
1348
+ ctx := createContext (t )
1349
+ fc := funcs [ast .JSONSchemaValid ]
1350
+ tbl := []struct {
1351
+ Input any
1352
+ Expected any
1353
+ }{
1354
+ // nulls
1355
+ {[]any {nil , `{}` }, nil },
1356
+ {[]any {`{}` , nil }, nil },
1357
+ {[]any {nil , nil }, nil },
1358
+
1359
+ // empty
1360
+ {[]any {`{}` , `{}` }, 1 },
1361
+
1362
+ // required
1363
+ {[]any {`{"required": ["a","b"]}` , `{"a": 5}` }, 0 },
1364
+ {[]any {`{"required": ["a","b"]}` , `{"a": 5, "b": 6}` }, 1 },
1365
+
1366
+ // type
1367
+ {[]any {`{"type": ["string"]}` , `{}` }, 0 },
1368
+ {[]any {`{"type": ["string"]}` , `"foobar"` }, 1 },
1369
+ {[]any {`{"type": ["object"]}` , `{}` }, 1 },
1370
+ {[]any {`{"type": ["object"]}` , `"foobar"` }, 0 },
1371
+
1372
+ // properties, type
1373
+ {[]any {`{"properties": {"a": {"type": "number"}}}` , `{}` }, 1 },
1374
+ {[]any {`{"properties": {"a": {"type": "number"}}}` , `{"a": "foobar"}` }, 0 },
1375
+ {[]any {`{"properties": {"a": {"type": "number"}}}` , `{"a": 5}` }, 1 },
1376
+
1377
+ // properties, minimum
1378
+ {[]any {`{"properties": {"a": {"type": "number", "minimum": 6}}}` , `{"a": 5}` }, 0 },
1379
+
1380
+ // properties, pattern
1381
+ {[]any {`{"properties": {"a": {"type": "string", "pattern": "^a"}}}` , `{"a": "abc"}` }, 1 },
1382
+ {[]any {`{"properties": {"a": {"type": "string", "pattern": "^a"}}}` , `{"a": "cba"}` }, 0 },
1383
+ }
1384
+ dtbl := tblToDtbl (tbl )
1385
+ for _ , tt := range dtbl {
1386
+ f , err := fc .getFunction (ctx , datumsToConstants (tt ["Input" ]))
1387
+ require .NoError (t , err )
1388
+ d , err := evalBuiltinFunc (f , ctx , chunk.Row {})
1389
+ require .NoError (t , err )
1390
+ if tt ["Expected" ][0 ].IsNull () {
1391
+ require .True (t , d .IsNull ())
1392
+ } else {
1393
+ testutil .DatumEqual (
1394
+ t , tt ["Expected" ][0 ], d ,
1395
+ fmt .Sprintf ("JSON_SCHEMA_VALID(%s,%s) = %d (expected: %d)" ,
1396
+ tt ["Input" ][0 ].GetString (),
1397
+ tt ["Input" ][1 ].GetString (),
1398
+ d .GetInt64 (),
1399
+ tt ["Expected" ][0 ].GetInt64 (),
1400
+ ),
1401
+ )
1402
+ }
1403
+ }
1404
+ }
1405
+
1406
+ // TestJSONSchemaValidCache is to test if the cached schema is used
1407
+ func TestJSONSchemaValidCache (t * testing.T ) {
1408
+ ctx := createContext (t )
1409
+ fc := funcs [ast .JSONSchemaValid ]
1410
+ tbl := []struct {
1411
+ Input any
1412
+ Expected any
1413
+ }{
1414
+ {[]any {`{}` , `{}` }, 1 },
1415
+ }
1416
+ dtbl := tblToDtbl (tbl )
1417
+
1418
+ for _ , tt := range dtbl {
1419
+ // Get the function and eval once, ensuring it is cached
1420
+ f , err := fc .getFunction (ctx , datumsToConstants (tt ["Input" ]))
1421
+ require .NoError (t , err )
1422
+ _ , err = evalBuiltinFunc (f , ctx , chunk.Row {})
1423
+ require .NoError (t , err )
1424
+
1425
+ // Disable the cache function
1426
+ require .NoError (t , failpoint .Enable ("github.com/pingcap/tidb/pkg/expression/jsonSchemaValidDisableCacheRefresh" , `return(true)` ))
1427
+
1428
+ // This eval should use the cache and not call the function.
1429
+ _ , err = evalBuiltinFunc (f , ctx , chunk.Row {})
1430
+ require .NoError (t , err )
1431
+
1432
+ // Now get a new cache by getting the function again.
1433
+ f , err = fc .getFunction (ctx , datumsToConstants (tt ["Input" ]))
1434
+ require .NoError (t , err )
1435
+
1436
+ // Empty cache, we call the function. This should return an error.
1437
+ _ , err = evalBuiltinFunc (f , ctx , chunk.Row {})
1438
+ require .Error (t , err )
1439
+ }
1440
+
1441
+ require .NoError (t , failpoint .Disable ("github.com/pingcap/tidb/pkg/expression/jsonSchemaValidDisableCacheRefresh" ))
1442
+ }
0 commit comments