Más contenido relacionado La actualidad más candente (20) Similar a SQLite Techniques (20) SQLite Techniques1. SQLite Techniques
Ben Scheirman
@subdigital
Code / Slides:
github.com/subdigital/iphonedevcon-
sandiego
3. SQLite API
Pure C API
Lots of strange-looking, hard to
debug code
Best choice is to abstract it away
11. Getting Resource
Paths
//fetches
path
for
foo.db
NSString
*resourcePath
=
[[NSBundle
mainBundle]
12. Getting Resource
Paths
//fetches
path
for
foo.db
NSString
*resourcePath
=
[[NSBundle
mainBundle]
pathForResource:@"foo"
13. Getting Resource
Paths
//fetches
path
for
foo.db
NSString
*resourcePath
=
[[NSBundle
mainBundle]
pathForResource:@"foo"
ofType:@"db"];
16. Finding the Documents
Directory
NSArray
*paths
=
NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory,
17. Finding the Documents
Directory
NSArray
*paths
=
NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory,
NSUserDomainMask,
18. Finding the Documents
Directory
NSArray
*paths
=
NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory,
NSUserDomainMask,
YES);
19. Finding the Documents
Directory
NSArray
*paths
=
NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory,
NSUserDomainMask,
YES);
NSString
*documentsDirectory
=
[paths
objectAtIndex:0];
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];
}
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];
}
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];
}
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];
}
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];
}
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];
}
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];
}
35. SQLite API -
Opening a connection
#import "sqlite3.h"
sqlite3 *db;
36. SQLite API -
Opening a connection
#import "sqlite3.h"
sqlite3 *db;
int result = sqlite3_open(PATH, &db);
37. SQLite API -
Opening a connection
#import "sqlite3.h"
sqlite3 *db;
int result = sqlite3_open(PATH, &db);
if (result != SQLITE_OK) {
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"
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];
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];
}
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
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);
45. SQLite API -
executing queries
int sqlite3_exec(
sqlite3 *db,
46. SQLite API -
executing queries
int sqlite3_exec(
sqlite3 *db,
char *sql,
47. SQLite API -
executing queries
int sqlite3_exec(
sqlite3 *db,
char *sql,
int (*callback)(void *, int, char**, char**) callbackFunc,
48. SQLite API -
executing queries
int sqlite3_exec(
sqlite3 *db,
char *sql,
int (*callback)(void *, int, char**, char**) callbackFunc,
void *context,
49. SQLite API -
executing queries
int sqlite3_exec(
sqlite3 *db,
char *sql,
int (*callback)(void *, int, char**, char**) callbackFunc,
void *context,
char **errorMessage
50. SQLite API -
executing queries
int sqlite3_exec(
sqlite3 *db,
char *sql,
int (*callback)(void *, int, char**, char**) callbackFunc,
void *context,
char **errorMessage
);
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
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,
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,
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,
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);
56. SQLite API -
Prepared Statements
More Powerful
Unfortunately much more code!
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);
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) {
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
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
}
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
}
//...
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
}
//...
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
}
//...
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
}
//...
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);
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);
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);
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)
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!
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!
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];
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) {
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];
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];
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];
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];
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);
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);
}
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);
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);
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;
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) {
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)];
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) {
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);
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];
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 {
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
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
}
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:
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]];
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]];
}
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]];
}
}
119. FMDB Usage
FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];
if (![db open])
NSLog(@"Could not open db.");
[db executeUpdate:@"blah blah blah"];
120. FMDB Usage
FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];
if (![db open])
NSLog(@"Could not open db.");
[db executeUpdate:@"blah blah blah"];
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])
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],
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]);
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)"];
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];
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;
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) {
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 (?, ?)" ,
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!
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]];
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]];
}
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];
134. Migrations
Concept from Ruby on Rails
Evolutionary database design
Each database has a "version"
App runs all migrations to the latest
version
138. FMDB Migration
Manager
http://github.com/mocra/fmdb-
migration-manager
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];
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
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}