diff --git a/sqlparser/CHANGELOG.md b/sqlparser/CHANGELOG.md index c19c52d6..59a40322 100644 --- a/sqlparser/CHANGELOG.md +++ b/sqlparser/CHANGELOG.md @@ -1,9 +1,10 @@ -## 0.33.1 +## 0.34.1 - Fix explicit `NULL` column constraints being dropped when converting nodes to SQL. - Add analysis errors for illegal unqualified references to `old` and `new` in triggers. +- Analysis support for sqlite 3.45 and jsonb functions. ## 0.33.0 diff --git a/sqlparser/lib/src/engine/module/json1.dart b/sqlparser/lib/src/engine/module/json1.dart index 20454065..b9bf3c87 100644 --- a/sqlparser/lib/src/engine/module/json1.dart +++ b/sqlparser/lib/src/engine/module/json1.dart @@ -5,15 +5,19 @@ class Json1Extension implements Extension { @override void register(SqlEngine engine) { + final supportsJsonb = engine.options.version >= SqliteVersion.v3_45; + engine - ..registerFunctionHandler(const _Json1Functions()) + ..registerFunctionHandler(_Json1Functions(supportsJsonb)) ..registerTableValuedFunctionHandler(const _JsonEachFunction()) ..registerTableValuedFunctionHandler(const _JsonTreeFunction()); } } class _Json1Functions implements FunctionHandler { - const _Json1Functions(); + final bool _supportBinaryJson; + + const _Json1Functions(this._supportBinaryJson); static const Set _returnStrings = { 'json', @@ -29,12 +33,27 @@ class _Json1Functions implements FunctionHandler { 'json_group_object', }; + static const Set _returnBlobs = { + 'jsonb', + 'jsonb_array', + 'jsonb_insert', + 'jsonb_object', + 'jsonb_patch', + 'jsonb_remove', + 'jsonb_replace', + 'jsonb_set', + 'jsonb_group_array', + 'jsonb_group_object' + }; + @override - Set get functionNames => const { + Set get functionNames => { ..._returnStrings, + if (_supportBinaryJson) ..._returnBlobs, 'json_type', 'json_valid', 'json_extract', + if (_supportBinaryJson) 'jsonb_extract', 'json_array_length', }; @@ -51,6 +70,8 @@ class _Json1Functions implements FunctionHandler { if (_returnStrings.contains(name)) { return const ResolveResult(ResolvedType(type: BasicType.text)); + } else if (_returnBlobs.contains(name)) { + return const ResolveResult(ResolvedType(type: BasicType.blob)); } else { switch (name) { case 'json_type': @@ -59,6 +80,7 @@ class _Json1Functions implements FunctionHandler { case 'json_valid': return const ResolveResult(ResolvedType.bool()); case 'json_extract': + case 'jsonb_extract': return const ResolveResult.unknown(); case 'json_array_length': return const ResolveResult(ResolvedType(type: BasicType.int)); diff --git a/sqlparser/lib/src/engine/options.dart b/sqlparser/lib/src/engine/options.dart index edcfe26b..6f86577c 100644 --- a/sqlparser/lib/src/engine/options.dart +++ b/sqlparser/lib/src/engine/options.dart @@ -93,6 +93,10 @@ class SqliteVersion implements Comparable { /// can't provide analysis warnings when using recent sqlite3 features. static const SqliteVersion minimum = SqliteVersion.v3(34); + /// Version `3.55.0` has added support for a binary JSON format and introduces + /// `jsonb` variants of JSON functions. + static const SqliteVersion v3_45 = SqliteVersion.v3(45); + /// Version `3.44.0` has added `ORDER BY` clauses as parameters for aggregate /// functions and more SQL functions. static const SqliteVersion v3_44 = SqliteVersion.v3(44); @@ -122,7 +126,7 @@ class SqliteVersion implements Comparable { /// The highest sqlite version supported by this `sqlparser` package. /// /// Newer features in `sqlite3` may not be recognized by this library. - static const SqliteVersion current = v3_44; + static const SqliteVersion current = v3_45; /// The major version of sqlite. /// diff --git a/sqlparser/test/engine/module/json1_test.dart b/sqlparser/test/engine/module/json1_test.dart index 5e43bcc2..a6d1e14f 100644 --- a/sqlparser/test/engine/module/json1_test.dart +++ b/sqlparser/test/engine/module/json1_test.dart @@ -1,10 +1,13 @@ import 'package:sqlparser/sqlparser.dart'; import 'package:test/test.dart'; +import '../../analysis/errors/utils.dart'; + void main() { group('json with new type inference', () { final engine = SqlEngine(EngineOptions( enabledExtensions: const [Json1Extension()], + version: SqliteVersion.v3_45, )); // add user (name, phone) table final table = engine.schemaReader.read( @@ -23,6 +26,7 @@ void main() { } const resolvedString = ResolveResult(ResolvedType(type: BasicType.text)); + const resolvedBlob = ResolveResult(ResolvedType(type: BasicType.blob)); test('create json', () { expect(findResult("json('{}')"), resolvedString); @@ -38,6 +42,19 @@ void main() { expect(findResult('json_group_object()'), resolvedString); }); + test('create binary json', () { + expect(findResult("jsonb('{}')"), resolvedBlob); + expect(findResult("jsonb_array('foo', 'bar')"), resolvedBlob); + expect(findResult("jsonb_insert('{}')"), resolvedBlob); + expect(findResult("jsonb_replace('{}')"), resolvedBlob); + expect(findResult("jsonb_set('{}')"), resolvedBlob); + expect(findResult('jsonb_object()'), resolvedBlob); + expect(findResult("jsonb_patch('{}', '{}')"), resolvedBlob); + expect(findResult("jsonb_remove('{}', '{}')"), resolvedBlob); + expect(findResult('jsonb_group_array()'), resolvedBlob); + expect(findResult('jsonb_group_object()'), resolvedBlob); + }); + test('json_type', () { expect( findResult("json_type('foo', 'bar')"), @@ -71,4 +88,15 @@ SELECT DISTINCT user.name expect(result.errors, isEmpty); }); }); + + test('does not allow jsonb functions before 3.45', () { + final engine = SqlEngine(EngineOptions(version: SqliteVersion.v3_44)); + final result = engine.analyze('SELECT jsonb(?);'); + expect(result.errors, [ + analysisErrorWith( + lexeme: 'jsonb', + type: AnalysisErrorType.unknownFunction, + ) + ]); + }); }