Skip to content

Commit

Permalink
Added support for returning data by its stored data type - or String …
Browse files Browse the repository at this point in the history
…if type couldn't be determined, Modified the Singleton code to ensure that init() cannot be called more than once, Added a bridging class to handle the string escape functionality since I could not figure out how to call the necessary C API from Swift directly, Integrated multiple bugfixes from rschmukler/bug-fixes
  • Loading branch information
FahimF committed Jun 19, 2014
1 parent a65566e commit 640b9d9
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 26 deletions.
15 changes: 15 additions & 0 deletions Bridge.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// Bridge.h
// TasksGalore
//
// Created by Fahim Farook on 15/6/14.
// Copyright (c) 2014 RookSoft Pte. Ltd. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface Bridge : NSObject

+(NSString *)esc:(NSString *)str;

@end
22 changes: 22 additions & 0 deletions Bridge.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// Bridge.m
// TasksGalore
//
// Created by Fahim Farook on 15/6/14.
// Copyright (c) 2014 RookSoft Pte. Ltd. All rights reserved.
//

#import "Bridge.h"
#import "sqlite3.h"

@implementation Bridge

+(NSString *)esc:(NSString *)str {
if (!str || [str length] == 0) {
return @"";
}
NSString *buf = @(sqlite3_mprintf("%q", [str cStringUsingEncoding:NSUTF8StringEncoding]));
return buf;
}

@end
11 changes: 11 additions & 0 deletions Bridging-Header.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//
// Bridging-Header.h
// TasksGalore
//
// Created by Fahim Farook on 12/6/14.
// Copyright (c) 2014 RookSoft Pte. Ltd. All rights reserved.
//

#import "sqlite3.h"
#import <time.h>
#import "Bridge.h"
13 changes: 4 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,10 @@ This is a basic SQLite wrapper for Swift. It is very simple at the moment and do

Adding to Your Project
---
* Create your SQLite database however you like but name it `data.db` and then add the `data.db` file to your Xcode project. (If you want to name the database file something other than `data.db`, then change the `DB_NAME` constant in the `SQLiteDB` class accordingly.)
* Add SQLiteDB.swift to your project
* If you don't have a bridging header file, create one. (It's just a header file - but it's usually named Bridging-Header.h or &lt;projectname&gt;-Bridging-Header.h).
* If you added a bridging header file, then make sure that you modify your project settings to point to the bridging header file. This will be under the "Build Settings" for your target and will be named "Objective-C Bridging Header".
* Add the following imports to your bridging header file:
```objective-c
#import <sqlite3.h>
#import <time.h>
```
* Create your SQLite database however you like, but name it `data.db` and then add the `data.db` file to your Xcode project. (If you want to name the database file something other than `data.db`, then change the `DB_NAME` constant in the `SQLiteDB` class accordingly.)
* Add all of the included source files (except for README.md, of course) to your project.
* If you don't have a bridging header file, use the included `Bridging-Header.h` file. If you already have a bridging header file, then copy the contents from the included `Bridging-Header.h` file in to your own bridging header file.
* If you didn't have a bridging header file, make sure that you modify your project settings to point to the new bridging header file. This will be under the "Build Settings" for your target and will be named "Objective-C Bridging Header".
* Add the SQLite library (libsqlite3.0.dylib) to your project under the "Build Phases" - "Link Binary With Libraries" section.

That's it. You're set!
Expand Down
64 changes: 47 additions & 17 deletions SQLiteDB.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ extension String {
}

class SQLRow {
let SQLITE_DATE = SQLITE_NULL + 1
var keys:String[] = String[]()
var values:Any[] = Any[]()
var types:CInt[] = CInt[]()
Expand All @@ -56,9 +57,20 @@ class SQLRow {
if type == SQLITE_INTEGER {
return val as Int
}
if type == SQLITE_TEXT {
return val as String
if type == SQLITE_FLOAT {
return val as Double
}
if type == SQLITE_BLOB {
return val as NSData
}
if type == SQLITE_NULL {
return nil
}
if type == SQLITE_DATE {
return val as NSDate
}
// Return everything else as String
return val as String
}
return nil
}
Expand All @@ -69,14 +81,13 @@ class SQLiteDB {
let SQLITE_DATE = SQLITE_NULL + 1
var db:COpaquePointer = nil
var queue:dispatch_queue_t = dispatch_queue_create("SQLiteDB", nil)
struct Static {
static var instance: SQLiteDB? = nil
static var token: dispatch_once_t = 0
}

class func sharedInstance() -> SQLiteDB! {
struct Static {
static var instance: SQLiteDB? = nil
static var onceToken: dispatch_once_t = 0
}

dispatch_once(&Static.onceToken) {
dispatch_once(&Static.token) {
println("SQLiteDB - Dispatch once")
Static.instance = self()
}
Expand All @@ -85,6 +96,7 @@ class SQLiteDB {

@required init() {
println("SQLiteDB - Init method")
assert(Static.instance == nil, "Singleton already initialized!")
// Get path to DB in Documents directory
let docDir:AnyObject = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0]
let dbName:String = String.fromCString(DB_NAME)
Expand Down Expand Up @@ -151,7 +163,7 @@ class SQLiteDB {
var cSql:CString = sql.bridgeToObjectiveC().cString()
var stmt:COpaquePointer = nil
// Prepare
result = sqlite3_prepare_v2(self.db, cSql, 0, &stmt, nil)
result = sqlite3_prepare_v2(self.db, cSql, -1, &stmt, nil)
if result != SQLITE_OK {
sqlite3_finalize(stmt)
let msg = "SQLiteDB - failed to prepare SQL: \(sql), Error: \(self.lastSQLError())"
Expand All @@ -161,7 +173,7 @@ class SQLiteDB {
}
// Step
result = sqlite3_step(stmt)
if result != SQLITE_OK {
if result != SQLITE_OK && result != SQLITE_DONE {
sqlite3_finalize(stmt)
let msg = "SQLiteDB - failed to execute SQL: \(sql), Error: \(self.lastSQLError())"
println(msg)
Expand Down Expand Up @@ -233,11 +245,23 @@ class SQLiteDB {
return rows
}

// SQL escape string
// SQL escape string - hacky version using an intermediate Objective-C class to make it work
func esc(str: String)->String {
var cstr:CString = str.bridgeToObjectiveC().cString()
// cstr = sqlite3_vmprintf("%Q", CVaListPointer(fromUnsafePointer: &cstr))
return ""
println("SQLiteDB - Original string: \(str)")
let sql = Bridge.esc(str)
println("SQLiteDB - Escaped string: \(sql)")
return sql
}

// SQL escape string - original version, does not work correctly at the moment
func esc2(str: String)->String {
println("SQLiteDB - Original string: \(str)")
let args = getVaList([str])
let cstr = sqlite3_vmprintf("%Q", args)
let sql = String.fromCString(cstr)
sqlite3_free(cstr)
println("SQLiteDB - Escaped string: \(sql)")
return sql
}

// Return last insert ID
Expand All @@ -252,7 +276,11 @@ class SQLiteDB {
// Return last SQL error
func lastSQLError()->String {
var err:CString? = nil
dispatch_sync(queue) {
if dispatch_get_current_queue() != queue {
dispatch_sync(queue) {
err = sqlite3_errmsg(self.db)
}
} else {
err = sqlite3_errmsg(self.db)
}
return (err ? NSString(CString:err!) : "")
Expand Down Expand Up @@ -356,16 +384,18 @@ class SQLiteDB {
let t = mktime(&time) + diff
let ti = NSTimeInterval(t)
let val = NSDate(timeIntervalSince1970:ti)
return val
}
}
// If not a text date, then it's a time interval
let val = sqlite3_column_double(stmt, index)
return Double(val)
let dt = NSDate(timeIntervalSince1970: val)
return dt
}
// If nothing works, return a string representation
let buf:UnsafePointer<CUnsignedChar> = sqlite3_column_text(stmt, index)
let cstr = CString(buf)
let val = String.fromCString(cstr)
return val
}
}
}

0 comments on commit 640b9d9

Please sign in to comment.