Add/Update TestCases for all introduced changes

This commit is contained in:
tibotix 2023-11-17 01:49:37 +01:00
parent f282ead955
commit deaf58c5fb
No known key found for this signature in database
GPG Key ID: 96DF02FF50AC54C7
5 changed files with 172 additions and 4 deletions

View File

@ -89,12 +89,25 @@ void main() {
expect(result.errors, isEmpty);
});
test('update statements with column-name-list', () {
final result = engine.analyze(
'WITH x AS (SELECT * FROM demo) UPDATE demo '
'SET (id, content) = (x.id, x.content) FROM x WHERE demo.id = x.id;');
expect(result.errors, isEmpty);
});
test('insert statements', () {
final result = engine.analyze(
'WITH x AS (SELECT * FROM demo) INSERT INTO demo SELECT * FROM x;');
expect(result.errors, isEmpty);
});
test('insert statements with upsert using column-name-list', () {
final result = engine.analyze(
'WITH x AS (SELECT * FROM demo) INSERT INTO demo SELECT * FROM x ON CONFLICT(content) DO UPDATE SET (id, content) = (0, \'hello\');');
expect(result.errors, isEmpty);
});
test('delete statements', () {
final result = engine.analyze(
'WITH x AS (SELECT * FROM demo) DELETE FROM demo WHERE id IN (SELECT id FROM x);');

View File

@ -0,0 +1,72 @@
import 'package:sqlparser/sqlparser.dart';
import 'package:test/test.dart';
import '../data.dart';
import 'utils.dart';
void main() {
late SqlEngine engine;
setUp(() {
engine = SqlEngine();
engine.registerTableFromSql('''
CREATE TABLE foo (
a INTEGER NOT NULL,
b INTEGER NOT NULL
);
''');
});
group("using column-name-list and tuple in update", () {
test('reports error if they have different sizes', () {
engine
.analyze("UPDATE foo SET (a, b) = (1);")
.expectError('(1)', type: AnalysisErrorType.cteColumnCountMismatch);
engine
.analyze("UPDATE foo SET (a) = (1,2);")
.expectError('(1,2)', type: AnalysisErrorType.cteColumnCountMismatch);
});
test('reports no error if they have same sizes', () {
engine.analyze("UPDATE foo SET (a, b) = (1,2);").expectNoError();
});
});
group("using column-name-list and values in update", () {
test('reports error if they have different sizes', () {
engine.analyze("UPDATE foo SET (a, b) = (VALUES(1));").expectError(
"(VALUES(1))",
type: AnalysisErrorType.cteColumnCountMismatch);
engine.analyze("UPDATE foo SET (a) = (VALUES(1,2));").expectError(
"(VALUES(1,2))",
type: AnalysisErrorType.cteColumnCountMismatch);
});
test('reports no error if they have same sizes', () {
engine.analyze("UPDATE foo SET (a, b) = (VALUES(1,2));").expectNoError();
});
});
group("using column-name-list and subquery in update", () {
test('reports error if they have different sizes', () {
engine.analyze("UPDATE foo SET (a, b) = (SELECT 1);").expectError(
'(SELECT 1)',
type: AnalysisErrorType.cteColumnCountMismatch);
engine.analyze("UPDATE foo SET (a) = (SELECT 1,2);").expectError(
'(SELECT 1,2)',
type: AnalysisErrorType.cteColumnCountMismatch);
engine
.analyze(
"UPDATE foo SET (a, b) = (SELECT b FROM foo as f WHERE f.a=a);")
.expectError('(SELECT b FROM foo as f WHERE f.a=a)',
type: AnalysisErrorType.cteColumnCountMismatch);
});
test('reports no error if they have same sizes', () {
engine.analyze("UPDATE foo SET (a, b) = (SELECT 1,2);").expectNoError();
engine
.analyze(
"UPDATE foo SET (a, b) = (SELECT b, a FROM foo as f WHERE f.a=a);")
.expectNoError();
});
});
}

View File

@ -23,6 +23,13 @@ void main() {
.expectError('g', type: AnalysisErrorType.writeToGeneratedColumn);
});
test('reports error when updating generated column with column-name-list',
() {
engine
.analyze("UPDATE a SET (ok, g) = ('new', 'old');")
.expectError('g', type: AnalysisErrorType.writeToGeneratedColumn);
});
test('reports error when inserting generated column', () {
engine
.analyze('INSERT INTO a (ok, g) VALUES (?, ?)')

View File

@ -14,13 +14,18 @@ void main() {
return TypeResolver(TypeInferenceSession(context))..run(context.root);
}
ResolvedType? resolveFirstVariable(String sql,
Iterable<ResolvedType?> resolveVariableTypes(String sql,
{AnalyzeStatementOptions? options}) {
final resolver = obtainResolver(sql, options: options);
final session = resolver.session;
final variable =
session.context.root.allDescendants.whereType<Variable>().first;
return session.typeOf(variable);
return session.context.root.allDescendants
.whereType<Variable>()
.map((variable) => session.typeOf(variable));
}
ResolvedType? resolveFirstVariable(String sql,
{AnalyzeStatementOptions? options}) {
return resolveVariableTypes(sql, options: options).first;
}
ResolvedType? resolveResultColumn(String sql) {
@ -292,6 +297,32 @@ WITH RECURSIVE
expect(type, const ResolvedType(type: BasicType.int));
});
test('handles multi column set components in updates', () {
final variableTypes =
resolveVariableTypes('UPDATE demo SET (id, content) = (?, ?)');
expect(variableTypes.first, const ResolvedType(type: BasicType.int));
expect(
variableTypes.elementAt(1), const ResolvedType(type: BasicType.text));
});
test('handles multi column set components in updates with select subquery',
() {
final variableTypes =
resolveVariableTypes('UPDATE demo SET (id, content) = (SELECT ?,?)');
expect(variableTypes.first, const ResolvedType(type: BasicType.int));
expect(
variableTypes.elementAt(1), const ResolvedType(type: BasicType.text));
});
test('handles multi column set components in updates with values subquery',
() {
final variableTypes =
resolveVariableTypes('UPDATE demo SET (id, content) = (VALUES(?,?))');
expect(variableTypes.first, const ResolvedType(type: BasicType.int));
expect(
variableTypes.elementAt(1), const ResolvedType(type: BasicType.text));
});
test('infers offsets in frame specs', () {
final type = resolveFirstVariable('SELECT SUM(id) OVER (ROWS ? PRECEDING)');
expect(type, const ResolvedType(type: BasicType.int));

View File

@ -26,6 +26,51 @@ void main() {
testAll(testCases);
});
test('parses updates with column-name-list and subquery', () {
testStatement(
'''
UPDATE foo
SET (a, b) = (SELECT b, a FROM bar AS b WHERE b.id=foo.id);
''',
UpdateStatement(table: TableReference('foo'), set: [
MultiColumnSetComponent(
columns: [Reference(columnName: 'a'), Reference(columnName: 'b')],
rowValue: SubQuery(
select: SelectStatement(
columns: [
ExpressionResultColumn(
expression: Reference(columnName: 'b'),
),
ExpressionResultColumn(
expression: Reference(columnName: 'a'),
),
],
from: TableReference('bar', as: 'b'),
where: BinaryExpression(
Reference(entityName: 'b', columnName: 'id'),
token(TokenType.equal),
Reference(entityName: 'foo', columnName: 'id'),
))))
]));
});
test('parses updates with column-name-list and scalar rowValues', () {
testStatement(
'''
UPDATE foo
SET (a, b) = (b, 3+4);
''',
UpdateStatement(table: TableReference('foo'), set: [
MultiColumnSetComponent(
columns: [Reference(columnName: 'a'), Reference(columnName: 'b')],
rowValue: Tuple(expressions: [
Reference(columnName: "b"),
BinaryExpression(NumericLiteral(3), token(TokenType.plus),
NumericLiteral(4)),
], usedAsRowValue: true))
]));
});
test('parses updates with FROM clause', () {
testStatement(
'''