mirror of https://github.com/AMT-Cheif/drift.git
Merge pull request #432 from jaggernod/throw-meaningful-error-on-prepared-statement
Handling exceptional case when executing Prepared Statement
This commit is contained in:
commit
9b2b73cd20
|
@ -67,6 +67,7 @@ class _SQLiteBindings {
|
|||
int Function(Pointer<Database> db) sqlite3_changes;
|
||||
int Function(Pointer<Database> db) sqlite3_last_insert_rowid;
|
||||
|
||||
int Function(Pointer<Database> db) sqlite3_extended_errcode;
|
||||
Pointer<CBlob> Function(int code) sqlite3_errstr;
|
||||
Pointer<CBlob> Function(Pointer<Database> database) sqlite3_errmsg;
|
||||
|
||||
|
@ -165,6 +166,10 @@ class _SQLiteBindings {
|
|||
sqlite3_finalize = sqlite
|
||||
.lookup<NativeFunction<sqlite3_finalize_native_t>>('sqlite3_finalize')
|
||||
.asFunction();
|
||||
sqlite3_extended_errcode = sqlite
|
||||
.lookup<NativeFunction<sqlite3_extended_errcode_native_t>>(
|
||||
'sqlite3_extended_errcode')
|
||||
.asFunction();
|
||||
sqlite3_errstr = sqlite
|
||||
.lookup<NativeFunction<sqlite3_errstr_native_t>>('sqlite3_errstr')
|
||||
.asFunction();
|
||||
|
|
|
@ -36,6 +36,9 @@ typedef sqlite3_reset_native_t = Int32 Function(Pointer<Statement> statement);
|
|||
typedef sqlite3_finalize_native_t = Int32 Function(
|
||||
Pointer<Statement> statement);
|
||||
|
||||
typedef sqlite3_extended_errcode_native_t = Int32 Function(
|
||||
Pointer<Database> database);
|
||||
|
||||
typedef sqlite3_errstr_native_t = Pointer<CBlob> Function(Int32 error);
|
||||
|
||||
typedef sqlite3_errmsg_native_t = Pointer<CBlob> Function(
|
||||
|
|
|
@ -16,7 +16,12 @@ class SqliteException implements Exception {
|
|||
|
||||
String explanation;
|
||||
if (code != null) {
|
||||
explanation = bindings.sqlite3_errstr(code).readString();
|
||||
// Getting hold of more explanatory error code as SQLITE_IOERR error group
|
||||
// has an extensive list of extended error codes
|
||||
final extendedCode = bindings.sqlite3_extended_errcode(db);
|
||||
final errStr = bindings.sqlite3_errstr(extendedCode).readString();
|
||||
|
||||
explanation = '$errStr (code $extendedCode)';
|
||||
}
|
||||
|
||||
return SqliteException(dbMessage, explanation);
|
||||
|
|
|
@ -45,10 +45,15 @@ class PreparedStatement {
|
|||
names[i] = bindings.sqlite3_column_name(_stmt, i).readString();
|
||||
}
|
||||
|
||||
while (_step() == Errors.SQLITE_ROW) {
|
||||
int resultCode;
|
||||
while ((resultCode = _step()) == Errors.SQLITE_ROW) {
|
||||
rows.add([for (var i = 0; i < columnCount; i++) _readValue(i)]);
|
||||
}
|
||||
|
||||
if (resultCode != Errors.SQLITE_OK && resultCode != Errors.SQLITE_DONE) {
|
||||
throw SqliteException._fromErrorCode(_db._db, resultCode);
|
||||
}
|
||||
|
||||
return Result(names, rows);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'dart:ffi';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:moor_ffi/database.dart';
|
||||
|
@ -85,4 +86,38 @@ void main() {
|
|||
|
||||
db.close();
|
||||
});
|
||||
|
||||
test('throws an exception when iterating over result rows', () {
|
||||
final db = Database.memory()
|
||||
..createFunction(
|
||||
'raise_if_two',
|
||||
1,
|
||||
Pointer.fromFunction(_raiseIfTwo),
|
||||
);
|
||||
|
||||
db.execute(
|
||||
'CREATE TABLE tbl (a INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT)');
|
||||
// insert with a = 1..3
|
||||
for (var i = 0; i < 3; i++) {
|
||||
db.execute('INSERT INTO tbl DEFAULT VALUES');
|
||||
}
|
||||
|
||||
final statement = db.prepare('SELECT raise_if_two(a) FROM tbl ORDER BY a');
|
||||
|
||||
expect(
|
||||
statement.select,
|
||||
throwsA(isA<SqliteException>()
|
||||
.having((e) => e.message, 'message', contains('was two'))),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
void _raiseIfTwo(Pointer<FunctionContext> ctx, int argCount,
|
||||
Pointer<Pointer<SqliteValue>> args) {
|
||||
final value = args[0].value;
|
||||
if (value == 2) {
|
||||
ctx.resultError('parameter was two');
|
||||
} else {
|
||||
ctx.resultNull();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
import 'package:moor_ffi/database.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
Database database;
|
||||
|
||||
setUp(() => database = Database.memory());
|
||||
|
||||
tearDown(() => database.close());
|
||||
|
||||
test('violating constraint throws exception with extended error code', () {
|
||||
database.execute('CREATE TABLE tbl(a INTEGER NOT NULL)');
|
||||
|
||||
final statement = database.prepare('INSERT INTO tbl DEFAULT VALUES');
|
||||
|
||||
expect(
|
||||
statement.execute,
|
||||
throwsA(
|
||||
isA<SqliteException>().having(
|
||||
(e) => e.explanation, 'explanation', endsWith(' (code 1299)')),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue