FMDatabaseAdditions.m 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. //
  2. // FMDatabaseAdditions.m
  3. // fmkit
  4. //
  5. // Created by August Mueller on 10/30/05.
  6. // Copyright 2005 Flying Meat Inc.. All rights reserved.
  7. //
  8. #import "FMDatabase.h"
  9. #import "FMDatabaseAdditions.h"
  10. @interface FMDatabase (PrivateStuff)
  11. - (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray*)arrayArgs orDictionary:(NSDictionary *)dictionaryArgs orVAList:(va_list)args;
  12. @end
  13. @implementation FMDatabase (FMDatabaseAdditions)
  14. #define RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(type, sel) \
  15. va_list args; \
  16. va_start(args, query); \
  17. FMResultSet *resultSet = [self executeQuery:query withArgumentsInArray:0x00 orDictionary:0x00 orVAList:args]; \
  18. va_end(args); \
  19. if (![resultSet next]) { return (type)0; } \
  20. type ret = [resultSet sel:0]; \
  21. [resultSet close]; \
  22. [resultSet setParentDB:nil]; \
  23. return ret;
  24. - (NSString*)stringForQuery:(NSString*)query, ... {
  25. RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSString *, stringForColumnIndex);
  26. }
  27. - (int)intForQuery:(NSString*)query, ... {
  28. RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(int, intForColumnIndex);
  29. }
  30. - (long)longForQuery:(NSString*)query, ... {
  31. RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(long, longForColumnIndex);
  32. }
  33. - (BOOL)boolForQuery:(NSString*)query, ... {
  34. RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(BOOL, boolForColumnIndex);
  35. }
  36. - (double)doubleForQuery:(NSString*)query, ... {
  37. RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(double, doubleForColumnIndex);
  38. }
  39. - (NSData*)dataForQuery:(NSString*)query, ... {
  40. RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSData *, dataForColumnIndex);
  41. }
  42. - (NSDate*)dateForQuery:(NSString*)query, ... {
  43. RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSDate *, dateForColumnIndex);
  44. }
  45. - (BOOL)tableExists:(NSString*)tableName {
  46. tableName = [tableName lowercaseString];
  47. FMResultSet *rs = [self executeQuery:@"select [sql] from sqlite_master where [type] = 'table' and lower(name) = ?", tableName];
  48. //if at least one next exists, table exists
  49. BOOL returnBool = [rs next];
  50. //close and free object
  51. [rs close];
  52. return returnBool;
  53. }
  54. /*
  55. get table with list of tables: result colums: type[STRING], name[STRING],tbl_name[STRING],rootpage[INTEGER],sql[STRING]
  56. check if table exist in database (patch from OZLB)
  57. */
  58. - (FMResultSet*)getSchema {
  59. //result colums: type[STRING], name[STRING],tbl_name[STRING],rootpage[INTEGER],sql[STRING]
  60. FMResultSet *rs = [self executeQuery:@"SELECT type, name, tbl_name, rootpage, sql FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE type != 'meta' AND name NOT LIKE 'sqlite_%' ORDER BY tbl_name, type DESC, name"];
  61. return rs;
  62. }
  63. /*
  64. get table schema: result colums: cid[INTEGER], name,type [STRING], notnull[INTEGER], dflt_value[],pk[INTEGER]
  65. */
  66. - (FMResultSet*)getTableSchema:(NSString*)tableName {
  67. //result colums: cid[INTEGER], name,type [STRING], notnull[INTEGER], dflt_value[],pk[INTEGER]
  68. FMResultSet *rs = [self executeQuery:[NSString stringWithFormat: @"PRAGMA table_info(%@)", tableName]];
  69. return rs;
  70. }
  71. - (BOOL)columnExists:(NSString*)tableName columnName:(NSString*)columnName {
  72. BOOL returnBool = NO;
  73. tableName = [tableName lowercaseString];
  74. columnName = [columnName lowercaseString];
  75. FMResultSet *rs = [self getTableSchema:tableName];
  76. //check if column is present in table schema
  77. while ([rs next]) {
  78. if ([[[rs stringForColumn:@"name"] lowercaseString] isEqualToString: columnName]) {
  79. returnBool = YES;
  80. break;
  81. }
  82. }
  83. return returnBool;
  84. }
  85. - (BOOL)validateSQL:(NSString*)sql error:(NSError**)error {
  86. sqlite3_stmt *pStmt = NULL;
  87. BOOL validationSucceeded = YES;
  88. BOOL keepTrying = YES;
  89. int numberOfRetries = 0;
  90. while (keepTrying == YES) {
  91. keepTrying = NO;
  92. int rc = sqlite3_prepare_v2(_db, [sql UTF8String], -1, &pStmt, 0);
  93. if (rc == SQLITE_BUSY || rc == SQLITE_LOCKED) {
  94. keepTrying = YES;
  95. usleep(20);
  96. if (_busyRetryTimeout && (numberOfRetries++ > _busyRetryTimeout)) {
  97. NSLog(@"%s:%d Database busy (%@)", __FUNCTION__, __LINE__, [self databasePath]);
  98. NSLog(@"Database busy");
  99. }
  100. }
  101. else if (rc != SQLITE_OK) {
  102. validationSucceeded = NO;
  103. if (error) {
  104. *error = [NSError errorWithDomain:NSCocoaErrorDomain
  105. code:[self lastErrorCode]
  106. userInfo:[NSDictionary dictionaryWithObject:[self lastErrorMessage]
  107. forKey:NSLocalizedDescriptionKey]];
  108. }
  109. }
  110. }
  111. sqlite3_finalize(pStmt);
  112. return validationSucceeded;
  113. }
  114. @end