SlideShare a Scribd company logo
SQLite Techniques

                              Ben Scheirman
                               @subdigital

                 Code / Slides:
       github.com/subdigital/iphonedevcon-
                    sandiego

Tuesday, September 28, 2010
SQLite is....

                 Single-user

                 File-based

                 Simple

                 Cross Platform

                 A subset of full ANSI SQL



Tuesday, September 28, 2010
SQLite API


                 Pure C API

                 Lots of strange-looking, hard to
                 debug code

                 Best choice is to abstract it away




Tuesday, September 28, 2010
SQLite Tools



                 SQLite Manager Add-in for Firefox

                 sqlite3 command line utility




Tuesday, September 28, 2010
Writable Databases


                 Your app bundle is signed!

                 (That means the contents can't
                 change)




Tuesday, September 28, 2010
Your App Sandbox




                              Your App Bundle


                                     Resources
                                                 Documents




Tuesday, September 28, 2010
Your App Sandbox




                              Your App Bundle


                                     Resources
                                                 Documents




Tuesday, September 28, 2010
Creating the
                            database


Tuesday, September 28, 2010
Getting Resource
                           Paths




Tuesday, September 28, 2010
Getting Resource
                           Paths

  //fetches	
  path	
  for	
  foo.db




Tuesday, September 28, 2010
Getting Resource
                           Paths

  //fetches	
  path	
  for	
  foo.db
  NSString	
  *resourcePath	
  =	
  [[NSBundle	
  mainBundle]




Tuesday, September 28, 2010
Getting Resource
                                   Paths

  //fetches	
  path	
  for	
  foo.db
  NSString	
  *resourcePath	
  =	
  [[NSBundle	
  mainBundle]
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  pathForResource:@"foo"




Tuesday, September 28, 2010
Getting Resource
                                   Paths

  //fetches	
  path	
  for	
  foo.db
  NSString	
  *resourcePath	
  =	
  [[NSBundle	
  mainBundle]
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  pathForResource:@"foo"
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ofType:@"db"];




Tuesday, September 28, 2010
Finding the Documents
              Directory




Tuesday, September 28, 2010
Finding the Documents
              Directory

            NSArray	
  *paths	
  =	
  NSSearchPathForDirectoriesInDomains(	
  




Tuesday, September 28, 2010
Finding the Documents
              Directory

            NSArray	
  *paths	
  =	
  NSSearchPathForDirectoriesInDomains(	
  
            	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  NSDocumentDirectory,	
  




Tuesday, September 28, 2010
Finding the Documents
              Directory

            NSArray	
  *paths	
  =	
  NSSearchPathForDirectoriesInDomains(	
  
            	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  NSDocumentDirectory,	
  
            	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  NSUserDomainMask,	
  




Tuesday, September 28, 2010
Finding the Documents
              Directory

            NSArray	
  *paths	
  =	
  NSSearchPathForDirectoriesInDomains(	
  
            	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  NSDocumentDirectory,	
  
            	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  NSUserDomainMask,	
  
            	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  YES);




Tuesday, September 28, 2010
Finding the Documents
              Directory

            NSArray	
  *paths	
  =	
  NSSearchPathForDirectoriesInDomains(	
  
            	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  NSDocumentDirectory,	
  
            	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  NSUserDomainMask,	
  
            	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  YES);

            NSString	
  *documentsDirectory	
  =	
  [paths	
  objectAtIndex:0];




Tuesday, September 28, 2010
Copy a default
              database on startup




Tuesday, September 28, 2010
Copy a default
              database on startup
         //in applicationDidFinishLaunching

         NSString *sourcePath = [[NSBundle mainBundle]
            pathForResource:@"app" ofType:@"db"];

         NSString *targetPath = ...
            NSFileManager *fm = [NSFileManager defaultManager];

         if(![fm fileExistsAtPath:targetPath]) {
           [fm copyItemAtPath:sourcePath toPath:targetPath error:&error];
         }




Tuesday, September 28, 2010
Copy a default
              database on startup
         //in applicationDidFinishLaunching

         NSString *sourcePath = [[NSBundle mainBundle]
            pathForResource:@"app" ofType:@"db"];

         NSString *targetPath = ...
            NSFileManager *fm = [NSFileManager defaultManager];

         if(![fm fileExistsAtPath:targetPath]) {
           [fm copyItemAtPath:sourcePath toPath:targetPath error:&error];
         }




Tuesday, September 28, 2010
Copy a default
              database on startup
         //in applicationDidFinishLaunching

         NSString *sourcePath = [[NSBundle mainBundle]
            pathForResource:@"app" ofType:@"db"];

         NSString *targetPath = ...
            NSFileManager *fm = [NSFileManager defaultManager];

         if(![fm fileExistsAtPath:targetPath]) {
           [fm copyItemAtPath:sourcePath toPath:targetPath error:&error];
         }




Tuesday, September 28, 2010
Copy a default
              database on startup
         //in applicationDidFinishLaunching

         NSString *sourcePath = [[NSBundle mainBundle]
            pathForResource:@"app" ofType:@"db"];

         NSString *targetPath = ...
            NSFileManager *fm = [NSFileManager defaultManager];

         if(![fm fileExistsAtPath:targetPath]) {
           [fm copyItemAtPath:sourcePath toPath:targetPath error:&error];
         }




Tuesday, September 28, 2010
Copy a default
              database on startup
         //in applicationDidFinishLaunching

         NSString *sourcePath = [[NSBundle mainBundle]
            pathForResource:@"app" ofType:@"db"];

         NSString *targetPath = ...
            NSFileManager *fm = [NSFileManager defaultManager];

         if(![fm fileExistsAtPath:targetPath]) {
           [fm copyItemAtPath:sourcePath toPath:targetPath error:&error];
         }




Tuesday, September 28, 2010
Copy a default
              database on startup
         //in applicationDidFinishLaunching

         NSString *sourcePath = [[NSBundle mainBundle]
            pathForResource:@"app" ofType:@"db"];

         NSString *targetPath = ...
            NSFileManager *fm = [NSFileManager defaultManager];

         if(![fm fileExistsAtPath:targetPath]) {
           [fm copyItemAtPath:sourcePath toPath:targetPath error:&error];
         }




Tuesday, September 28, 2010
Copy a default
              database on startup
         //in applicationDidFinishLaunching

         NSString *sourcePath = [[NSBundle mainBundle]
            pathForResource:@"app" ofType:@"db"];

         NSString *targetPath = ...
            NSFileManager *fm = [NSFileManager defaultManager];

         if(![fm fileExistsAtPath:targetPath]) {
           [fm copyItemAtPath:sourcePath toPath:targetPath error:&error];
         }




Tuesday, September 28, 2010
SQLite API Basics




Tuesday, September 28, 2010
Add the Framework




Tuesday, September 28, 2010
Add the Framework




Tuesday, September 28, 2010
Add the Framework




Tuesday, September 28, 2010
Add the Framework




Tuesday, September 28, 2010
SQLite API -
           Opening a connection




Tuesday, September 28, 2010
SQLite API -
           Opening a connection
     #import "sqlite3.h"




Tuesday, September 28, 2010
SQLite API -
           Opening a connection
     #import "sqlite3.h"

     sqlite3 *db;




Tuesday, September 28, 2010
SQLite API -
           Opening a connection
     #import "sqlite3.h"

     sqlite3 *db;

     int result = sqlite3_open(PATH, &db);




Tuesday, September 28, 2010
SQLite API -
           Opening a connection
     #import "sqlite3.h"

     sqlite3 *db;

     int result = sqlite3_open(PATH, &db);
     if (result != SQLITE_OK) {




Tuesday, September 28, 2010
SQLite API -
           Opening a connection
     #import "sqlite3.h"

     sqlite3 *db;

     int result = sqlite3_open(PATH, &db);
     if (result != SQLITE_OK) {
        [NSException raise:@"SQLITE ERROR"




Tuesday, September 28, 2010
SQLite API -
           Opening a connection
     #import "sqlite3.h"

     sqlite3 *db;

     int result = sqlite3_open(PATH, &db);
     if (result != SQLITE_OK) {
        [NSException raise:@"SQLITE ERROR"
                     format:@"Error %d", result];




Tuesday, September 28, 2010
SQLite API -
           Opening a connection
     #import "sqlite3.h"

     sqlite3 *db;

     int result = sqlite3_open(PATH, &db);
     if (result != SQLITE_OK) {
        [NSException raise:@"SQLITE ERROR"
                     format:@"Error %d", result];
     }




Tuesday, September 28, 2010
SQLite API -
           Opening a connection
     #import "sqlite3.h"

     sqlite3 *db;

     int result = sqlite3_open(PATH, &db);
     if (result != SQLITE_OK) {
        [NSException raise:@"SQLITE ERROR"
                     format:@"Error %d", result];
     }


     //later




Tuesday, September 28, 2010
SQLite API -
           Opening a connection
     #import "sqlite3.h"

     sqlite3 *db;

     int result = sqlite3_open(PATH, &db);
     if (result != SQLITE_OK) {
        [NSException raise:@"SQLITE ERROR"
                     format:@"Error %d", result];
     }


     //later
     sqlite3_close(db);




Tuesday, September 28, 2010
SQLite API -
                   executing queries




Tuesday, September 28, 2010
SQLite API -
                   executing queries
     int sqlite3_exec(




Tuesday, September 28, 2010
SQLite API -
                   executing queries
     int sqlite3_exec(
        sqlite3 *db,




Tuesday, September 28, 2010
SQLite API -
                   executing queries
     int sqlite3_exec(
        sqlite3 *db,
        char *sql,




Tuesday, September 28, 2010
SQLite API -
                   executing queries
     int sqlite3_exec(
        sqlite3 *db,
        char *sql,
        int (*callback)(void *, int, char**, char**) callbackFunc,




Tuesday, September 28, 2010
SQLite API -
                   executing queries
     int sqlite3_exec(
        sqlite3 *db,
        char *sql,
        int (*callback)(void *, int, char**, char**) callbackFunc,
        void *context,




Tuesday, September 28, 2010
SQLite API -
                   executing queries
     int sqlite3_exec(
        sqlite3 *db,
        char *sql,
        int (*callback)(void *, int, char**, char**) callbackFunc,
        void *context,
        char **errorMessage




Tuesday, September 28, 2010
SQLite API -
                   executing queries
     int sqlite3_exec(
        sqlite3 *db,
        char *sql,
        int (*callback)(void *, int, char**, char**) callbackFunc,
        void *context,
        char **errorMessage
        );




Tuesday, September 28, 2010
SQLite API -
                   executing queries
     int sqlite3_exec(
        sqlite3 *db,
        char *sql,
        int (*callback)(void *, int, char**, char**) callbackFunc,
        void *context,
        char **errorMessage
        );


     //callback signature




Tuesday, September 28, 2010
SQLite API -
                   executing queries
     int sqlite3_exec(
        sqlite3 *db,
        char *sql,
        int (*callback)(void *, int, char**, char**) callbackFunc,
        void *context,
        char **errorMessage
        );


     //callback signature
     int RowCallback(void * context,




Tuesday, September 28, 2010
SQLite API -
                   executing queries
     int sqlite3_exec(
        sqlite3 *db,
        char *sql,
        int (*callback)(void *, int, char**, char**) callbackFunc,
        void *context,
        char **errorMessage
        );


     //callback signature
     int RowCallback(void * context,
        int numColumns,




Tuesday, September 28, 2010
SQLite API -
                   executing queries
     int sqlite3_exec(
        sqlite3 *db,
        char *sql,
        int (*callback)(void *, int, char**, char**) callbackFunc,
        void *context,
        char **errorMessage
        );


     //callback signature
     int RowCallback(void * context,
        int numColumns,
        char** colValues,




Tuesday, September 28, 2010
SQLite API -
                   executing queries
     int sqlite3_exec(
        sqlite3 *db,
        char *sql,
        int (*callback)(void *, int, char**, char**) callbackFunc,
        void *context,
        char **errorMessage
        );


     //callback signature
     int RowCallback(void * context,
        int numColumns,
        char** colValues,
        char ** colNames);




Tuesday, September 28, 2010
SQLite API -
              Prepared Statements


           More Powerful

           Unfortunately much more code!




Tuesday, September 28, 2010
SQLite API-Prepared Statements




Tuesday, September 28, 2010
SQLite API-Prepared Statements


        sqlite3 *db;




Tuesday, September 28, 2010
SQLite API-Prepared Statements


        sqlite3 *db;
        int result = sqlite3_open(DB_PATH, &db);




Tuesday, September 28, 2010
SQLite API-Prepared Statements


        sqlite3 *db;
        int result = sqlite3_open(DB_PATH, &db);
        if(result != SQLITE_OK) {




Tuesday, September 28, 2010
SQLite API-Prepared Statements


        sqlite3 *db;
        int result = sqlite3_open(DB_PATH, &db);
        if(result != SQLITE_OK) {
            //handle error




Tuesday, September 28, 2010
SQLite API-Prepared Statements


        sqlite3 *db;
        int result = sqlite3_open(DB_PATH, &db);
        if(result != SQLITE_OK) {
            //handle error
        }




Tuesday, September 28, 2010
SQLite API-Prepared Statements


        sqlite3 *db;
        int result = sqlite3_open(DB_PATH, &db);
        if(result != SQLITE_OK) {
            //handle error
        }




Tuesday, September 28, 2010
SQLite API-Prepared Statements


        sqlite3 *db;
        int result = sqlite3_open(DB_PATH, &db);
        if(result != SQLITE_OK) {
            //handle error
        }

        sqlite3_stmt *stmt;




Tuesday, September 28, 2010
SQLite API-Prepared Statements


        sqlite3 *db;
        int result = sqlite3_open(DB_PATH, &db);
        if(result != SQLITE_OK) {
            //handle error
        }

        sqlite3_stmt *stmt;
        result = sqlite3_prepare_v2(db, sql_cstring, -1, &stmt, NULL);




Tuesday, September 28, 2010
SQLite API-Prepared Statements


        sqlite3 *db;
        int result = sqlite3_open(DB_PATH, &db);
        if(result != SQLITE_OK) {
            //handle error
        }

        sqlite3_stmt *stmt;
        result = sqlite3_prepare_v2(db, sql_cstring, -1, &stmt, NULL);
        if(result != SQLITE_OK) {




Tuesday, September 28, 2010
SQLite API-Prepared Statements


        sqlite3 *db;
        int result = sqlite3_open(DB_PATH, &db);
        if(result != SQLITE_OK) {
            //handle error
        }

        sqlite3_stmt *stmt;
        result = sqlite3_prepare_v2(db, sql_cstring, -1, &stmt, NULL);
        if(result != SQLITE_OK) {
            //handle error




Tuesday, September 28, 2010
SQLite API-Prepared Statements


        sqlite3 *db;
        int result = sqlite3_open(DB_PATH, &db);
        if(result != SQLITE_OK) {
            //handle error
        }

        sqlite3_stmt *stmt;
        result = sqlite3_prepare_v2(db, sql_cstring, -1, &stmt, NULL);
        if(result != SQLITE_OK) {
            //handle error
        }




Tuesday, September 28, 2010
SQLite API-Prepared Statements


        sqlite3 *db;
        int result = sqlite3_open(DB_PATH, &db);
        if(result != SQLITE_OK) {
            //handle error
        }

        sqlite3_stmt *stmt;
        result = sqlite3_prepare_v2(db, sql_cstring, -1, &stmt, NULL);
        if(result != SQLITE_OK) {
            //handle error
        }

        //...




Tuesday, September 28, 2010
SQLite API-Prepared Statements


        sqlite3 *db;
        int result = sqlite3_open(DB_PATH, &db);
        if(result != SQLITE_OK) {
            //handle error
        }

        sqlite3_stmt *stmt;
        result = sqlite3_prepare_v2(db, sql_cstring, -1, &stmt, NULL);
        if(result != SQLITE_OK) {
            //handle error
        }

        //...




Tuesday, September 28, 2010
SQLite API-Prepared Statements


        sqlite3 *db;
        int result = sqlite3_open(DB_PATH, &db);
        if(result != SQLITE_OK) {
            //handle error
        }

        sqlite3_stmt *stmt;
        result = sqlite3_prepare_v2(db, sql_cstring, -1, &stmt, NULL);
        if(result != SQLITE_OK) {
            //handle error
        }

        //...




Tuesday, September 28, 2010
SQLite API-Prepared Statements


        sqlite3 *db;
        int result = sqlite3_open(DB_PATH, &db);
        if(result != SQLITE_OK) {
            //handle error
        }

        sqlite3_stmt *stmt;
        result = sqlite3_prepare_v2(db, sql_cstring, -1, &stmt, NULL);
        if(result != SQLITE_OK) {
            //handle error
        }

        //...




Tuesday, September 28, 2010
SQLite API-Prepared Statements




Tuesday, September 28, 2010
SQLite API-Prepared Statements
      //INSERT INTO CARS(year, make) VALUES(?, ?)




Tuesday, September 28, 2010
SQLite API-Prepared Statements
      //INSERT INTO CARS(year, make) VALUES(?, ?)

      //PARAMETERS HAVE A 1-BASED INDEX!




Tuesday, September 28, 2010
SQLite API-Prepared Statements
      //INSERT INTO CARS(year, make) VALUES(?, ?)

      //PARAMETERS HAVE A 1-BASED INDEX!
      sqlite3_bind_int(stmt, 1 /* idx */, 5);




Tuesday, September 28, 2010
SQLite API-Prepared Statements
      //INSERT INTO CARS(year, make) VALUES(?, ?)

      //PARAMETERS HAVE A 1-BASED INDEX!
      sqlite3_bind_int(stmt, 1 /* idx */, 5);
      sqlite3_bind_text(stmt, 2 /* idx */,"value", -1, SQLITE_TRANSIENT);




Tuesday, September 28, 2010
SQLite API-Prepared Statements
      //INSERT INTO CARS(year, make) VALUES(?, ?)

      //PARAMETERS HAVE A 1-BASED INDEX!
      sqlite3_bind_int(stmt, 1 /* idx */, 5);
      sqlite3_bind_text(stmt, 2 /* idx */,"value", -1, SQLITE_TRANSIENT);




Tuesday, September 28, 2010
SQLite API-Prepared Statements
      //INSERT INTO CARS(year, make) VALUES(?, ?)

      //PARAMETERS HAVE A 1-BASED INDEX!
      sqlite3_bind_int(stmt, 1 /* idx */, 5);
      sqlite3_bind_text(stmt, 2 /* idx */,"value", -1, SQLITE_TRANSIENT);

      result = sqlite3_step(stmt);




Tuesday, September 28, 2010
SQLite API-Prepared Statements
      //INSERT INTO CARS(year, make) VALUES(?, ?)

      //PARAMETERS HAVE A 1-BASED INDEX!
      sqlite3_bind_int(stmt, 1 /* idx */, 5);
      sqlite3_bind_text(stmt, 2 /* idx */,"value", -1, SQLITE_TRANSIENT);

      result = sqlite3_step(stmt);
      if(result == SQLITE_DONE)




Tuesday, September 28, 2010
SQLite API-Prepared Statements
      //INSERT INTO CARS(year, make) VALUES(?, ?)

      //PARAMETERS HAVE A 1-BASED INDEX!
      sqlite3_bind_int(stmt, 1 /* idx */, 5);
      sqlite3_bind_text(stmt, 2 /* idx */,"value", -1, SQLITE_TRANSIENT);

      result = sqlite3_step(stmt);
      if(result == SQLITE_DONE)
          return [NSArray array]; //nothing to do!




Tuesday, September 28, 2010
SQLite API-Prepared Statements
      //INSERT INTO CARS(year, make) VALUES(?, ?)

      //PARAMETERS HAVE A 1-BASED INDEX!
      sqlite3_bind_int(stmt, 1 /* idx */, 5);
      sqlite3_bind_text(stmt, 2 /* idx */,"value", -1, SQLITE_TRANSIENT);

      result = sqlite3_step(stmt);
      if(result == SQLITE_DONE)
          return [NSArray array]; //nothing to do!




Tuesday, September 28, 2010
SQLite API-Prepared Statements
      //INSERT INTO CARS(year, make) VALUES(?, ?)

      //PARAMETERS HAVE A 1-BASED INDEX!
      sqlite3_bind_int(stmt, 1 /* idx */, 5);
      sqlite3_bind_text(stmt, 2 /* idx */,"value", -1, SQLITE_TRANSIENT);

      result = sqlite3_step(stmt);
      if(result == SQLITE_DONE)
          return [NSArray array]; //nothing to do!

      NSMutableArray *results = [NSMutableArray array];




Tuesday, September 28, 2010
SQLite API-Prepared Statements
      //INSERT INTO CARS(year, make) VALUES(?, ?)

      //PARAMETERS HAVE A 1-BASED INDEX!
      sqlite3_bind_int(stmt, 1 /* idx */, 5);
      sqlite3_bind_text(stmt, 2 /* idx */,"value", -1, SQLITE_TRANSIENT);

      result = sqlite3_step(stmt);
      if(result == SQLITE_DONE)
          return [NSArray array]; //nothing to do!

      NSMutableArray *results = [NSMutableArray array];
      while(result == SQLITE_ROW) {




Tuesday, September 28, 2010
SQLite API-Prepared Statements
      //INSERT INTO CARS(year, make) VALUES(?, ?)

      //PARAMETERS HAVE A 1-BASED INDEX!
      sqlite3_bind_int(stmt, 1 /* idx */, 5);
      sqlite3_bind_text(stmt, 2 /* idx */,"value", -1, SQLITE_TRANSIENT);

      result = sqlite3_step(stmt);
      if(result == SQLITE_DONE)
          return [NSArray array]; //nothing to do!

      NSMutableArray *results = [NSMutableArray array];
      while(result == SQLITE_ROW) {
          NSMutableDictionary *row = [NSMutableDictionary dictionary];




Tuesday, September 28, 2010
SQLite API-Prepared Statements
      //INSERT INTO CARS(year, make) VALUES(?, ?)

      //PARAMETERS HAVE A 1-BASED INDEX!
      sqlite3_bind_int(stmt, 1 /* idx */, 5);
      sqlite3_bind_text(stmt, 2 /* idx */,"value", -1, SQLITE_TRANSIENT);

      result = sqlite3_step(stmt);
      if(result == SQLITE_DONE)
          return [NSArray array]; //nothing to do!

      NSMutableArray *results = [NSMutableArray array];
      while(result == SQLITE_ROW) {
          NSMutableDictionary *row = [NSMutableDictionary dictionary];




Tuesday, September 28, 2010
SQLite API-Prepared Statements
      //INSERT INTO CARS(year, make) VALUES(?, ?)

      //PARAMETERS HAVE A 1-BASED INDEX!
      sqlite3_bind_int(stmt, 1 /* idx */, 5);
      sqlite3_bind_text(stmt, 2 /* idx */,"value", -1, SQLITE_TRANSIENT);

      result = sqlite3_step(stmt);
      if(result == SQLITE_DONE)
          return [NSArray array]; //nothing to do!

      NSMutableArray *results = [NSMutableArray array];
      while(result == SQLITE_ROW) {
          NSMutableDictionary *row = [NSMutableDictionary dictionary];

             [self processRow:row forStatement:stmt];




Tuesday, September 28, 2010
SQLite API-Prepared Statements
      //INSERT INTO CARS(year, make) VALUES(?, ?)

      //PARAMETERS HAVE A 1-BASED INDEX!
      sqlite3_bind_int(stmt, 1 /* idx */, 5);
      sqlite3_bind_text(stmt, 2 /* idx */,"value", -1, SQLITE_TRANSIENT);

      result = sqlite3_step(stmt);
      if(result == SQLITE_DONE)
          return [NSArray array]; //nothing to do!

      NSMutableArray *results = [NSMutableArray array];
      while(result == SQLITE_ROW) {
          NSMutableDictionary *row = [NSMutableDictionary dictionary];

             [self processRow:row forStatement:stmt];

             [results addObject:row];




Tuesday, September 28, 2010
SQLite API-Prepared Statements
      //INSERT INTO CARS(year, make) VALUES(?, ?)

      //PARAMETERS HAVE A 1-BASED INDEX!
      sqlite3_bind_int(stmt, 1 /* idx */, 5);
      sqlite3_bind_text(stmt, 2 /* idx */,"value", -1, SQLITE_TRANSIENT);

      result = sqlite3_step(stmt);
      if(result == SQLITE_DONE)
          return [NSArray array]; //nothing to do!

      NSMutableArray *results = [NSMutableArray array];
      while(result == SQLITE_ROW) {
          NSMutableDictionary *row = [NSMutableDictionary dictionary];

             [self processRow:row forStatement:stmt];

             [results addObject:row];
             result = sqlite3_step(stmt);




Tuesday, September 28, 2010
SQLite API-Prepared Statements
      //INSERT INTO CARS(year, make) VALUES(?, ?)

      //PARAMETERS HAVE A 1-BASED INDEX!
      sqlite3_bind_int(stmt, 1 /* idx */, 5);
      sqlite3_bind_text(stmt, 2 /* idx */,"value", -1, SQLITE_TRANSIENT);

      result = sqlite3_step(stmt);
      if(result == SQLITE_DONE)
          return [NSArray array]; //nothing to do!

      NSMutableArray *results = [NSMutableArray array];
      while(result == SQLITE_ROW) {
          NSMutableDictionary *row = [NSMutableDictionary dictionary];

             [self processRow:row forStatement:stmt];

             [results addObject:row];
             result = sqlite3_step(stmt);
      }




Tuesday, September 28, 2010
SQLite API-Prepared Statements
      //INSERT INTO CARS(year, make) VALUES(?, ?)

      //PARAMETERS HAVE A 1-BASED INDEX!
      sqlite3_bind_int(stmt, 1 /* idx */, 5);
      sqlite3_bind_text(stmt, 2 /* idx */,"value", -1, SQLITE_TRANSIENT);

      result = sqlite3_step(stmt);
      if(result == SQLITE_DONE)
          return [NSArray array]; //nothing to do!

      NSMutableArray *results = [NSMutableArray array];
      while(result == SQLITE_ROW) {
          NSMutableDictionary *row = [NSMutableDictionary dictionary];

             [self processRow:row forStatement:stmt];

             [results addObject:row];
             result = sqlite3_step(stmt);
      }

      sqlite_finalize(stmt);



Tuesday, September 28, 2010
SQLite API-Prepared Statements
      //INSERT INTO CARS(year, make) VALUES(?, ?)

      //PARAMETERS HAVE A 1-BASED INDEX!
      sqlite3_bind_int(stmt, 1 /* idx */, 5);
      sqlite3_bind_text(stmt, 2 /* idx */,"value", -1, SQLITE_TRANSIENT);

      result = sqlite3_step(stmt);
      if(result == SQLITE_DONE)
          return [NSArray array]; //nothing to do!

      NSMutableArray *results = [NSMutableArray array];
      while(result == SQLITE_ROW) {
          NSMutableDictionary *row = [NSMutableDictionary dictionary];

             [self processRow:row forStatement:stmt];

             [results addObject:row];
             result = sqlite3_step(stmt);
      }

      sqlite_finalize(stmt);



Tuesday, September 28, 2010
SQLite API-Prepared Statements
      //INSERT INTO CARS(year, make) VALUES(?, ?)

      //PARAMETERS HAVE A 1-BASED INDEX!
      sqlite3_bind_int(stmt, 1 /* idx */, 5);
      sqlite3_bind_text(stmt, 2 /* idx */,"value", -1, SQLITE_TRANSIENT);

      result = sqlite3_step(stmt);
      if(result == SQLITE_DONE)
          return [NSArray array]; //nothing to do!

      NSMutableArray *results = [NSMutableArray array];
      while(result == SQLITE_ROW) {
          NSMutableDictionary *row = [NSMutableDictionary dictionary];

             [self processRow:row forStatement:stmt];

             [results addObject:row];
             result = sqlite3_step(stmt);
      }

      sqlite_finalize(stmt);

      return results;
Tuesday, September 28, 2010
SQLite API-Prepared Statements




Tuesday, September 28, 2010
SQLite API-Prepared Statements

-(void)processRow:(NSMutableDictionary *)row forStatement:
(sqlite3_stmt*)stmt {




Tuesday, September 28, 2010
SQLite API-Prepared Statements

-(void)processRow:(NSMutableDictionary *)row forStatement:
(sqlite3_stmt*)stmt {
  int columnCount = sqlite3_column_count(stmt);




Tuesday, September 28, 2010
SQLite API-Prepared Statements

-(void)processRow:(NSMutableDictionary *)row forStatement:
(sqlite3_stmt*)stmt {
  int columnCount = sqlite3_column_count(stmt);
  for(int i=0; i<columnCount; i++) {




Tuesday, September 28, 2010
SQLite API-Prepared Statements

-(void)processRow:(NSMutableDictionary *)row forStatement:
(sqlite3_stmt*)stmt {
  int columnCount = sqlite3_column_count(stmt);
  for(int i=0; i<columnCount; i++) {
      //0-based index!




Tuesday, September 28, 2010
SQLite API-Prepared Statements

-(void)processRow:(NSMutableDictionary *)row forStatement:
(sqlite3_stmt*)stmt {
  int columnCount = sqlite3_column_count(stmt);
  for(int i=0; i<columnCount; i++) {
      //0-based index!
      const char * colName = sqlite3_column_name(stmt, i);




Tuesday, September 28, 2010
SQLite API-Prepared Statements

-(void)processRow:(NSMutableDictionary *)row forStatement:
(sqlite3_stmt*)stmt {
  int columnCount = sqlite3_column_count(stmt);
  for(int i=0; i<columnCount; i++) {
      //0-based index!
      const char * colName = sqlite3_column_name(stmt, i);
      int type = sqlite3_column_type(stmt, i);




Tuesday, September 28, 2010
SQLite API-Prepared Statements

-(void)processRow:(NSMutableDictionary *)row forStatement:
(sqlite3_stmt*)stmt {
  int columnCount = sqlite3_column_count(stmt);
  for(int i=0; i<columnCount; i++) {
      //0-based index!
      const char * colName = sqlite3_column_name(stmt, i);
      int type = sqlite3_column_type(stmt, i);

          id value = [NSNull null];




Tuesday, September 28, 2010
SQLite API-Prepared Statements

-(void)processRow:(NSMutableDictionary *)row forStatement:
(sqlite3_stmt*)stmt {
  int columnCount = sqlite3_column_count(stmt);
  for(int i=0; i<columnCount; i++) {
      //0-based index!
      const char * colName = sqlite3_column_name(stmt, i);
      int type = sqlite3_column_type(stmt, i);

          id value = [NSNull null];
          if(type == SQLITE_INTEGER) {




Tuesday, September 28, 2010
SQLite API-Prepared Statements

-(void)processRow:(NSMutableDictionary *)row forStatement:
(sqlite3_stmt*)stmt {
  int columnCount = sqlite3_column_count(stmt);
  for(int i=0; i<columnCount; i++) {
      //0-based index!
      const char * colName = sqlite3_column_name(stmt, i);
      int type = sqlite3_column_type(stmt, i);

          id value = [NSNull null];
          if(type == SQLITE_INTEGER) {
             value = [NSNumber numberWithInt:sqlite3_column_int(stmt, i)];




Tuesday, September 28, 2010
SQLite API-Prepared Statements

-(void)processRow:(NSMutableDictionary *)row forStatement:
(sqlite3_stmt*)stmt {
  int columnCount = sqlite3_column_count(stmt);
  for(int i=0; i<columnCount; i++) {
      //0-based index!
      const char * colName = sqlite3_column_name(stmt, i);
      int type = sqlite3_column_type(stmt, i);

          id value = [NSNull null];
          if(type == SQLITE_INTEGER) {
             value = [NSNumber numberWithInt:sqlite3_column_int(stmt, i)];
          } else if (type == SQLITE_TEXT) {




Tuesday, September 28, 2010
SQLite API-Prepared Statements

-(void)processRow:(NSMutableDictionary *)row forStatement:
(sqlite3_stmt*)stmt {
  int columnCount = sqlite3_column_count(stmt);
  for(int i=0; i<columnCount; i++) {
      //0-based index!
      const char * colName = sqlite3_column_name(stmt, i);
      int type = sqlite3_column_type(stmt, i);

          id value = [NSNull null];
          if(type == SQLITE_INTEGER) {
             value = [NSNumber numberWithInt:sqlite3_column_int(stmt, i)];
          } else if (type == SQLITE_TEXT) {
             const unsigned char * text = sqlite3_column_text(stmt, i);




Tuesday, September 28, 2010
SQLite API-Prepared Statements

-(void)processRow:(NSMutableDictionary *)row forStatement:
(sqlite3_stmt*)stmt {
  int columnCount = sqlite3_column_count(stmt);
  for(int i=0; i<columnCount; i++) {
      //0-based index!
      const char * colName = sqlite3_column_name(stmt, i);
      int type = sqlite3_column_type(stmt, i);

          id value = [NSNull null];
          if(type == SQLITE_INTEGER) {
             value = [NSNumber numberWithInt:sqlite3_column_int(stmt, i)];
          } else if (type == SQLITE_TEXT) {
             const unsigned char * text = sqlite3_column_text(stmt, i);
             value = [NSString stringWithFormat:@"%s", text];




Tuesday, September 28, 2010
SQLite API-Prepared Statements

-(void)processRow:(NSMutableDictionary *)row forStatement:
(sqlite3_stmt*)stmt {
  int columnCount = sqlite3_column_count(stmt);
  for(int i=0; i<columnCount; i++) {
      //0-based index!
      const char * colName = sqlite3_column_name(stmt, i);
      int type = sqlite3_column_type(stmt, i);

          id value = [NSNull null];
          if(type == SQLITE_INTEGER) {
             value = [NSNumber numberWithInt:sqlite3_column_int(stmt, i)];
          } else if (type == SQLITE_TEXT) {
             const unsigned char * text = sqlite3_column_text(stmt, i);
             value = [NSString stringWithFormat:@"%s", text];
          } else {




Tuesday, September 28, 2010
SQLite API-Prepared Statements

-(void)processRow:(NSMutableDictionary *)row forStatement:
(sqlite3_stmt*)stmt {
  int columnCount = sqlite3_column_count(stmt);
  for(int i=0; i<columnCount; i++) {
      //0-based index!
      const char * colName = sqlite3_column_name(stmt, i);
      int type = sqlite3_column_type(stmt, i);

          id value = [NSNull null];
          if(type == SQLITE_INTEGER) {
             value = [NSNumber numberWithInt:sqlite3_column_int(stmt, i)];
          } else if (type == SQLITE_TEXT) {
             const unsigned char * text = sqlite3_column_text(stmt, i);
             value = [NSString stringWithFormat:@"%s", text];
          } else {
             // more type handling




Tuesday, September 28, 2010
SQLite API-Prepared Statements

-(void)processRow:(NSMutableDictionary *)row forStatement:
(sqlite3_stmt*)stmt {
  int columnCount = sqlite3_column_count(stmt);
  for(int i=0; i<columnCount; i++) {
      //0-based index!
      const char * colName = sqlite3_column_name(stmt, i);
      int type = sqlite3_column_type(stmt, i);

          id value = [NSNull null];
          if(type == SQLITE_INTEGER) {
             value = [NSNumber numberWithInt:sqlite3_column_int(stmt, i)];
          } else if (type == SQLITE_TEXT) {
             const unsigned char * text = sqlite3_column_text(stmt, i);
             value = [NSString stringWithFormat:@"%s", text];
          } else {
             // more type handling
          }




Tuesday, September 28, 2010
SQLite API-Prepared Statements

-(void)processRow:(NSMutableDictionary *)row forStatement:
(sqlite3_stmt*)stmt {
  int columnCount = sqlite3_column_count(stmt);
  for(int i=0; i<columnCount; i++) {
      //0-based index!
      const char * colName = sqlite3_column_name(stmt, i);
      int type = sqlite3_column_type(stmt, i);

          id value = [NSNull null];
          if(type == SQLITE_INTEGER) {
             value = [NSNumber numberWithInt:sqlite3_column_int(stmt, i)];
          } else if (type == SQLITE_TEXT) {
             const unsigned char * text = sqlite3_column_text(stmt, i);
             value = [NSString stringWithFormat:@"%s", text];
          } else {
             // more type handling
          }
          [row setObject:value forKey:



Tuesday, September 28, 2010
SQLite API-Prepared Statements

-(void)processRow:(NSMutableDictionary *)row forStatement:
(sqlite3_stmt*)stmt {
  int columnCount = sqlite3_column_count(stmt);
  for(int i=0; i<columnCount; i++) {
      //0-based index!
      const char * colName = sqlite3_column_name(stmt, i);
      int type = sqlite3_column_type(stmt, i);

          id value = [NSNull null];
          if(type == SQLITE_INTEGER) {
             value = [NSNumber numberWithInt:sqlite3_column_int(stmt, i)];
          } else if (type == SQLITE_TEXT) {
             const unsigned char * text = sqlite3_column_text(stmt, i);
             value = [NSString stringWithFormat:@"%s", text];
          } else {
             // more type handling
          }
          [row setObject:value forKey:
              [NSString stringWithUTF8String:colName]];


Tuesday, September 28, 2010
SQLite API-Prepared Statements

-(void)processRow:(NSMutableDictionary *)row forStatement:
(sqlite3_stmt*)stmt {
  int columnCount = sqlite3_column_count(stmt);
  for(int i=0; i<columnCount; i++) {
      //0-based index!
      const char * colName = sqlite3_column_name(stmt, i);
      int type = sqlite3_column_type(stmt, i);

          id value = [NSNull null];
          if(type == SQLITE_INTEGER) {
             value = [NSNumber numberWithInt:sqlite3_column_int(stmt, i)];
          } else if (type == SQLITE_TEXT) {
             const unsigned char * text = sqlite3_column_text(stmt, i);
             value = [NSString stringWithFormat:@"%s", text];
          } else {
             // more type handling
          }
          [row setObject:value forKey:
              [NSString stringWithUTF8String:colName]];
   }

Tuesday, September 28, 2010
SQLite API-Prepared Statements

-(void)processRow:(NSMutableDictionary *)row forStatement:
(sqlite3_stmt*)stmt {
  int columnCount = sqlite3_column_count(stmt);
  for(int i=0; i<columnCount; i++) {
      //0-based index!
      const char * colName = sqlite3_column_name(stmt, i);
      int type = sqlite3_column_type(stmt, i);

          id value = [NSNull null];
          if(type == SQLITE_INTEGER) {
             value = [NSNumber numberWithInt:sqlite3_column_int(stmt, i)];
          } else if (type == SQLITE_TEXT) {
             const unsigned char * text = sqlite3_column_text(stmt, i);
             value = [NSString stringWithFormat:@"%s", text];
          } else {
             // more type handling
          }
          [row setObject:value forKey:
              [NSString stringWithUTF8String:colName]];
    }
}
Tuesday, September 28, 2010
FMDB


                 http://github.com/ccgus/fmdb




Tuesday, September 28, 2010
FMDB Usage




Tuesday, September 28, 2010
FMDB Usage
           FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];




Tuesday, September 28, 2010
FMDB Usage
           FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];
           if (![db open])




Tuesday, September 28, 2010
FMDB Usage
           FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];
           if (![db open])
              NSLog(@"Could not open db.");




Tuesday, September 28, 2010
FMDB Usage
           FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];
           if (![db open])
              NSLog(@"Could not open db.");

           [db executeUpdate:@"blah blah blah"];




Tuesday, September 28, 2010
FMDB Usage
           FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];
           if (![db open])
              NSLog(@"Could not open db.");

           [db executeUpdate:@"blah blah blah"];
             




Tuesday, September 28, 2010
FMDB Usage
           FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];
           if (![db open])
              NSLog(@"Could not open db.");

           [db executeUpdate:@"blah blah blah"];
             
           if ([db hadError])




Tuesday, September 28, 2010
FMDB Usage
           FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];
           if (![db open])
              NSLog(@"Could not open db.");

           [db executeUpdate:@"blah blah blah"];
             
           if ([db hadError])
            NSLog(@"Err %d: %@", [db lastErrorCode],




Tuesday, September 28, 2010
FMDB Usage
           FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];
           if (![db open])
              NSLog(@"Could not open db.");

           [db executeUpdate:@"blah blah blah"];
             
           if ([db hadError])
            NSLog(@"Err %d: %@", [db lastErrorCode],
                [db lastErrorMessage]);




Tuesday, September 28, 2010
FMDB Usage
           FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];
           if (![db open])
              NSLog(@"Could not open db.");

           [db executeUpdate:@"blah blah blah"];
             
           if ([db hadError])
            NSLog(@"Err %d: %@", [db lastErrorCode],
                [db lastErrorMessage]);

           [db executeUpdate:@"create table test (a text, b integer)"];




Tuesday, September 28, 2010
FMDB Usage
           FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];
           if (![db open])
              NSLog(@"Could not open db.");

           [db executeUpdate:@"blah blah blah"];
             
           if ([db hadError])
            NSLog(@"Err %d: %@", [db lastErrorCode],
                [db lastErrorMessage]);

           [db executeUpdate:@"create table test (a text, b integer)"];

           [db beginTransaction];




Tuesday, September 28, 2010
FMDB Usage
           FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];
           if (![db open])
              NSLog(@"Could not open db.");

           [db executeUpdate:@"blah blah blah"];
             
           if ([db hadError])
            NSLog(@"Err %d: %@", [db lastErrorCode],
                [db lastErrorMessage]);

           [db executeUpdate:@"create table test (a text, b integer)"];

           [db beginTransaction];
           int i = 0;




Tuesday, September 28, 2010
FMDB Usage
           FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];
           if (![db open])
              NSLog(@"Could not open db.");

           [db executeUpdate:@"blah blah blah"];
             
           if ([db hadError])
            NSLog(@"Err %d: %@", [db lastErrorCode],
                [db lastErrorMessage]);

           [db executeUpdate:@"create table test (a text, b integer)"];

           [db beginTransaction];
           int i = 0;
           while (i++ < 20) {




Tuesday, September 28, 2010
FMDB Usage
           FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];
           if (![db open])
              NSLog(@"Could not open db.");

           [db executeUpdate:@"blah blah blah"];
             
           if ([db hadError])
            NSLog(@"Err %d: %@", [db lastErrorCode],
                [db lastErrorMessage]);

           [db executeUpdate:@"create table test (a text, b integer)"];

           [db beginTransaction];
           int i = 0;
           while (i++ < 20) {
             [db executeUpdate:@"insert into test (a, b) values (?, ?)" ,




Tuesday, September 28, 2010
FMDB Usage
           FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];
           if (![db open])
              NSLog(@"Could not open db.");

           [db executeUpdate:@"blah blah blah"];
             
           if ([db hadError])
            NSLog(@"Err %d: %@", [db lastErrorCode],
                [db lastErrorMessage]);

           [db executeUpdate:@"create table test (a text, b integer)"];

           [db beginTransaction];
           int i = 0;
           while (i++ < 20) {
             [db executeUpdate:@"insert into test (a, b) values (?, ?)" ,
                @"hi'", // look! I put in a ', and I'm not escaping it!




Tuesday, September 28, 2010
FMDB Usage
           FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];
           if (![db open])
              NSLog(@"Could not open db.");

           [db executeUpdate:@"blah blah blah"];
             
           if ([db hadError])
            NSLog(@"Err %d: %@", [db lastErrorCode],
                [db lastErrorMessage]);

           [db executeUpdate:@"create table test (a text, b integer)"];

           [db beginTransaction];
           int i = 0;
           while (i++ < 20) {
             [db executeUpdate:@"insert into test (a, b) values (?, ?)" ,
                @"hi'", // look! I put in a ', and I'm not escaping it!
                [NSNumber numberWithInt:i]];


Tuesday, September 28, 2010
FMDB Usage
           FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];
           if (![db open])
              NSLog(@"Could not open db.");

           [db executeUpdate:@"blah blah blah"];
             
           if ([db hadError])
            NSLog(@"Err %d: %@", [db lastErrorCode],
                [db lastErrorMessage]);

           [db executeUpdate:@"create table test (a text, b integer)"];

           [db beginTransaction];
           int i = 0;
           while (i++ < 20) {
             [db executeUpdate:@"insert into test (a, b) values (?, ?)" ,
                @"hi'", // look! I put in a ', and I'm not escaping it!
                [NSNumber numberWithInt:i]];
           }

Tuesday, September 28, 2010
FMDB Usage
           FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];
           if (![db open])
              NSLog(@"Could not open db.");

           [db executeUpdate:@"blah blah blah"];
             
           if ([db hadError])
            NSLog(@"Err %d: %@", [db lastErrorCode],
                [db lastErrorMessage]);

           [db executeUpdate:@"create table test (a text, b integer)"];

           [db beginTransaction];
           int i = 0;
           while (i++ < 20) {
             [db executeUpdate:@"insert into test (a, b) values (?, ?)" ,
                @"hi'", // look! I put in a ', and I'm not escaping it!
                [NSNumber numberWithInt:i]];
           }
           [db commit];
Tuesday, September 28, 2010
What about updates?


                 Database is never copied over again

                 If we did, your customers would lose
                 data




Tuesday, September 28, 2010
Migrations

                 Concept from Ruby on Rails

                 Evolutionary database design

                 Each database has a "version"

                 App runs all migrations to the latest
                 version




Tuesday, September 28, 2010
Migrations

                              number        name
                                1      initial_schema
                                2        update_foo
                                3      implement_blah




Tuesday, September 28, 2010
Migrations

                              number        name
                                1      initial_schema
                                2        update_foo
                                3      implement_blah




Tuesday, September 28, 2010
Hand-rolled Database
                 Migrator


                 DEMO




Tuesday, September 28, 2010
FMDB Migration
                                  Manager


                 http://github.com/mocra/fmdb-
                 migration-manager




Tuesday, September 28, 2010
FMDB Migration
                                  Manager

 NSArray *migrations = [NSArray arrayWithObjects:
      [CreateStudents migration], // 1
      [CreateStaffMembers migration], // 2
      [AddStudentNumberToStudents migration], // 3
      nil
   ];
 [FmdbMigrationManager executeForDatabasePath:@"/tmp/tmp.db"
 withMigrations:migrations];




Tuesday, September 28, 2010
FMDB Migration
                                  Manager
 @interface CreateStudents : FmdbMigration
 {
 }
 @end

 @implementation CreateStudents
 - (void)up {
   [self createTable:@"students" withColumns:[NSArray arrayWithObjects:
       [FmdbMigrationColumn columnWithColumnName:@"first_name" columnType:@"string"],
       [FmdbMigrationColumn columnWithColumnName:@"age" columnType:@"integer"
              defaultValue:21], nil];
 }

 - (void)down {
   [self dropTable:@"students"];
 }

 @end




Tuesday, September 28, 2010
ActiveRecord

             Person *p = [[Person alloc] init];
             p.name = @"Joe";
             p.occupation = @"Dishwasher";

             [p save];




             Person *p = [Person personWithId:5];
             ==> Person {id:5, name:Joe, occupation:Dishwasher}




Tuesday, September 28, 2010
Aptiva's ActiveRecord


                  http://github.com/aptiva/activerecord




                                 (YMMV)




Tuesday, September 28, 2010
Questions?




Tuesday, September 28, 2010

More Related Content

KEY
SQLite Techniques
KEY
SQLite Techniques
KEY
PPT
NIO.2, the I/O API for the future
PDF
extending-php
PDF
Mengembalikan data yang terhapus atau rusak pada hardisk menggunakan ubuntu
PDF
Having Fun Programming!
PDF
The Browser Environment - A Systems Programmer's Perspective
SQLite Techniques
SQLite Techniques
NIO.2, the I/O API for the future
extending-php
Mengembalikan data yang terhapus atau rusak pada hardisk menggunakan ubuntu
Having Fun Programming!
The Browser Environment - A Systems Programmer's Perspective

What's hot (20)

PDF
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
TXT
Yy
TXT
Nouveau document texte
PPTX
Looping the Loop with SPL Iterators
TXT
C99.php
PDF
Go for the paranoid network programmer, 3rd edition
ZIP
What's new in the Drupal 7 API?
PDF
Be RESTful (Symfony Camp 2008)
PPT
spug_2008-08
PDF
Filesystem Abstraction with Flysystem
PPTX
Ch3(working with file)
TXT
PDF
Symfony2 - WebExpo 2010
PDF
Scaling / optimizing search on netlog
ODP
Letting In the Light: Using Solr as an External Search Component
PPTX
Speed up your developments with Symfony2
KEY
JavaScript Classes and Inheritance
PPTX
Psycopg2 - Connect to PostgreSQL using Python Script
PDF
Dependency Injection IPC 201
TXT
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
Yy
Nouveau document texte
Looping the Loop with SPL Iterators
C99.php
Go for the paranoid network programmer, 3rd edition
What's new in the Drupal 7 API?
Be RESTful (Symfony Camp 2008)
spug_2008-08
Filesystem Abstraction with Flysystem
Ch3(working with file)
Symfony2 - WebExpo 2010
Scaling / optimizing search on netlog
Letting In the Light: Using Solr as an External Search Component
Speed up your developments with Symfony2
JavaScript Classes and Inheritance
Psycopg2 - Connect to PostgreSQL using Python Script
Dependency Injection IPC 201
Ad

Similar to SQLite Techniques (20)

PDF
iPhone for .NET Developers
PDF
MDSD for iPhone and Android
PDF
09 Data
PDF
Mongo db
KEY
занятие8
PDF
Lecture 2#- (Intro to Obj-C, Interface Builder and Xcode)
PDF
Techfest 2013 No RESTKit for the Weary
PDF
EC3 Workshop - Evernote API with Mobile SDKs
PDF
Metaprogramming
PDF
Data Loading for Ext GWT
PDF
XQuery Design Patterns
PDF
IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP
PDF
Continuous Integration Testing for Plone Using Hudson
PDF
The jQuery Divide
PDF
Large problems, Mostly Solved
PDF
Fabric-让部署变得简单
PDF
Acceptance & Integration Testing With Behat (PBC11)
PDF
Desenvolvendo Aplicativos Sociais com Rails 3
PDF
Developing in HTML5: Widgetbox & Sencha Touch
PDF
Pyconie 2012
iPhone for .NET Developers
MDSD for iPhone and Android
09 Data
Mongo db
занятие8
Lecture 2#- (Intro to Obj-C, Interface Builder and Xcode)
Techfest 2013 No RESTKit for the Weary
EC3 Workshop - Evernote API with Mobile SDKs
Metaprogramming
Data Loading for Ext GWT
XQuery Design Patterns
IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP
Continuous Integration Testing for Plone Using Hudson
The jQuery Divide
Large problems, Mostly Solved
Fabric-让部署变得简单
Acceptance & Integration Testing With Behat (PBC11)
Desenvolvendo Aplicativos Sociais com Rails 3
Developing in HTML5: Widgetbox & Sencha Touch
Pyconie 2012
Ad

More from joaopmaia (6)

PPTX
AFNetworking
PDF
Core Data presentation
PPT
Meetup uikit programming
PPT
Web App Testing With Selenium
PDF
Eventum Presentation
PDF
Form Validation NG
AFNetworking
Core Data presentation
Meetup uikit programming
Web App Testing With Selenium
Eventum Presentation
Form Validation NG

Recently uploaded (20)

PDF
Machine learning based COVID-19 study performance prediction
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PPTX
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
PPTX
MYSQL Presentation for SQL database connectivity
PPTX
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
DOCX
The AUB Centre for AI in Media Proposal.docx
PDF
KodekX | Application Modernization Development
PPT
Teaching material agriculture food technology
PDF
Electronic commerce courselecture one. Pdf
PDF
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
PDF
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
PPTX
Spectroscopy.pptx food analysis technology
PDF
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
PDF
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
PPTX
Programs and apps: productivity, graphics, security and other tools
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PDF
MIND Revenue Release Quarter 2 2025 Press Release
PPTX
Cloud computing and distributed systems.
Machine learning based COVID-19 study performance prediction
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
MYSQL Presentation for SQL database connectivity
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
Advanced methodologies resolving dimensionality complications for autism neur...
The AUB Centre for AI in Media Proposal.docx
KodekX | Application Modernization Development
Teaching material agriculture food technology
Electronic commerce courselecture one. Pdf
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
Spectroscopy.pptx food analysis technology
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
Programs and apps: productivity, graphics, security and other tools
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
MIND Revenue Release Quarter 2 2025 Press Release
Cloud computing and distributed systems.

SQLite Techniques

  • 1. SQLite Techniques Ben Scheirman @subdigital Code / Slides: github.com/subdigital/iphonedevcon- sandiego Tuesday, September 28, 2010
  • 2. SQLite is.... Single-user File-based Simple Cross Platform A subset of full ANSI SQL Tuesday, September 28, 2010
  • 3. SQLite API Pure C API Lots of strange-looking, hard to debug code Best choice is to abstract it away Tuesday, September 28, 2010
  • 4. SQLite Tools SQLite Manager Add-in for Firefox sqlite3 command line utility Tuesday, September 28, 2010
  • 5. Writable Databases Your app bundle is signed! (That means the contents can't change) Tuesday, September 28, 2010
  • 6. Your App Sandbox Your App Bundle Resources Documents Tuesday, September 28, 2010
  • 7. Your App Sandbox Your App Bundle Resources Documents Tuesday, September 28, 2010
  • 8. Creating the database Tuesday, September 28, 2010
  • 9. Getting Resource Paths Tuesday, September 28, 2010
  • 10. Getting Resource Paths //fetches  path  for  foo.db Tuesday, September 28, 2010
  • 11. Getting Resource Paths //fetches  path  for  foo.db NSString  *resourcePath  =  [[NSBundle  mainBundle] Tuesday, September 28, 2010
  • 12. Getting Resource Paths //fetches  path  for  foo.db NSString  *resourcePath  =  [[NSBundle  mainBundle]                                                          pathForResource:@"foo" Tuesday, September 28, 2010
  • 13. Getting Resource Paths //fetches  path  for  foo.db NSString  *resourcePath  =  [[NSBundle  mainBundle]                                                          pathForResource:@"foo"                                                          ofType:@"db"]; Tuesday, September 28, 2010
  • 14. Finding the Documents Directory Tuesday, September 28, 2010
  • 15. Finding the Documents Directory NSArray  *paths  =  NSSearchPathForDirectoriesInDomains(   Tuesday, September 28, 2010
  • 16. Finding the Documents Directory NSArray  *paths  =  NSSearchPathForDirectoriesInDomains(                                                        NSDocumentDirectory,   Tuesday, September 28, 2010
  • 17. Finding the Documents Directory NSArray  *paths  =  NSSearchPathForDirectoriesInDomains(                                                        NSDocumentDirectory,                                                        NSUserDomainMask,   Tuesday, September 28, 2010
  • 18. Finding the Documents Directory NSArray  *paths  =  NSSearchPathForDirectoriesInDomains(                                                        NSDocumentDirectory,                                                        NSUserDomainMask,                                                        YES); Tuesday, September 28, 2010
  • 19. Finding the Documents Directory NSArray  *paths  =  NSSearchPathForDirectoriesInDomains(                                                        NSDocumentDirectory,                                                        NSUserDomainMask,                                                        YES); NSString  *documentsDirectory  =  [paths  objectAtIndex:0]; Tuesday, September 28, 2010
  • 20. Copy a default database on startup Tuesday, September 28, 2010
  • 21. Copy a default database on startup //in applicationDidFinishLaunching NSString *sourcePath = [[NSBundle mainBundle] pathForResource:@"app" ofType:@"db"]; NSString *targetPath = ... NSFileManager *fm = [NSFileManager defaultManager]; if(![fm fileExistsAtPath:targetPath]) { [fm copyItemAtPath:sourcePath toPath:targetPath error:&error]; } Tuesday, September 28, 2010
  • 22. Copy a default database on startup //in applicationDidFinishLaunching NSString *sourcePath = [[NSBundle mainBundle] pathForResource:@"app" ofType:@"db"]; NSString *targetPath = ... NSFileManager *fm = [NSFileManager defaultManager]; if(![fm fileExistsAtPath:targetPath]) { [fm copyItemAtPath:sourcePath toPath:targetPath error:&error]; } Tuesday, September 28, 2010
  • 23. Copy a default database on startup //in applicationDidFinishLaunching NSString *sourcePath = [[NSBundle mainBundle] pathForResource:@"app" ofType:@"db"]; NSString *targetPath = ... NSFileManager *fm = [NSFileManager defaultManager]; if(![fm fileExistsAtPath:targetPath]) { [fm copyItemAtPath:sourcePath toPath:targetPath error:&error]; } Tuesday, September 28, 2010
  • 24. Copy a default database on startup //in applicationDidFinishLaunching NSString *sourcePath = [[NSBundle mainBundle] pathForResource:@"app" ofType:@"db"]; NSString *targetPath = ... NSFileManager *fm = [NSFileManager defaultManager]; if(![fm fileExistsAtPath:targetPath]) { [fm copyItemAtPath:sourcePath toPath:targetPath error:&error]; } Tuesday, September 28, 2010
  • 25. Copy a default database on startup //in applicationDidFinishLaunching NSString *sourcePath = [[NSBundle mainBundle] pathForResource:@"app" ofType:@"db"]; NSString *targetPath = ... NSFileManager *fm = [NSFileManager defaultManager]; if(![fm fileExistsAtPath:targetPath]) { [fm copyItemAtPath:sourcePath toPath:targetPath error:&error]; } Tuesday, September 28, 2010
  • 26. Copy a default database on startup //in applicationDidFinishLaunching NSString *sourcePath = [[NSBundle mainBundle] pathForResource:@"app" ofType:@"db"]; NSString *targetPath = ... NSFileManager *fm = [NSFileManager defaultManager]; if(![fm fileExistsAtPath:targetPath]) { [fm copyItemAtPath:sourcePath toPath:targetPath error:&error]; } Tuesday, September 28, 2010
  • 27. Copy a default database on startup //in applicationDidFinishLaunching NSString *sourcePath = [[NSBundle mainBundle] pathForResource:@"app" ofType:@"db"]; NSString *targetPath = ... NSFileManager *fm = [NSFileManager defaultManager]; if(![fm fileExistsAtPath:targetPath]) { [fm copyItemAtPath:sourcePath toPath:targetPath error:&error]; } Tuesday, September 28, 2010
  • 28. SQLite API Basics Tuesday, September 28, 2010
  • 29. Add the Framework Tuesday, September 28, 2010
  • 30. Add the Framework Tuesday, September 28, 2010
  • 31. Add the Framework Tuesday, September 28, 2010
  • 32. Add the Framework Tuesday, September 28, 2010
  • 33. SQLite API - Opening a connection Tuesday, September 28, 2010
  • 34. SQLite API - Opening a connection #import "sqlite3.h" Tuesday, September 28, 2010
  • 35. SQLite API - Opening a connection #import "sqlite3.h" sqlite3 *db; Tuesday, September 28, 2010
  • 36. SQLite API - Opening a connection #import "sqlite3.h" sqlite3 *db; int result = sqlite3_open(PATH, &db); Tuesday, September 28, 2010
  • 37. SQLite API - Opening a connection #import "sqlite3.h" sqlite3 *db; int result = sqlite3_open(PATH, &db); if (result != SQLITE_OK) { Tuesday, September 28, 2010
  • 38. SQLite API - Opening a connection #import "sqlite3.h" sqlite3 *db; int result = sqlite3_open(PATH, &db); if (result != SQLITE_OK) { [NSException raise:@"SQLITE ERROR" Tuesday, September 28, 2010
  • 39. SQLite API - Opening a connection #import "sqlite3.h" sqlite3 *db; int result = sqlite3_open(PATH, &db); if (result != SQLITE_OK) { [NSException raise:@"SQLITE ERROR" format:@"Error %d", result]; Tuesday, September 28, 2010
  • 40. SQLite API - Opening a connection #import "sqlite3.h" sqlite3 *db; int result = sqlite3_open(PATH, &db); if (result != SQLITE_OK) { [NSException raise:@"SQLITE ERROR" format:@"Error %d", result]; } Tuesday, September 28, 2010
  • 41. SQLite API - Opening a connection #import "sqlite3.h" sqlite3 *db; int result = sqlite3_open(PATH, &db); if (result != SQLITE_OK) { [NSException raise:@"SQLITE ERROR" format:@"Error %d", result]; } //later Tuesday, September 28, 2010
  • 42. SQLite API - Opening a connection #import "sqlite3.h" sqlite3 *db; int result = sqlite3_open(PATH, &db); if (result != SQLITE_OK) { [NSException raise:@"SQLITE ERROR" format:@"Error %d", result]; } //later sqlite3_close(db); Tuesday, September 28, 2010
  • 43. SQLite API - executing queries Tuesday, September 28, 2010
  • 44. SQLite API - executing queries int sqlite3_exec( Tuesday, September 28, 2010
  • 45. SQLite API - executing queries int sqlite3_exec( sqlite3 *db, Tuesday, September 28, 2010
  • 46. SQLite API - executing queries int sqlite3_exec( sqlite3 *db, char *sql, Tuesday, September 28, 2010
  • 47. SQLite API - executing queries int sqlite3_exec( sqlite3 *db, char *sql, int (*callback)(void *, int, char**, char**) callbackFunc, Tuesday, September 28, 2010
  • 48. SQLite API - executing queries int sqlite3_exec( sqlite3 *db, char *sql, int (*callback)(void *, int, char**, char**) callbackFunc, void *context, Tuesday, September 28, 2010
  • 49. SQLite API - executing queries int sqlite3_exec( sqlite3 *db, char *sql, int (*callback)(void *, int, char**, char**) callbackFunc, void *context, char **errorMessage Tuesday, September 28, 2010
  • 50. SQLite API - executing queries int sqlite3_exec( sqlite3 *db, char *sql, int (*callback)(void *, int, char**, char**) callbackFunc, void *context, char **errorMessage ); Tuesday, September 28, 2010
  • 51. SQLite API - executing queries int sqlite3_exec( sqlite3 *db, char *sql, int (*callback)(void *, int, char**, char**) callbackFunc, void *context, char **errorMessage ); //callback signature Tuesday, September 28, 2010
  • 52. SQLite API - executing queries int sqlite3_exec( sqlite3 *db, char *sql, int (*callback)(void *, int, char**, char**) callbackFunc, void *context, char **errorMessage ); //callback signature int RowCallback(void * context, Tuesday, September 28, 2010
  • 53. SQLite API - executing queries int sqlite3_exec( sqlite3 *db, char *sql, int (*callback)(void *, int, char**, char**) callbackFunc, void *context, char **errorMessage ); //callback signature int RowCallback(void * context, int numColumns, Tuesday, September 28, 2010
  • 54. SQLite API - executing queries int sqlite3_exec( sqlite3 *db, char *sql, int (*callback)(void *, int, char**, char**) callbackFunc, void *context, char **errorMessage ); //callback signature int RowCallback(void * context, int numColumns, char** colValues, Tuesday, September 28, 2010
  • 55. SQLite API - executing queries int sqlite3_exec( sqlite3 *db, char *sql, int (*callback)(void *, int, char**, char**) callbackFunc, void *context, char **errorMessage ); //callback signature int RowCallback(void * context, int numColumns, char** colValues, char ** colNames); Tuesday, September 28, 2010
  • 56. SQLite API - Prepared Statements More Powerful Unfortunately much more code! Tuesday, September 28, 2010
  • 58. SQLite API-Prepared Statements sqlite3 *db; Tuesday, September 28, 2010
  • 59. SQLite API-Prepared Statements sqlite3 *db; int result = sqlite3_open(DB_PATH, &db); Tuesday, September 28, 2010
  • 60. SQLite API-Prepared Statements sqlite3 *db; int result = sqlite3_open(DB_PATH, &db); if(result != SQLITE_OK) { Tuesday, September 28, 2010
  • 61. SQLite API-Prepared Statements sqlite3 *db; int result = sqlite3_open(DB_PATH, &db); if(result != SQLITE_OK) { //handle error Tuesday, September 28, 2010
  • 62. SQLite API-Prepared Statements sqlite3 *db; int result = sqlite3_open(DB_PATH, &db); if(result != SQLITE_OK) { //handle error } Tuesday, September 28, 2010
  • 63. SQLite API-Prepared Statements sqlite3 *db; int result = sqlite3_open(DB_PATH, &db); if(result != SQLITE_OK) { //handle error } Tuesday, September 28, 2010
  • 64. SQLite API-Prepared Statements sqlite3 *db; int result = sqlite3_open(DB_PATH, &db); if(result != SQLITE_OK) { //handle error } sqlite3_stmt *stmt; Tuesday, September 28, 2010
  • 65. SQLite API-Prepared Statements sqlite3 *db; int result = sqlite3_open(DB_PATH, &db); if(result != SQLITE_OK) { //handle error } sqlite3_stmt *stmt; result = sqlite3_prepare_v2(db, sql_cstring, -1, &stmt, NULL); Tuesday, September 28, 2010
  • 66. SQLite API-Prepared Statements sqlite3 *db; int result = sqlite3_open(DB_PATH, &db); if(result != SQLITE_OK) { //handle error } sqlite3_stmt *stmt; result = sqlite3_prepare_v2(db, sql_cstring, -1, &stmt, NULL); if(result != SQLITE_OK) { Tuesday, September 28, 2010
  • 67. SQLite API-Prepared Statements sqlite3 *db; int result = sqlite3_open(DB_PATH, &db); if(result != SQLITE_OK) { //handle error } sqlite3_stmt *stmt; result = sqlite3_prepare_v2(db, sql_cstring, -1, &stmt, NULL); if(result != SQLITE_OK) { //handle error Tuesday, September 28, 2010
  • 68. SQLite API-Prepared Statements sqlite3 *db; int result = sqlite3_open(DB_PATH, &db); if(result != SQLITE_OK) { //handle error } sqlite3_stmt *stmt; result = sqlite3_prepare_v2(db, sql_cstring, -1, &stmt, NULL); if(result != SQLITE_OK) { //handle error } Tuesday, September 28, 2010
  • 69. SQLite API-Prepared Statements sqlite3 *db; int result = sqlite3_open(DB_PATH, &db); if(result != SQLITE_OK) { //handle error } sqlite3_stmt *stmt; result = sqlite3_prepare_v2(db, sql_cstring, -1, &stmt, NULL); if(result != SQLITE_OK) { //handle error } //... Tuesday, September 28, 2010
  • 70. SQLite API-Prepared Statements sqlite3 *db; int result = sqlite3_open(DB_PATH, &db); if(result != SQLITE_OK) { //handle error } sqlite3_stmt *stmt; result = sqlite3_prepare_v2(db, sql_cstring, -1, &stmt, NULL); if(result != SQLITE_OK) { //handle error } //... Tuesday, September 28, 2010
  • 71. SQLite API-Prepared Statements sqlite3 *db; int result = sqlite3_open(DB_PATH, &db); if(result != SQLITE_OK) { //handle error } sqlite3_stmt *stmt; result = sqlite3_prepare_v2(db, sql_cstring, -1, &stmt, NULL); if(result != SQLITE_OK) { //handle error } //... Tuesday, September 28, 2010
  • 72. SQLite API-Prepared Statements sqlite3 *db; int result = sqlite3_open(DB_PATH, &db); if(result != SQLITE_OK) { //handle error } sqlite3_stmt *stmt; result = sqlite3_prepare_v2(db, sql_cstring, -1, &stmt, NULL); if(result != SQLITE_OK) { //handle error } //... Tuesday, September 28, 2010
  • 74. SQLite API-Prepared Statements //INSERT INTO CARS(year, make) VALUES(?, ?) Tuesday, September 28, 2010
  • 75. SQLite API-Prepared Statements //INSERT INTO CARS(year, make) VALUES(?, ?) //PARAMETERS HAVE A 1-BASED INDEX! Tuesday, September 28, 2010
  • 76. SQLite API-Prepared Statements //INSERT INTO CARS(year, make) VALUES(?, ?) //PARAMETERS HAVE A 1-BASED INDEX! sqlite3_bind_int(stmt, 1 /* idx */, 5); Tuesday, September 28, 2010
  • 77. SQLite API-Prepared Statements //INSERT INTO CARS(year, make) VALUES(?, ?) //PARAMETERS HAVE A 1-BASED INDEX! sqlite3_bind_int(stmt, 1 /* idx */, 5); sqlite3_bind_text(stmt, 2 /* idx */,"value", -1, SQLITE_TRANSIENT); Tuesday, September 28, 2010
  • 78. SQLite API-Prepared Statements //INSERT INTO CARS(year, make) VALUES(?, ?) //PARAMETERS HAVE A 1-BASED INDEX! sqlite3_bind_int(stmt, 1 /* idx */, 5); sqlite3_bind_text(stmt, 2 /* idx */,"value", -1, SQLITE_TRANSIENT); Tuesday, September 28, 2010
  • 79. SQLite API-Prepared Statements //INSERT INTO CARS(year, make) VALUES(?, ?) //PARAMETERS HAVE A 1-BASED INDEX! sqlite3_bind_int(stmt, 1 /* idx */, 5); sqlite3_bind_text(stmt, 2 /* idx */,"value", -1, SQLITE_TRANSIENT); result = sqlite3_step(stmt); Tuesday, September 28, 2010
  • 80. SQLite API-Prepared Statements //INSERT INTO CARS(year, make) VALUES(?, ?) //PARAMETERS HAVE A 1-BASED INDEX! sqlite3_bind_int(stmt, 1 /* idx */, 5); sqlite3_bind_text(stmt, 2 /* idx */,"value", -1, SQLITE_TRANSIENT); result = sqlite3_step(stmt); if(result == SQLITE_DONE) Tuesday, September 28, 2010
  • 81. SQLite API-Prepared Statements //INSERT INTO CARS(year, make) VALUES(?, ?) //PARAMETERS HAVE A 1-BASED INDEX! sqlite3_bind_int(stmt, 1 /* idx */, 5); sqlite3_bind_text(stmt, 2 /* idx */,"value", -1, SQLITE_TRANSIENT); result = sqlite3_step(stmt); if(result == SQLITE_DONE) return [NSArray array]; //nothing to do! Tuesday, September 28, 2010
  • 82. SQLite API-Prepared Statements //INSERT INTO CARS(year, make) VALUES(?, ?) //PARAMETERS HAVE A 1-BASED INDEX! sqlite3_bind_int(stmt, 1 /* idx */, 5); sqlite3_bind_text(stmt, 2 /* idx */,"value", -1, SQLITE_TRANSIENT); result = sqlite3_step(stmt); if(result == SQLITE_DONE) return [NSArray array]; //nothing to do! Tuesday, September 28, 2010
  • 83. SQLite API-Prepared Statements //INSERT INTO CARS(year, make) VALUES(?, ?) //PARAMETERS HAVE A 1-BASED INDEX! sqlite3_bind_int(stmt, 1 /* idx */, 5); sqlite3_bind_text(stmt, 2 /* idx */,"value", -1, SQLITE_TRANSIENT); result = sqlite3_step(stmt); if(result == SQLITE_DONE) return [NSArray array]; //nothing to do! NSMutableArray *results = [NSMutableArray array]; Tuesday, September 28, 2010
  • 84. SQLite API-Prepared Statements //INSERT INTO CARS(year, make) VALUES(?, ?) //PARAMETERS HAVE A 1-BASED INDEX! sqlite3_bind_int(stmt, 1 /* idx */, 5); sqlite3_bind_text(stmt, 2 /* idx */,"value", -1, SQLITE_TRANSIENT); result = sqlite3_step(stmt); if(result == SQLITE_DONE) return [NSArray array]; //nothing to do! NSMutableArray *results = [NSMutableArray array]; while(result == SQLITE_ROW) { Tuesday, September 28, 2010
  • 85. SQLite API-Prepared Statements //INSERT INTO CARS(year, make) VALUES(?, ?) //PARAMETERS HAVE A 1-BASED INDEX! sqlite3_bind_int(stmt, 1 /* idx */, 5); sqlite3_bind_text(stmt, 2 /* idx */,"value", -1, SQLITE_TRANSIENT); result = sqlite3_step(stmt); if(result == SQLITE_DONE) return [NSArray array]; //nothing to do! NSMutableArray *results = [NSMutableArray array]; while(result == SQLITE_ROW) { NSMutableDictionary *row = [NSMutableDictionary dictionary]; Tuesday, September 28, 2010
  • 86. SQLite API-Prepared Statements //INSERT INTO CARS(year, make) VALUES(?, ?) //PARAMETERS HAVE A 1-BASED INDEX! sqlite3_bind_int(stmt, 1 /* idx */, 5); sqlite3_bind_text(stmt, 2 /* idx */,"value", -1, SQLITE_TRANSIENT); result = sqlite3_step(stmt); if(result == SQLITE_DONE) return [NSArray array]; //nothing to do! NSMutableArray *results = [NSMutableArray array]; while(result == SQLITE_ROW) { NSMutableDictionary *row = [NSMutableDictionary dictionary]; Tuesday, September 28, 2010
  • 87. SQLite API-Prepared Statements //INSERT INTO CARS(year, make) VALUES(?, ?) //PARAMETERS HAVE A 1-BASED INDEX! sqlite3_bind_int(stmt, 1 /* idx */, 5); sqlite3_bind_text(stmt, 2 /* idx */,"value", -1, SQLITE_TRANSIENT); result = sqlite3_step(stmt); if(result == SQLITE_DONE) return [NSArray array]; //nothing to do! NSMutableArray *results = [NSMutableArray array]; while(result == SQLITE_ROW) { NSMutableDictionary *row = [NSMutableDictionary dictionary]; [self processRow:row forStatement:stmt]; Tuesday, September 28, 2010
  • 88. SQLite API-Prepared Statements //INSERT INTO CARS(year, make) VALUES(?, ?) //PARAMETERS HAVE A 1-BASED INDEX! sqlite3_bind_int(stmt, 1 /* idx */, 5); sqlite3_bind_text(stmt, 2 /* idx */,"value", -1, SQLITE_TRANSIENT); result = sqlite3_step(stmt); if(result == SQLITE_DONE) return [NSArray array]; //nothing to do! NSMutableArray *results = [NSMutableArray array]; while(result == SQLITE_ROW) { NSMutableDictionary *row = [NSMutableDictionary dictionary]; [self processRow:row forStatement:stmt]; [results addObject:row]; Tuesday, September 28, 2010
  • 89. SQLite API-Prepared Statements //INSERT INTO CARS(year, make) VALUES(?, ?) //PARAMETERS HAVE A 1-BASED INDEX! sqlite3_bind_int(stmt, 1 /* idx */, 5); sqlite3_bind_text(stmt, 2 /* idx */,"value", -1, SQLITE_TRANSIENT); result = sqlite3_step(stmt); if(result == SQLITE_DONE) return [NSArray array]; //nothing to do! NSMutableArray *results = [NSMutableArray array]; while(result == SQLITE_ROW) { NSMutableDictionary *row = [NSMutableDictionary dictionary]; [self processRow:row forStatement:stmt]; [results addObject:row]; result = sqlite3_step(stmt); Tuesday, September 28, 2010
  • 90. SQLite API-Prepared Statements //INSERT INTO CARS(year, make) VALUES(?, ?) //PARAMETERS HAVE A 1-BASED INDEX! sqlite3_bind_int(stmt, 1 /* idx */, 5); sqlite3_bind_text(stmt, 2 /* idx */,"value", -1, SQLITE_TRANSIENT); result = sqlite3_step(stmt); if(result == SQLITE_DONE) return [NSArray array]; //nothing to do! NSMutableArray *results = [NSMutableArray array]; while(result == SQLITE_ROW) { NSMutableDictionary *row = [NSMutableDictionary dictionary]; [self processRow:row forStatement:stmt]; [results addObject:row]; result = sqlite3_step(stmt); } Tuesday, September 28, 2010
  • 91. SQLite API-Prepared Statements //INSERT INTO CARS(year, make) VALUES(?, ?) //PARAMETERS HAVE A 1-BASED INDEX! sqlite3_bind_int(stmt, 1 /* idx */, 5); sqlite3_bind_text(stmt, 2 /* idx */,"value", -1, SQLITE_TRANSIENT); result = sqlite3_step(stmt); if(result == SQLITE_DONE) return [NSArray array]; //nothing to do! NSMutableArray *results = [NSMutableArray array]; while(result == SQLITE_ROW) { NSMutableDictionary *row = [NSMutableDictionary dictionary]; [self processRow:row forStatement:stmt]; [results addObject:row]; result = sqlite3_step(stmt); } sqlite_finalize(stmt); Tuesday, September 28, 2010
  • 92. SQLite API-Prepared Statements //INSERT INTO CARS(year, make) VALUES(?, ?) //PARAMETERS HAVE A 1-BASED INDEX! sqlite3_bind_int(stmt, 1 /* idx */, 5); sqlite3_bind_text(stmt, 2 /* idx */,"value", -1, SQLITE_TRANSIENT); result = sqlite3_step(stmt); if(result == SQLITE_DONE) return [NSArray array]; //nothing to do! NSMutableArray *results = [NSMutableArray array]; while(result == SQLITE_ROW) { NSMutableDictionary *row = [NSMutableDictionary dictionary]; [self processRow:row forStatement:stmt]; [results addObject:row]; result = sqlite3_step(stmt); } sqlite_finalize(stmt); Tuesday, September 28, 2010
  • 93. SQLite API-Prepared Statements //INSERT INTO CARS(year, make) VALUES(?, ?) //PARAMETERS HAVE A 1-BASED INDEX! sqlite3_bind_int(stmt, 1 /* idx */, 5); sqlite3_bind_text(stmt, 2 /* idx */,"value", -1, SQLITE_TRANSIENT); result = sqlite3_step(stmt); if(result == SQLITE_DONE) return [NSArray array]; //nothing to do! NSMutableArray *results = [NSMutableArray array]; while(result == SQLITE_ROW) { NSMutableDictionary *row = [NSMutableDictionary dictionary]; [self processRow:row forStatement:stmt]; [results addObject:row]; result = sqlite3_step(stmt); } sqlite_finalize(stmt); return results; Tuesday, September 28, 2010
  • 95. SQLite API-Prepared Statements -(void)processRow:(NSMutableDictionary *)row forStatement: (sqlite3_stmt*)stmt { Tuesday, September 28, 2010
  • 96. SQLite API-Prepared Statements -(void)processRow:(NSMutableDictionary *)row forStatement: (sqlite3_stmt*)stmt { int columnCount = sqlite3_column_count(stmt); Tuesday, September 28, 2010
  • 97. SQLite API-Prepared Statements -(void)processRow:(NSMutableDictionary *)row forStatement: (sqlite3_stmt*)stmt { int columnCount = sqlite3_column_count(stmt); for(int i=0; i<columnCount; i++) { Tuesday, September 28, 2010
  • 98. SQLite API-Prepared Statements -(void)processRow:(NSMutableDictionary *)row forStatement: (sqlite3_stmt*)stmt { int columnCount = sqlite3_column_count(stmt); for(int i=0; i<columnCount; i++) { //0-based index! Tuesday, September 28, 2010
  • 99. SQLite API-Prepared Statements -(void)processRow:(NSMutableDictionary *)row forStatement: (sqlite3_stmt*)stmt { int columnCount = sqlite3_column_count(stmt); for(int i=0; i<columnCount; i++) { //0-based index! const char * colName = sqlite3_column_name(stmt, i); Tuesday, September 28, 2010
  • 100. SQLite API-Prepared Statements -(void)processRow:(NSMutableDictionary *)row forStatement: (sqlite3_stmt*)stmt { int columnCount = sqlite3_column_count(stmt); for(int i=0; i<columnCount; i++) { //0-based index! const char * colName = sqlite3_column_name(stmt, i); int type = sqlite3_column_type(stmt, i); Tuesday, September 28, 2010
  • 101. SQLite API-Prepared Statements -(void)processRow:(NSMutableDictionary *)row forStatement: (sqlite3_stmt*)stmt { int columnCount = sqlite3_column_count(stmt); for(int i=0; i<columnCount; i++) { //0-based index! const char * colName = sqlite3_column_name(stmt, i); int type = sqlite3_column_type(stmt, i); id value = [NSNull null]; Tuesday, September 28, 2010
  • 102. SQLite API-Prepared Statements -(void)processRow:(NSMutableDictionary *)row forStatement: (sqlite3_stmt*)stmt { int columnCount = sqlite3_column_count(stmt); for(int i=0; i<columnCount; i++) { //0-based index! const char * colName = sqlite3_column_name(stmt, i); int type = sqlite3_column_type(stmt, i); id value = [NSNull null]; if(type == SQLITE_INTEGER) { Tuesday, September 28, 2010
  • 103. SQLite API-Prepared Statements -(void)processRow:(NSMutableDictionary *)row forStatement: (sqlite3_stmt*)stmt { int columnCount = sqlite3_column_count(stmt); for(int i=0; i<columnCount; i++) { //0-based index! const char * colName = sqlite3_column_name(stmt, i); int type = sqlite3_column_type(stmt, i); id value = [NSNull null]; if(type == SQLITE_INTEGER) { value = [NSNumber numberWithInt:sqlite3_column_int(stmt, i)]; Tuesday, September 28, 2010
  • 104. SQLite API-Prepared Statements -(void)processRow:(NSMutableDictionary *)row forStatement: (sqlite3_stmt*)stmt { int columnCount = sqlite3_column_count(stmt); for(int i=0; i<columnCount; i++) { //0-based index! const char * colName = sqlite3_column_name(stmt, i); int type = sqlite3_column_type(stmt, i); id value = [NSNull null]; if(type == SQLITE_INTEGER) { value = [NSNumber numberWithInt:sqlite3_column_int(stmt, i)]; } else if (type == SQLITE_TEXT) { Tuesday, September 28, 2010
  • 105. SQLite API-Prepared Statements -(void)processRow:(NSMutableDictionary *)row forStatement: (sqlite3_stmt*)stmt { int columnCount = sqlite3_column_count(stmt); for(int i=0; i<columnCount; i++) { //0-based index! const char * colName = sqlite3_column_name(stmt, i); int type = sqlite3_column_type(stmt, i); id value = [NSNull null]; if(type == SQLITE_INTEGER) { value = [NSNumber numberWithInt:sqlite3_column_int(stmt, i)]; } else if (type == SQLITE_TEXT) { const unsigned char * text = sqlite3_column_text(stmt, i); Tuesday, September 28, 2010
  • 106. SQLite API-Prepared Statements -(void)processRow:(NSMutableDictionary *)row forStatement: (sqlite3_stmt*)stmt { int columnCount = sqlite3_column_count(stmt); for(int i=0; i<columnCount; i++) { //0-based index! const char * colName = sqlite3_column_name(stmt, i); int type = sqlite3_column_type(stmt, i); id value = [NSNull null]; if(type == SQLITE_INTEGER) { value = [NSNumber numberWithInt:sqlite3_column_int(stmt, i)]; } else if (type == SQLITE_TEXT) { const unsigned char * text = sqlite3_column_text(stmt, i); value = [NSString stringWithFormat:@"%s", text]; Tuesday, September 28, 2010
  • 107. SQLite API-Prepared Statements -(void)processRow:(NSMutableDictionary *)row forStatement: (sqlite3_stmt*)stmt { int columnCount = sqlite3_column_count(stmt); for(int i=0; i<columnCount; i++) { //0-based index! const char * colName = sqlite3_column_name(stmt, i); int type = sqlite3_column_type(stmt, i); id value = [NSNull null]; if(type == SQLITE_INTEGER) { value = [NSNumber numberWithInt:sqlite3_column_int(stmt, i)]; } else if (type == SQLITE_TEXT) { const unsigned char * text = sqlite3_column_text(stmt, i); value = [NSString stringWithFormat:@"%s", text]; } else { Tuesday, September 28, 2010
  • 108. SQLite API-Prepared Statements -(void)processRow:(NSMutableDictionary *)row forStatement: (sqlite3_stmt*)stmt { int columnCount = sqlite3_column_count(stmt); for(int i=0; i<columnCount; i++) { //0-based index! const char * colName = sqlite3_column_name(stmt, i); int type = sqlite3_column_type(stmt, i); id value = [NSNull null]; if(type == SQLITE_INTEGER) { value = [NSNumber numberWithInt:sqlite3_column_int(stmt, i)]; } else if (type == SQLITE_TEXT) { const unsigned char * text = sqlite3_column_text(stmt, i); value = [NSString stringWithFormat:@"%s", text]; } else { // more type handling Tuesday, September 28, 2010
  • 109. SQLite API-Prepared Statements -(void)processRow:(NSMutableDictionary *)row forStatement: (sqlite3_stmt*)stmt { int columnCount = sqlite3_column_count(stmt); for(int i=0; i<columnCount; i++) { //0-based index! const char * colName = sqlite3_column_name(stmt, i); int type = sqlite3_column_type(stmt, i); id value = [NSNull null]; if(type == SQLITE_INTEGER) { value = [NSNumber numberWithInt:sqlite3_column_int(stmt, i)]; } else if (type == SQLITE_TEXT) { const unsigned char * text = sqlite3_column_text(stmt, i); value = [NSString stringWithFormat:@"%s", text]; } else { // more type handling } Tuesday, September 28, 2010
  • 110. SQLite API-Prepared Statements -(void)processRow:(NSMutableDictionary *)row forStatement: (sqlite3_stmt*)stmt { int columnCount = sqlite3_column_count(stmt); for(int i=0; i<columnCount; i++) { //0-based index! const char * colName = sqlite3_column_name(stmt, i); int type = sqlite3_column_type(stmt, i); id value = [NSNull null]; if(type == SQLITE_INTEGER) { value = [NSNumber numberWithInt:sqlite3_column_int(stmt, i)]; } else if (type == SQLITE_TEXT) { const unsigned char * text = sqlite3_column_text(stmt, i); value = [NSString stringWithFormat:@"%s", text]; } else { // more type handling } [row setObject:value forKey: Tuesday, September 28, 2010
  • 111. SQLite API-Prepared Statements -(void)processRow:(NSMutableDictionary *)row forStatement: (sqlite3_stmt*)stmt { int columnCount = sqlite3_column_count(stmt); for(int i=0; i<columnCount; i++) { //0-based index! const char * colName = sqlite3_column_name(stmt, i); int type = sqlite3_column_type(stmt, i); id value = [NSNull null]; if(type == SQLITE_INTEGER) { value = [NSNumber numberWithInt:sqlite3_column_int(stmt, i)]; } else if (type == SQLITE_TEXT) { const unsigned char * text = sqlite3_column_text(stmt, i); value = [NSString stringWithFormat:@"%s", text]; } else { // more type handling } [row setObject:value forKey: [NSString stringWithUTF8String:colName]]; Tuesday, September 28, 2010
  • 112. SQLite API-Prepared Statements -(void)processRow:(NSMutableDictionary *)row forStatement: (sqlite3_stmt*)stmt { int columnCount = sqlite3_column_count(stmt); for(int i=0; i<columnCount; i++) { //0-based index! const char * colName = sqlite3_column_name(stmt, i); int type = sqlite3_column_type(stmt, i); id value = [NSNull null]; if(type == SQLITE_INTEGER) { value = [NSNumber numberWithInt:sqlite3_column_int(stmt, i)]; } else if (type == SQLITE_TEXT) { const unsigned char * text = sqlite3_column_text(stmt, i); value = [NSString stringWithFormat:@"%s", text]; } else { // more type handling } [row setObject:value forKey: [NSString stringWithUTF8String:colName]]; } Tuesday, September 28, 2010
  • 113. SQLite API-Prepared Statements -(void)processRow:(NSMutableDictionary *)row forStatement: (sqlite3_stmt*)stmt { int columnCount = sqlite3_column_count(stmt); for(int i=0; i<columnCount; i++) { //0-based index! const char * colName = sqlite3_column_name(stmt, i); int type = sqlite3_column_type(stmt, i); id value = [NSNull null]; if(type == SQLITE_INTEGER) { value = [NSNumber numberWithInt:sqlite3_column_int(stmt, i)]; } else if (type == SQLITE_TEXT) { const unsigned char * text = sqlite3_column_text(stmt, i); value = [NSString stringWithFormat:@"%s", text]; } else { // more type handling } [row setObject:value forKey: [NSString stringWithUTF8String:colName]]; } } Tuesday, September 28, 2010
  • 114. FMDB http://github.com/ccgus/fmdb Tuesday, September 28, 2010
  • 116. FMDB Usage   FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"]; Tuesday, September 28, 2010
  • 117. FMDB Usage   FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];   if (![db open]) Tuesday, September 28, 2010
  • 118. FMDB Usage   FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];   if (![db open])      NSLog(@"Could not open db."); Tuesday, September 28, 2010
  • 119. FMDB Usage   FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];   if (![db open])      NSLog(@"Could not open db.");   [db executeUpdate:@"blah blah blah"]; Tuesday, September 28, 2010
  • 120. FMDB Usage   FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];   if (![db open])      NSLog(@"Could not open db.");   [db executeUpdate:@"blah blah blah"];      Tuesday, September 28, 2010
  • 121. FMDB Usage   FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];   if (![db open])      NSLog(@"Could not open db.");   [db executeUpdate:@"blah blah blah"];        if ([db hadError]) Tuesday, September 28, 2010
  • 122. FMDB Usage   FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];   if (![db open])      NSLog(@"Could not open db.");   [db executeUpdate:@"blah blah blah"];        if ([db hadError])    NSLog(@"Err %d: %@", [db lastErrorCode], Tuesday, September 28, 2010
  • 123. FMDB Usage   FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];   if (![db open])      NSLog(@"Could not open db.");   [db executeUpdate:@"blah blah blah"];        if ([db hadError])    NSLog(@"Err %d: %@", [db lastErrorCode], [db lastErrorMessage]); Tuesday, September 28, 2010
  • 124. FMDB Usage   FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];   if (![db open])      NSLog(@"Could not open db.");   [db executeUpdate:@"blah blah blah"];        if ([db hadError])    NSLog(@"Err %d: %@", [db lastErrorCode], [db lastErrorMessage]);   [db executeUpdate:@"create table test (a text, b integer)"]; Tuesday, September 28, 2010
  • 125. FMDB Usage   FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];   if (![db open])      NSLog(@"Could not open db.");   [db executeUpdate:@"blah blah blah"];        if ([db hadError])    NSLog(@"Err %d: %@", [db lastErrorCode], [db lastErrorMessage]);   [db executeUpdate:@"create table test (a text, b integer)"];   [db beginTransaction]; Tuesday, September 28, 2010
  • 126. FMDB Usage   FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];   if (![db open])      NSLog(@"Could not open db.");   [db executeUpdate:@"blah blah blah"];        if ([db hadError])    NSLog(@"Err %d: %@", [db lastErrorCode], [db lastErrorMessage]);   [db executeUpdate:@"create table test (a text, b integer)"];   [db beginTransaction];   int i = 0; Tuesday, September 28, 2010
  • 127. FMDB Usage   FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];   if (![db open])      NSLog(@"Could not open db.");   [db executeUpdate:@"blah blah blah"];        if ([db hadError])    NSLog(@"Err %d: %@", [db lastErrorCode], [db lastErrorMessage]);   [db executeUpdate:@"create table test (a text, b integer)"];   [db beginTransaction];   int i = 0;   while (i++ < 20) { Tuesday, September 28, 2010
  • 128. FMDB Usage   FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];   if (![db open])      NSLog(@"Could not open db.");   [db executeUpdate:@"blah blah blah"];        if ([db hadError])    NSLog(@"Err %d: %@", [db lastErrorCode], [db lastErrorMessage]);   [db executeUpdate:@"create table test (a text, b integer)"];   [db beginTransaction];   int i = 0;   while (i++ < 20) {   [db executeUpdate:@"insert into test (a, b) values (?, ?)" , Tuesday, September 28, 2010
  • 129. FMDB Usage   FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];   if (![db open])      NSLog(@"Could not open db.");   [db executeUpdate:@"blah blah blah"];        if ([db hadError])    NSLog(@"Err %d: %@", [db lastErrorCode], [db lastErrorMessage]);   [db executeUpdate:@"create table test (a text, b integer)"];   [db beginTransaction];   int i = 0;   while (i++ < 20) {   [db executeUpdate:@"insert into test (a, b) values (?, ?)" ,        @"hi'", // look! I put in a ', and I'm not escaping it! Tuesday, September 28, 2010
  • 130. FMDB Usage   FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];   if (![db open])      NSLog(@"Could not open db.");   [db executeUpdate:@"blah blah blah"];        if ([db hadError])    NSLog(@"Err %d: %@", [db lastErrorCode], [db lastErrorMessage]);   [db executeUpdate:@"create table test (a text, b integer)"];   [db beginTransaction];   int i = 0;   while (i++ < 20) {   [db executeUpdate:@"insert into test (a, b) values (?, ?)" ,        @"hi'", // look! I put in a ', and I'm not escaping it!        [NSNumber numberWithInt:i]]; Tuesday, September 28, 2010
  • 131. FMDB Usage   FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];   if (![db open])      NSLog(@"Could not open db.");   [db executeUpdate:@"blah blah blah"];        if ([db hadError])    NSLog(@"Err %d: %@", [db lastErrorCode], [db lastErrorMessage]);   [db executeUpdate:@"create table test (a text, b integer)"];   [db beginTransaction];   int i = 0;   while (i++ < 20) {   [db executeUpdate:@"insert into test (a, b) values (?, ?)" ,        @"hi'", // look! I put in a ', and I'm not escaping it!        [NSNumber numberWithInt:i]];   } Tuesday, September 28, 2010
  • 132. FMDB Usage   FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];   if (![db open])      NSLog(@"Could not open db.");   [db executeUpdate:@"blah blah blah"];        if ([db hadError])    NSLog(@"Err %d: %@", [db lastErrorCode], [db lastErrorMessage]);   [db executeUpdate:@"create table test (a text, b integer)"];   [db beginTransaction];   int i = 0;   while (i++ < 20) {   [db executeUpdate:@"insert into test (a, b) values (?, ?)" ,        @"hi'", // look! I put in a ', and I'm not escaping it!        [NSNumber numberWithInt:i]];   }   [db commit]; Tuesday, September 28, 2010
  • 133. What about updates? Database is never copied over again If we did, your customers would lose data Tuesday, September 28, 2010
  • 134. Migrations Concept from Ruby on Rails Evolutionary database design Each database has a "version" App runs all migrations to the latest version Tuesday, September 28, 2010
  • 135. Migrations number name 1 initial_schema 2 update_foo 3 implement_blah Tuesday, September 28, 2010
  • 136. Migrations number name 1 initial_schema 2 update_foo 3 implement_blah Tuesday, September 28, 2010
  • 137. Hand-rolled Database Migrator DEMO Tuesday, September 28, 2010
  • 138. FMDB Migration Manager http://github.com/mocra/fmdb- migration-manager Tuesday, September 28, 2010
  • 139. FMDB Migration Manager NSArray *migrations = [NSArray arrayWithObjects: [CreateStudents migration], // 1 [CreateStaffMembers migration], // 2 [AddStudentNumberToStudents migration], // 3 nil ]; [FmdbMigrationManager executeForDatabasePath:@"/tmp/tmp.db" withMigrations:migrations]; Tuesday, September 28, 2010
  • 140. FMDB Migration Manager @interface CreateStudents : FmdbMigration { } @end @implementation CreateStudents - (void)up { [self createTable:@"students" withColumns:[NSArray arrayWithObjects: [FmdbMigrationColumn columnWithColumnName:@"first_name" columnType:@"string"], [FmdbMigrationColumn columnWithColumnName:@"age" columnType:@"integer" defaultValue:21], nil]; } - (void)down { [self dropTable:@"students"]; } @end Tuesday, September 28, 2010
  • 141. ActiveRecord Person *p = [[Person alloc] init]; p.name = @"Joe"; p.occupation = @"Dishwasher"; [p save]; Person *p = [Person personWithId:5]; ==> Person {id:5, name:Joe, occupation:Dishwasher} Tuesday, September 28, 2010
  • 142. Aptiva's ActiveRecord http://github.com/aptiva/activerecord (YMMV) Tuesday, September 28, 2010