SQLite Techniques

J
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
1 of 143

Recommended

SQLite Techniques by
SQLite TechniquesSQLite Techniques
SQLite Techniquesjoaopmaia
1.1K views143 slides
SQLite Techniques by
SQLite TechniquesSQLite Techniques
SQLite TechniquesBen Scheirman
914 views143 slides
solving little problems by
solving little problemssolving little problems
solving little problemsAustin Ziegler
1.2K views31 slides
NIO.2, the I/O API for the future by
NIO.2, the I/O API for the futureNIO.2, the I/O API for the future
NIO.2, the I/O API for the futureMasoud Kalali
1.9K views29 slides
extending-php by
extending-phpextending-php
extending-phptutorialsruby
663 views24 slides
Mengembalikan data yang terhapus atau rusak pada hardisk menggunakan ubuntu by
Mengembalikan data yang terhapus atau rusak pada hardisk menggunakan ubuntuMengembalikan data yang terhapus atau rusak pada hardisk menggunakan ubuntu
Mengembalikan data yang terhapus atau rusak pada hardisk menggunakan ubuntuAlferizhy Chalter
915 views11 slides

More Related Content

What's hot

The Browser Environment - A Systems Programmer's Perspective [sinatra edition] by
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]Eleanor McHugh
225 views33 slides
Yy by
YyYy
Yyyygh
998 views64 slides
Nouveau document texte by
Nouveau document texteNouveau document texte
Nouveau document texteSai Ef
932 views64 slides
Looping the Loop with SPL Iterators by
Looping the Loop with SPL IteratorsLooping the Loop with SPL Iterators
Looping the Loop with SPL IteratorsMark Baker
270 views55 slides
C99.php by
C99.phpC99.php
C99.phpveng33k
1.5K views68 slides
Go for the paranoid network programmer, 3rd edition by
Go for the paranoid network programmer, 3rd editionGo for the paranoid network programmer, 3rd edition
Go for the paranoid network programmer, 3rd editionEleanor McHugh
254 views199 slides

What's hot(20)

The Browser Environment - A Systems Programmer's Perspective [sinatra edition] by Eleanor McHugh
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
Eleanor McHugh225 views
Yy by yygh
YyYy
Yy
yygh998 views
Nouveau document texte by Sai Ef
Nouveau document texteNouveau document texte
Nouveau document texte
Sai Ef932 views
Looping the Loop with SPL Iterators by Mark Baker
Looping the Loop with SPL IteratorsLooping the Loop with SPL Iterators
Looping the Loop with SPL Iterators
Mark Baker270 views
C99.php by veng33k
C99.phpC99.php
C99.php
veng33k1.5K views
Go for the paranoid network programmer, 3rd edition by Eleanor McHugh
Go for the paranoid network programmer, 3rd editionGo for the paranoid network programmer, 3rd edition
Go for the paranoid network programmer, 3rd edition
Eleanor McHugh254 views
What's new in the Drupal 7 API? by Alexandru Badiu
What's new in the Drupal 7 API?What's new in the Drupal 7 API?
What's new in the Drupal 7 API?
Alexandru Badiu1.5K views
spug_2008-08 by colinmeyer
spug_2008-08spug_2008-08
spug_2008-08
colinmeyer306 views
Filesystem Abstraction with Flysystem by Frank de Jonge
Filesystem Abstraction with FlysystemFilesystem Abstraction with Flysystem
Filesystem Abstraction with Flysystem
Frank de Jonge4.9K views
Ch3(working with file) by Chhom Karath
Ch3(working with file)Ch3(working with file)
Ch3(working with file)
Chhom Karath174 views
Letting In the Light: Using Solr as an External Search Component by Jay Luker
Letting In the Light: Using Solr as an External Search ComponentLetting In the Light: Using Solr as an External Search Component
Letting In the Light: Using Solr as an External Search Component
Jay Luker2.8K views
Speed up your developments with Symfony2 by Hugo Hamon
Speed up your developments with Symfony2Speed up your developments with Symfony2
Speed up your developments with Symfony2
Hugo Hamon4.5K views
JavaScript Classes and Inheritance by marcheiligers
JavaScript Classes and InheritanceJavaScript Classes and Inheritance
JavaScript Classes and Inheritance
marcheiligers1.6K views
Psycopg2 - Connect to PostgreSQL using Python Script by Survey Department
Psycopg2 - Connect to PostgreSQL using Python ScriptPsycopg2 - Connect to PostgreSQL using Python Script
Psycopg2 - Connect to PostgreSQL using Python Script
Survey Department5.5K views

Similar to SQLite Techniques

iPhone for .NET Developers by
iPhone for .NET DevelopersiPhone for .NET Developers
iPhone for .NET DevelopersBen Scheirman
275 views72 slides
MDSD for iPhone and Android by
MDSD for iPhone and AndroidMDSD for iPhone and Android
MDSD for iPhone and AndroidHeiko Behrens
880 views59 slides
09 Data by
09 Data09 Data
09 DataMahmoud
1.6K views166 slides
Mongo db by
Mongo dbMongo db
Mongo dbAntonio Terreno
710 views31 slides
занятие8 by
занятие8занятие8
занятие8Oleg Parinov
659 views15 slides
Lecture 2#- (Intro to Obj-C, Interface Builder and Xcode) by
Lecture 2#- (Intro to Obj-C, Interface Builder and Xcode)Lecture 2#- (Intro to Obj-C, Interface Builder and Xcode)
Lecture 2#- (Intro to Obj-C, Interface Builder and Xcode)Nguyen Thanh Xuan
653 views42 slides

Similar to SQLite Techniques(20)

iPhone for .NET Developers by Ben Scheirman
iPhone for .NET DevelopersiPhone for .NET Developers
iPhone for .NET Developers
Ben Scheirman275 views
MDSD for iPhone and Android by Heiko Behrens
MDSD for iPhone and AndroidMDSD for iPhone and Android
MDSD for iPhone and Android
Heiko Behrens880 views
09 Data by Mahmoud
09 Data09 Data
09 Data
Mahmoud 1.6K views
Lecture 2#- (Intro to Obj-C, Interface Builder and Xcode) by Nguyen Thanh Xuan
Lecture 2#- (Intro to Obj-C, Interface Builder and Xcode)Lecture 2#- (Intro to Obj-C, Interface Builder and Xcode)
Lecture 2#- (Intro to Obj-C, Interface Builder and Xcode)
Nguyen Thanh Xuan653 views
Techfest 2013 No RESTKit for the Weary by Matt Galloway
Techfest 2013 No RESTKit for the WearyTechfest 2013 No RESTKit for the Weary
Techfest 2013 No RESTKit for the Weary
Matt Galloway1.1K views
Data Loading for Ext GWT by Sencha
Data Loading for Ext GWTData Loading for Ext GWT
Data Loading for Ext GWT
Sencha1.5K views
IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP by Guilherme Blanco
IPC2010SE Doctrine2 Enterprise Persistence Layer for PHPIPC2010SE Doctrine2 Enterprise Persistence Layer for PHP
IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP
Guilherme Blanco4.5K views
Continuous Integration Testing for Plone Using Hudson by Eric Steele
Continuous Integration Testing for Plone Using HudsonContinuous Integration Testing for Plone Using Hudson
Continuous Integration Testing for Plone Using Hudson
Eric Steele1.1K views
Large problems, Mostly Solved by ericholscher
Large problems, Mostly SolvedLarge problems, Mostly Solved
Large problems, Mostly Solved
ericholscher1.4K views
Fabric-让部署变得简单 by Eric Lo
Fabric-让部署变得简单Fabric-让部署变得简单
Fabric-让部署变得简单
Eric Lo2.5K views
Acceptance & Integration Testing With Behat (PBC11) by benwaine
Acceptance & Integration Testing With Behat (PBC11)Acceptance & Integration Testing With Behat (PBC11)
Acceptance & Integration Testing With Behat (PBC11)
benwaine3.5K views
Desenvolvendo Aplicativos Sociais com Rails 3 by Carlos Brando
Desenvolvendo Aplicativos Sociais com Rails 3Desenvolvendo Aplicativos Sociais com Rails 3
Desenvolvendo Aplicativos Sociais com Rails 3
Carlos Brando665 views
Mastering the AWS SDK for PHP (TLS306) | AWS re:Invent 2013 by Amazon Web Services
Mastering the AWS SDK for PHP (TLS306) | AWS re:Invent 2013Mastering the AWS SDK for PHP (TLS306) | AWS re:Invent 2013
Mastering the AWS SDK for PHP (TLS306) | AWS re:Invent 2013
Amazon Web Services40.8K views
Developing in HTML5: Widgetbox & Sencha Touch by Sencha
Developing in HTML5: Widgetbox & Sencha TouchDeveloping in HTML5: Widgetbox & Sencha Touch
Developing in HTML5: Widgetbox & Sencha Touch
Sencha1.7K views

More from joaopmaia

AFNetworking by
AFNetworking AFNetworking
AFNetworking joaopmaia
4.6K views23 slides
Core Data presentation by
Core Data presentationCore Data presentation
Core Data presentationjoaopmaia
3.3K views27 slides
Meetup uikit programming by
Meetup uikit programmingMeetup uikit programming
Meetup uikit programmingjoaopmaia
2.9K views13 slides
Web App Testing With Selenium by
Web App Testing With SeleniumWeb App Testing With Selenium
Web App Testing With Seleniumjoaopmaia
2.2K views21 slides
Eventum Presentation by
Eventum PresentationEventum Presentation
Eventum Presentationjoaopmaia
2.7K views15 slides
Form Validation NG by
Form Validation NGForm Validation NG
Form Validation NGjoaopmaia
1.2K views17 slides

More from joaopmaia(6)

AFNetworking by joaopmaia
AFNetworking AFNetworking
AFNetworking
joaopmaia4.6K views
Core Data presentation by joaopmaia
Core Data presentationCore Data presentation
Core Data presentation
joaopmaia3.3K views
Meetup uikit programming by joaopmaia
Meetup uikit programmingMeetup uikit programming
Meetup uikit programming
joaopmaia2.9K views
Web App Testing With Selenium by joaopmaia
Web App Testing With SeleniumWeb App Testing With Selenium
Web App Testing With Selenium
joaopmaia2.2K views
Eventum Presentation by joaopmaia
Eventum PresentationEventum Presentation
Eventum Presentation
joaopmaia2.7K views
Form Validation NG by joaopmaia
Form Validation NGForm Validation NG
Form Validation NG
joaopmaia1.2K views

Recently uploaded

KVM Security Groups Under the Hood - Wido den Hollander - Your.Online by
KVM Security Groups Under the Hood - Wido den Hollander - Your.OnlineKVM Security Groups Under the Hood - Wido den Hollander - Your.Online
KVM Security Groups Under the Hood - Wido den Hollander - Your.OnlineShapeBlue
221 views19 slides
Kyo - Functional Scala 2023.pdf by
Kyo - Functional Scala 2023.pdfKyo - Functional Scala 2023.pdf
Kyo - Functional Scala 2023.pdfFlavio W. Brasil
457 views92 slides
Enabling DPU Hardware Accelerators in XCP-ng Cloud Platform Environment - And... by
Enabling DPU Hardware Accelerators in XCP-ng Cloud Platform Environment - And...Enabling DPU Hardware Accelerators in XCP-ng Cloud Platform Environment - And...
Enabling DPU Hardware Accelerators in XCP-ng Cloud Platform Environment - And...ShapeBlue
106 views12 slides
Live Demo Showcase: Unveiling Dell PowerFlex’s IaaS Capabilities with Apache ... by
Live Demo Showcase: Unveiling Dell PowerFlex’s IaaS Capabilities with Apache ...Live Demo Showcase: Unveiling Dell PowerFlex’s IaaS Capabilities with Apache ...
Live Demo Showcase: Unveiling Dell PowerFlex’s IaaS Capabilities with Apache ...ShapeBlue
126 views10 slides
Business Analyst Series 2023 - Week 4 Session 8 by
Business Analyst Series 2023 -  Week 4 Session 8Business Analyst Series 2023 -  Week 4 Session 8
Business Analyst Series 2023 - Week 4 Session 8DianaGray10
123 views13 slides
GDG Cloud Southlake 28 Brad Taylor and Shawn Augenstein Old Problems in the N... by
GDG Cloud Southlake 28 Brad Taylor and Shawn Augenstein Old Problems in the N...GDG Cloud Southlake 28 Brad Taylor and Shawn Augenstein Old Problems in the N...
GDG Cloud Southlake 28 Brad Taylor and Shawn Augenstein Old Problems in the N...James Anderson
160 views32 slides

Recently uploaded(20)

KVM Security Groups Under the Hood - Wido den Hollander - Your.Online by ShapeBlue
KVM Security Groups Under the Hood - Wido den Hollander - Your.OnlineKVM Security Groups Under the Hood - Wido den Hollander - Your.Online
KVM Security Groups Under the Hood - Wido den Hollander - Your.Online
ShapeBlue221 views
Enabling DPU Hardware Accelerators in XCP-ng Cloud Platform Environment - And... by ShapeBlue
Enabling DPU Hardware Accelerators in XCP-ng Cloud Platform Environment - And...Enabling DPU Hardware Accelerators in XCP-ng Cloud Platform Environment - And...
Enabling DPU Hardware Accelerators in XCP-ng Cloud Platform Environment - And...
ShapeBlue106 views
Live Demo Showcase: Unveiling Dell PowerFlex’s IaaS Capabilities with Apache ... by ShapeBlue
Live Demo Showcase: Unveiling Dell PowerFlex’s IaaS Capabilities with Apache ...Live Demo Showcase: Unveiling Dell PowerFlex’s IaaS Capabilities with Apache ...
Live Demo Showcase: Unveiling Dell PowerFlex’s IaaS Capabilities with Apache ...
ShapeBlue126 views
Business Analyst Series 2023 - Week 4 Session 8 by DianaGray10
Business Analyst Series 2023 -  Week 4 Session 8Business Analyst Series 2023 -  Week 4 Session 8
Business Analyst Series 2023 - Week 4 Session 8
DianaGray10123 views
GDG Cloud Southlake 28 Brad Taylor and Shawn Augenstein Old Problems in the N... by James Anderson
GDG Cloud Southlake 28 Brad Taylor and Shawn Augenstein Old Problems in the N...GDG Cloud Southlake 28 Brad Taylor and Shawn Augenstein Old Problems in the N...
GDG Cloud Southlake 28 Brad Taylor and Shawn Augenstein Old Problems in the N...
James Anderson160 views
TrustArc Webinar - Managing Online Tracking Technology Vendors_ A Checklist f... by TrustArc
TrustArc Webinar - Managing Online Tracking Technology Vendors_ A Checklist f...TrustArc Webinar - Managing Online Tracking Technology Vendors_ A Checklist f...
TrustArc Webinar - Managing Online Tracking Technology Vendors_ A Checklist f...
TrustArc170 views
Business Analyst Series 2023 - Week 4 Session 7 by DianaGray10
Business Analyst Series 2023 -  Week 4 Session 7Business Analyst Series 2023 -  Week 4 Session 7
Business Analyst Series 2023 - Week 4 Session 7
DianaGray10139 views
Future of AR - Facebook Presentation by Rob McCarty
Future of AR - Facebook PresentationFuture of AR - Facebook Presentation
Future of AR - Facebook Presentation
Rob McCarty64 views
iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas... by Bernd Ruecker
iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas...iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas...
iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas...
Bernd Ruecker54 views
How to Re-use Old Hardware with CloudStack. Saving Money and the Environment ... by ShapeBlue
How to Re-use Old Hardware with CloudStack. Saving Money and the Environment ...How to Re-use Old Hardware with CloudStack. Saving Money and the Environment ...
How to Re-use Old Hardware with CloudStack. Saving Money and the Environment ...
ShapeBlue166 views
Centralized Logging Feature in CloudStack using ELK and Grafana - Kiran Chava... by ShapeBlue
Centralized Logging Feature in CloudStack using ELK and Grafana - Kiran Chava...Centralized Logging Feature in CloudStack using ELK and Grafana - Kiran Chava...
Centralized Logging Feature in CloudStack using ELK and Grafana - Kiran Chava...
ShapeBlue145 views
Updates on the LINSTOR Driver for CloudStack - Rene Peinthor - LINBIT by ShapeBlue
Updates on the LINSTOR Driver for CloudStack - Rene Peinthor - LINBITUpdates on the LINSTOR Driver for CloudStack - Rene Peinthor - LINBIT
Updates on the LINSTOR Driver for CloudStack - Rene Peinthor - LINBIT
ShapeBlue206 views
"Surviving highload with Node.js", Andrii Shumada by Fwdays
"Surviving highload with Node.js", Andrii Shumada "Surviving highload with Node.js", Andrii Shumada
"Surviving highload with Node.js", Andrii Shumada
Fwdays56 views
CloudStack and GitOps at Enterprise Scale - Alex Dometrius, Rene Glover - AT&T by ShapeBlue
CloudStack and GitOps at Enterprise Scale - Alex Dometrius, Rene Glover - AT&TCloudStack and GitOps at Enterprise Scale - Alex Dometrius, Rene Glover - AT&T
CloudStack and GitOps at Enterprise Scale - Alex Dometrius, Rene Glover - AT&T
ShapeBlue152 views
What’s New in CloudStack 4.19 - Abhishek Kumar - ShapeBlue by ShapeBlue
What’s New in CloudStack 4.19 - Abhishek Kumar - ShapeBlueWhat’s New in CloudStack 4.19 - Abhishek Kumar - ShapeBlue
What’s New in CloudStack 4.19 - Abhishek Kumar - ShapeBlue
ShapeBlue263 views
Extending KVM Host HA for Non-NFS Storage - Alex Ivanov - StorPool by ShapeBlue
Extending KVM Host HA for Non-NFS Storage -  Alex Ivanov - StorPoolExtending KVM Host HA for Non-NFS Storage -  Alex Ivanov - StorPool
Extending KVM Host HA for Non-NFS Storage - Alex Ivanov - StorPool
ShapeBlue123 views
Initiating and Advancing Your Strategic GIS Governance Strategy by Safe Software
Initiating and Advancing Your Strategic GIS Governance StrategyInitiating and Advancing Your Strategic GIS Governance Strategy
Initiating and Advancing Your Strategic GIS Governance Strategy
Safe Software176 views
Digital Personal Data Protection (DPDP) Practical Approach For CISOs by Priyanka Aash
Digital Personal Data Protection (DPDP) Practical Approach For CISOsDigital Personal Data Protection (DPDP) Practical Approach For CISOs
Digital Personal Data Protection (DPDP) Practical Approach For CISOs
Priyanka Aash158 views

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