| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106 |
- //
- // SQLite.swift
- // Swifter
- //
- // Copyright (c) 2014-2016 Damian Kołakowski. All rights reserved.
- //
- import Foundation
- enum SQLiteError: ErrorType {
- case OpenFailed(String?)
- case ExecFailed(String?)
- }
- public class SQLite {
-
- private let databaseConnection: COpaquePointer
-
- public static func open(path: String) throws -> SQLite {
- var databaseConnection = COpaquePointer()
- let openResult = path.withCString { sqlite3_open($0, &databaseConnection) }
- guard openResult == SQLITE_OK else {
- throw SQLiteError.OpenFailed(String.fromCString(sqlite3_errmsg(databaseConnection)))
- }
- return SQLite(databaseConnection)
- }
-
- private init(_ databaseConnection: COpaquePointer) {
- self.databaseConnection = databaseConnection
- }
-
- private struct ExecCContext { var callback: ([String: String] -> Void)? }
- public func exec(sql: String) throws {
- try exec(sql, callback: nil)
- }
-
- public func exec(sql: String, callback: ([String: String] -> Void)?) throws {
- var errorMessagePointer = UnsafeMutablePointer<Int8>()
- var execCContext = ExecCContext(callback: callback)
- let execResult = sql.withCString {
- sqlite3_exec(databaseConnection, $0, { (context, count, values, names) -> Int32 in
- var content = [String: String]()
- for i in 0..<count {
- if let name = String.fromCString(names.advancedBy(Int(i)).memory),
- let value = String.fromCString(values.advancedBy(Int(i)).memory) {
- content[name] = value
- }
- }
- if let callback = UnsafeMutablePointer<ExecCContext>(context).memory.callback {
- callback(content)
- }
- return SQLITE_OK
- }, &execCContext, &errorMessagePointer)
- }
- guard execResult == SQLITE_OK else {
- let errorDetails = String.fromCString(errorMessagePointer)
- sqlite3_free(errorMessagePointer)
- throw SQLiteError.ExecFailed(errorDetails)
- }
- }
-
- public func enumerate(sql: String) throws -> StatmentSequence {
- var statement = COpaquePointer()
- let prepareResult = sql.withCString { sqlite3_prepare_v2(databaseConnection, $0, Int32(sql.utf8.count), &statement, nil) }
- guard prepareResult == SQLITE_OK else {
- throw SQLiteError.ExecFailed(String.fromCString(sqlite3_errmsg(databaseConnection)))
- }
- return StatmentSequence(statement: statement)
- }
-
- public struct StatmentGenerator: GeneratorType {
-
- public let statement: COpaquePointer
-
- public func next() -> [String: String]? {
- switch sqlite3_step(statement) {
- case SQLITE_ROW:
- var content = [String: String]()
- for i in 0..<sqlite3_column_count(statement) {
- if let name = String.fromCString(UnsafePointer<CChar>(sqlite3_column_name(statement, i))),
- let value = String.fromCString(UnsafePointer<CChar>(sqlite3_column_text(statement, i))) {
- content[name] = value
- }
- }
- return content
- default:
- sqlite3_finalize(statement)
- return nil
- }
- }
- }
-
- public struct StatmentSequence: SequenceType {
-
- public let statement: COpaquePointer
-
- public func generate() -> StatmentGenerator {
- return StatmentGenerator(statement: statement)
- }
- }
-
- public func close() throws {
- sqlite3_close(databaseConnection)
- }
- }
|