Skip to content
parfeon edited this page Feb 7, 2012 · 8 revisions

Welcome to the DBConnect Wiki!
In this Wiki section I will reveal some information about this wrapper and its classes. I will also show you (with example), why would you probably like to use wrappers (mine or some other).

#Wiki content:

##What's all about this wrappers

I'm sure, what all newcomers would ask themselves: "why do we need all these wrappers to work with SQLite?".
Ummm emmmm let's see what you will have to do, to insert one row of data into new table:

// Let's open some sqlite database connection  
sqlite3 *connection = NULL;  
int returnCode = sqlite3_open(':memory:', &connection);  
if(returnCode == SQLITE_OK){  // Check, whether the connection was opened  
    // Compile SQLite statement for table creation and evaluate SQL query to SQLite database  
    sqlite3_stmt *createStatement = NULL;  
    returnCode = sqlite3_prepare_v2(connection, "CREATE TABLE IF NOT EXISTS someTable (id INTEGER, 
                                                        fieldName1 TEXT, fieldName2 TEXT NOT NULL);", 
                                                -1, &createStatement, NULL);  
    if(returnCode == SQLITE_OK){  
        returnCode = sqlite3_step(createStatement);  
        if(returnCode == SQLITE_DONE){  // Check, whether the database was created or not  
            // Compile SQLite statement for data insertion and evaluate SQL query to SQLite database  
            sqlite3_stmt *insertStatement = NULL;  
            returnCode = sqlite3_prepare_v2(connection, "INSERT INTO someTable (id, fieldName1, fieldName2)  
                                                                        VALUES (?1, ?2, ?3);", 
                                                        -1, &insertStatement, NULL);  
        if(returnCode == SQLITE_DONE){  // Check, whether the table was created or not  
            // Now we need to bind some data. It will be placed instead of indexed tokens  
            sqlite3_bind_int(insertStatement, 1, 1);  
            sqlite3_bind_text(insertStatement, 2, [[@"First field value"] UTF8String], -1, SQLITE_STATIC);  
            sqlite3_bind_text(insertStatement, 3, [[@"Second field value"] UTF8String], -1, SQLITE_STATIC);  
            returnCode = sqlite3_step(insertStatement);  
            if(returnCode == SQLITE_OK){  // Check, whether the row was inserted or not  
                NSLog(@"Hurray!!! We finally inserted values into a new table and it was made \  
                      only with 28 lines of code o_O");  
            } else {  
                NSLog(@"Damn, we wrote 28 lines of code and failed to insert value into new table");  
            }
        } else {
            // Do something with table creation error
        }
    } else {  
        // Do something with error  
    }  	
    sqlite3_finalize(createStatement);  
    createStatement = NULL;  
    sqlite3_finalize(insertStatement);  
    insertStatement = NULL;  
    sqlite3_close(connection);  
    connection = NULL;  
}

Phew, you see, we don't have to write much code to add a single row into database, which has only 3 data fields. Code above uses 16 lines of code, which produces some changes to database and cleanups after it is completed. But what if you need to add data into a table with 20 fields? It already sounds like a real problem.
So here you will find that using wrappers is not just making code cleaner, but it is also fun ;)

For example, here is the same code as above, but performed with DBConnect:

  
// Let's open some sqlite database connection  
DBCDatabase *db = [[DBCDatabase alloc] initWithPath:@":memory:"];
if([db open]){  // Check, whether the connection was opened  
    // Create new table
    BOOL creationSuccessfull = [db evaluateUpdate:@"CREATE TABLE IF NOT EXISTS someTable (id INTEGER, 
                                                    fieldName1 TEXT, fieldName2 TEXT NOT NULL);", nil];
    if(creationSuccessfull){  // Check, whether the table was created or not  
        BOOL insertionSuccessfull = [db evaluateUpdate:@"CREATE TABLE IF NOT EXISTS someTable (?1, ?2, ?3);", 
                                                                                  [NSNumber numberWithInt:1],  
                                                                                  @"First field value",  
                                                                                  @"Second field value",
                                                                                  nil];
        if(insertionSuccessfull){
            NSLog(@"Hurray!!! We finally inserted values into new table and it was made \  
                  only with 12 lines of code. It looks much better and it is really human-readable");
        } else {
            NSLog(@"Damn, we wrote 12 lines of code and failed to insert value into new table");  
        }
    } else {
       // Do something with table creation error
    }
} else {
    // Handle database connection-open error
}
if([db close]){
    // Database is closed and resources, used while performing requests are released
} else {
    // It looks like we can't close database connection, probably someone holds database file
}

Code above shows, what wrappers (DBConnect in this case) make it really easy-to-use SQLite databases with Objective-C. In the shown example, there is only 4 lines of code, which does something with database, other lines are checking of conditions.You probably won't use those part of conditions most of time.

So, if you are still interested in my wrapper, you can proceed to Wiki content and head to interested class or section from there.
Top

##Thread-safe
As we all know, threads are basically used to perform some heavy operations outside of the main thread, in order to keep application's interface responsive to user. Well, this is SQLite Achilles heel and that's why they wrote that in their documentation: "Threads are evil. Avoid them".
So the main problem with SQLite is that you can't safely pass the database connection handler from thread, created to another thread. As they say, if sqlite3 binary compiled with SQLITE_THREADSAFE, everything will be fine. But that's not our case, because on Mac OS X and iOS sqlite3 binary is compiled without this flag, so we need to do something with this issue.
We can solve it by placing locks around thread-sensitive code and make sure, that you are using the same lock instance to lock/unlock. It is really annoying to place these locks almost everywhere and to control releasing of the lock. So I've made all this stuff for you. You can freely pass DBCDatabase instance to other threads or create one thread in other and perform queries. Fill free with threads now.
Top

##Installation DBConnect installation is fairly easy. All you need to do is to link libsqlite3.0.dylib library into you project and add file from DBConnect somewhere in your project.

##How-to's
There are not so many classes, which were provided to be used by programmer, so all of them have descriptions in implementation files for each of methods. But it's usually really hard to tech on methods description only, so I will provide some small examples in each class section (all classes have their Wiki page with example and description).
Top

##Classes
As I've written, on the main page of the project, DBConnect consist of three basic classes: DBCDatabase, DBCDatabaseResult, DBCDatabaseRow
There are also few extension categories for users, which would like to have easier way to adjust some database settings or get some SQL queries shortcut for some tasks. To be more precise, there are 2 categories: DBCDatabase+Aliases and DBCDatabase+Advanced.
And we also have some objects, which will help us to represent retrieved information from some methods of DBCDatabase+Aliases category: DBCDatabaseInfo, DBCDatabaseIndexInfo, DBCDatabaseIndexedColumnInfo, DBCDatabaseTableColumnInfo.

That's all that I wanted to tell you in this section
Top

Clone this wiki locally