diff --git a/Sources/SQLite/SQLite+Result.swift b/Sources/SQLite/SQLite+Result.swift index a289e31..1920e92 100644 --- a/Sources/SQLite/SQLite+Result.swift +++ b/Sources/SQLite/SQLite+Result.swift @@ -31,7 +31,7 @@ extension SQLite { column = "" } - //Iterates over possible SQLite datatypes. + //Iterates over possible SQLite data types. switch sqlite3_column_type(pointer, i) { case SQLITE_TEXT: let text = sqlite3_column_text(pointer, i) @@ -68,7 +68,7 @@ extension SQLite { data[column] = .null default: - throw SQLiteError.execute("unsupported type") + throw StatusError.misuse("unsupported type") } } diff --git a/Sources/SQLite/SQLite+Statement.swift b/Sources/SQLite/SQLite+Statement.swift index 4ea2bea..05e3d8d 100644 --- a/Sources/SQLite/SQLite+Statement.swift +++ b/Sources/SQLite/SQLite+Statement.swift @@ -32,40 +32,43 @@ extension SQLite { } public func bind(_ value: Double) throws { - if sqlite3_bind_double(pointer, nextBindPosition, value) != SQLITE_OK { - throw SQLiteError.bind(database.errorMessage) - } + let status = sqlite3_bind_double(pointer, nextBindPosition, value) + + try StatusError.check(with: status, msg: database.errorMessage) } public func bind(_ value: Int) throws { - if sqlite3_bind_int64(pointer, nextBindPosition, Int64(value)) != SQLITE_OK { - throw SQLiteError.bind(database.errorMessage) - } + let status = sqlite3_bind_int64(pointer, nextBindPosition, Int64(value)) + + try StatusError.check(with: status, msg: database.errorMessage) + } public func bind(_ value: String) throws { let strlen = Int32(value.utf8.count) - if sqlite3_bind_text(pointer, nextBindPosition, value, strlen, SQLITE_TRANSIENT) != SQLITE_OK { - throw SQLiteError.bind(database.errorMessage) - } + + let status = sqlite3_bind_text(pointer, nextBindPosition, value, strlen, SQLITE_TRANSIENT) + + try StatusError.check(with: status, msg: database.errorMessage) } public func bind(_ value: Bytes) throws { let count = Int32(value.count) - if sqlite3_bind_blob(pointer, nextBindPosition, value, count, SQLITE_TRANSIENT) != SQLITE_OK { - throw SQLiteError.bind(database.errorMessage) - } + + let status = sqlite3_bind_blob(pointer, nextBindPosition, value, count, SQLITE_TRANSIENT) + + try StatusError.check(with: status, msg: database.errorMessage) } public func bind(_ value: Bool) throws { try bind(value ? 1 : 0) } - - + public func null() throws { - if sqlite3_bind_null(pointer, nextBindPosition) != SQLITE_OK { - throw SQLiteError.bind(database.errorMessage) - } + let status = sqlite3_bind_null(pointer, nextBindPosition) + + try StatusError.check(with: status, msg: database.errorMessage) } } + } diff --git a/Sources/SQLite/SQLite.swift b/Sources/SQLite/SQLite.swift index a1a9d27..f68d2a9 100644 --- a/Sources/SQLite/SQLite.swift +++ b/Sources/SQLite/SQLite.swift @@ -31,20 +31,21 @@ public class SQLite { */ public init(path: String) throws { let options = SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_FULLMUTEX - if sqlite3_open_v2(path, &database, options, nil) != SQLITE_OK { - throw SQLiteError.connection(database?.errorMessage ?? "") - } + + let status = sqlite3_open_v2(path, &database, options, nil) + + StatusError.check(with: status, msg: database?.errorMessage ?? "") } /** - Closes a connetion to the database. + Closes a connection to the database. */ public func close() { sqlite3_close(database) } /** - Closes the database when deinitialized. + Closes the database when de-initialized. */ deinit { self.close() @@ -54,13 +55,13 @@ public class SQLite { Executes a statement query string and calls the prepare closure to bind any prepared values. - + The resulting rows are returned if no errors occur. */ public func execute(_ queryString: String, prepareClosure: PrepareClosure = { _ in }) throws -> [Result.Row] { guard let database = self.database else { - throw SQLiteError.execute("No database") + throw StatusError(with: SQLITE_ERROR, msg: "No database")! } let statementContainer = UnsafeMutablePointer.allocate(capacity: 1) @@ -68,12 +69,12 @@ public class SQLite { statementContainer.deallocate(capacity: 1) } - if sqlite3_prepare_v2(database, queryString, -1, statementContainer, nil) != SQLITE_OK { - throw SQLiteError.prepare(database.errorMessage) - } + let status = sqlite3_prepare_v2(database, queryString, -1, statementContainer, nil); + + try StatusError.check(with: status, msg: database.errorMessage) guard let statementPointer = statementContainer.pointee else { - throw SQLiteError.execute("Statement pointer errror") + throw StatusError(with: SQLITE_ERROR, msg: "Statement pointer error")! } let statement = Statement(pointer: statementPointer, database: database) @@ -81,7 +82,7 @@ public class SQLite { var result = Result() while sqlite3_step(statement.pointer) == SQLITE_ROW { - + var row = Result.Row() let count = sqlite3_column_count(statement.pointer) @@ -91,11 +92,11 @@ public class SQLite { result.rows.append(row) } - - if sqlite3_finalize(statement.pointer) != SQLITE_OK { - throw SQLiteError.execute(database.errorMessage) - } - + + let finalizeStatus = sqlite3_finalize(statement.pointer) + + try StatusError.check(with: finalizeStatus, msg: database.errorMessage) + return result.rows } @@ -113,6 +114,7 @@ public class SQLite { } //MARK: Error + @available(*, deprecated, message: "SQLiteError will be removed on release 3.0.0, use StatusError instead.") public enum SQLiteError: Error { case connection(String) case close(String) @@ -120,6 +122,7 @@ public class SQLite { case bind(String) case execute(String) } + } extension SQLite.Database { @@ -136,4 +139,3 @@ extension SQLite.Database { } } - diff --git a/Sources/SQLite/StatusError.swift b/Sources/SQLite/StatusError.swift new file mode 100644 index 0000000..0c30f57 --- /dev/null +++ b/Sources/SQLite/StatusError.swift @@ -0,0 +1,119 @@ +import CSQLite + +public enum StatusError: Error { + + public typealias StatusCode = Int32 + + /** + The definitions of these error codes + is in sqlite3.h. + */ + init?(with status: StatusCode, msg: String) { + switch status { + case SQLITE_OK: + return nil + case SQLITE_ERROR: + self = .error(msg) + case SQLITE_INTERNAL: + self = .intern(msg) + case SQLITE_PERM: + self = .permission(msg) + case SQLITE_ABORT: + self = .abort(msg) + case SQLITE_BUSY: + self = .busy(msg) + case SQLITE_LOCKED: + self = .locked(msg) + case SQLITE_NOMEM: + self = .noMemory(msg) + case SQLITE_READONLY: + self = .readOnly(msg) + case SQLITE_INTERRUPT: + self = .interrupt(msg) + case SQLITE_IOERR: + self = .ioError(msg) + case SQLITE_CORRUPT: + self = .corrupt(msg) + case SQLITE_NOTFOUND: + self = .notFound(msg) + case SQLITE_FULL: + self = .full(msg) + case SQLITE_CANTOPEN: + self = .cantOpen(msg) + case SQLITE_PROTOCOL: + self = .proto(msg) + case SQLITE_EMPTY: + self = .empty(msg) + case SQLITE_SCHEMA: + self = .schema(msg) + case SQLITE_TOOBIG: + self = .tooBig(msg) + case SQLITE_CONSTRAINT: + self = .constraint(msg) + case SQLITE_MISMATCH: + self = .mismatch(msg) + case SQLITE_MISUSE: + self = .misuse(msg) + case SQLITE_NOLFS: + self = .noLFS(msg) + case SQLITE_AUTH: + self = .auth(msg) + case SQLITE_FORMAT: + self = .format(msg) + case SQLITE_RANGE: + self = .range(msg) + case SQLITE_NOTADB: + self = .notADatabase(msg) + case SQLITE_NOTICE: + self = .notice(msg) + case SQLITE_WARNING: + self = .warning(msg) + case SQLITE_ROW: + self = .row(msg) + case SQLITE_DONE: + self = .done(msg) + default: + self = .error(msg) + } + } + /** + Helper function that checks if + the status passed is an error. + */ + public static func check(with status: StatusCode, msg: String) throws { + if let error = StatusError(with: status, msg: msg) { + throw error + } + } + + case error(String) + case intern(String) + case permission(String) + case abort(String) + case busy(String) + case locked(String) + case noMemory(String) + case readOnly(String) + case interrupt(String) + case ioError(String) + case corrupt(String) + case notFound(String) + case full(String) + case cantOpen(String) + case proto(String) + case empty(String) + case schema(String) + case tooBig(String) + case constraint(String) + case mismatch(String) + case misuse(String) + case noLFS(String) + case auth(String) + case format(String) + case range(String) + case notADatabase(String) + case notice(String) + case warning(String) + case row(String) + case done(String) +}