1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
| - (BOOL)executeUpdate:(NSString*)sql error:(NSError**)outErr withArgumentsInArray:(NSArray*)arrayArgs orDictionary:(NSDictionary *)dictionaryArgs orVAList:(va_list)args { if (![self databaseExists]) { return NO; } if (_isExecutingStatement) { [self warnInUse]; return NO; } _isExecutingStatement = YES; int rc = 0x00; sqlite3_stmt *pStmt = 0x00; FMStatement *cachedStmt = 0x00; if (_traceExecution && sql) { NSLog(@"%@ executeUpdate: %@", self, sql); } if (_shouldCacheStatements) { cachedStmt = [self cachedStatementForQuery:sql]; pStmt = cachedStmt ? [cachedStmt statement] : 0x00; [cachedStmt reset]; } if (!pStmt) { rc = sqlite3_prepare_v2(_db, [sql UTF8String], -1, &pStmt, 0); if (SQLITE_OK != rc) { if (_logsErrors) { NSLog(@"DB Error: %d \"%@\"", [self lastErrorCode], [self lastErrorMessage]); NSLog(@"DB Query: %@", sql); NSLog(@"DB Path: %@", _databasePath); } if (_crashOnErrors) { NSAssert(false, @"DB Error: %d \"%@\"", [self lastErrorCode], [self lastErrorMessage]); abort(); } if (outErr) { *outErr = [self errorWithMessage:[NSString stringWithUTF8String:sqlite3_errmsg(_db)]]; } sqlite3_finalize(pStmt); _isExecutingStatement = NO; return NO; } } id obj; int idx = 0; int queryCount = sqlite3_bind_parameter_count(pStmt); // If dictionaryArgs is passed in, that means we are using sqlite's named parameter support if (dictionaryArgs) { for (NSString *dictionaryKey in [dictionaryArgs allKeys]) { // Prefix the key with a colon. NSString *parameterName = [[NSString alloc] initWithFormat:@":%@", dictionaryKey]; if (_traceExecution) { NSLog(@"%@ = %@", parameterName, [dictionaryArgs objectForKey:dictionaryKey]); } // Get the index for the parameter name. int namedIdx = sqlite3_bind_parameter_index(pStmt, [parameterName UTF8String]); FMDBRelease(parameterName); if (namedIdx > 0) { // Standard binding from here. [self bindObject:[dictionaryArgs objectForKey:dictionaryKey] toColumn:namedIdx inStatement:pStmt]; // increment the binding count, so our check below works out idx++; } else { // 由于多了outErr,所以绑定时出错需要将error抛出 NSString *message = [NSString stringWithFormat:@"Could not find index for %@", dictionaryKey]; if (_logsErrors) { NSLog(@"%@", message); } if (outErr) { *outErr = [self errorWithMessage:message]; } } } } else { while (idx < queryCount) { if (arrayArgs && idx < (int)[arrayArgs count]) { obj = [arrayArgs objectAtIndex:(NSUInteger)idx]; } else if (args) { obj = va_arg(args, id); } else { //We ran out of arguments break; } if (_traceExecution) { if ([obj isKindOfClass:[NSData class]]) { NSLog(@"data: %ld bytes", (unsigned long)[(NSData*)obj length]); } else { NSLog(@"obj: %@", obj); } } idx++; [self bindObject:obj toColumn:idx inStatement:pStmt]; } } if (idx != queryCount) { // 同样也是组装error抛出 NSString *message = [NSString stringWithFormat:@"Error: the bind count (%d) is not correct for the # of variables in the query (%d) (%@) (executeUpdate)", idx, queryCount, sql]; if (_logsErrors) { NSLog(@"%@", message); } if (outErr) { *outErr = [self errorWithMessage:message]; } sqlite3_finalize(pStmt); _isExecutingStatement = NO; return NO; } /* Call sqlite3_step() to run the virtual machine. Since the SQL being ** executed is not a SELECT statement, we assume no data will be returned. */ // sqlite3_prepare函数将SQL命令字符串解析并转换为一系列的命令字节码,这些字节码最终被传送到SQlite3的虚拟数据库引擎(VDBE: Virtual Database Engine)中执行,完成这项工作的是sqlite3_step函数。比如一个SELECT查询操作,sqlite3_step函数的每次调用都会返回结果集中的其中一行,直到再没有有效数据行了。每次调用sqlite3_step函数如果返回SQLITE_ROW,代表获得了有效数据行,可以通过sqlite3_column函数提取某列的值。如果调用sqlite3_step函数返回SQLITE_DONE,则代表prepared语句已经执行到终点了,没有有效数据了。很多命令第一次调用sqlite3_step函数就会返回SQLITE_DONE,因为这些SQL命令不会返回数据。对于INSERT,UPDATE,DELETE命令,会返回它们所修改的行号——一个单行单列的值。 /** SQLITE_BUSY 数据库文件有锁 SQLITE_LOCKED 数据库中的某张表有锁 SQLITE_DONE sqlite3_step()执行完毕 SQLITE_ROW sqlite3_step()获取到下一行数据 SQLITE_ERROR 一般用于没有特别指定错误码的错误,就是说函数在执行过程中发生了错误,但无法知道错误发生的原因。 SQLITE_MISUSE 没有正确使用SQLite接口,比如一条语句在sqlite3_step函数执行之后,没有被重置之前,再次给其绑定参数,这时bind函数就会返回SQLITE_MISUSE。 **/ rc = sqlite3_step(pStmt); if (SQLITE_DONE == rc) { // all is well, let's return. } // sql操作被sqlite3_interrupt()函数终止 else if (SQLITE_INTERRUPT == rc) { if (_logsErrors) { NSLog(@"Error calling sqlite3_step. Query was interrupted (%d: %s) SQLITE_INTERRUPT", rc, sqlite3_errmsg(_db)); NSLog(@"DB Query: %@", sql); } } else if (rc == SQLITE_ROW) { NSString *message = [NSString stringWithFormat:@"A executeUpdate is being called with a query string '%@'", sql]; if (_logsErrors) { NSLog(@"%@", message); NSLog(@"DB Query: %@", sql); } if (outErr) { *outErr = [self errorWithMessage:message]; } } else { if (outErr) { *outErr = [self errorWithMessage:[NSString stringWithUTF8String:sqlite3_errmsg(_db)]]; } if (SQLITE_ERROR == rc) { if (_logsErrors) { NSLog(@"Error calling sqlite3_step (%d: %s) SQLITE_ERROR", rc, sqlite3_errmsg(_db)); NSLog(@"DB Query: %@", sql); } } else if (SQLITE_MISUSE == rc) { // uh oh. if (_logsErrors) { NSLog(@"Error calling sqlite3_step (%d: %s) SQLITE_MISUSE", rc, sqlite3_errmsg(_db)); NSLog(@"DB Query: %@", sql); } } else { // wtf? if (_logsErrors) { NSLog(@"Unknown error calling sqlite3_step (%d: %s) eu", rc, sqlite3_errmsg(_db)); NSLog(@"DB Query: %@", sql); } } } if (_shouldCacheStatements && !cachedStmt) { cachedStmt = [[FMStatement alloc] init]; [cachedStmt setStatement:pStmt]; [self setCachedStatement:cachedStmt forQuery:sql]; FMDBRelease(cachedStmt); } int closeErrorCode; if (cachedStmt) { [cachedStmt setUseCount:[cachedStmt useCount] + 1]; closeErrorCode = sqlite3_reset(pStmt); } else { /* Finalize the virtual machine. This releases all memory and other ** resources allocated by the sqlite3_prepare() call above. */ closeErrorCode = sqlite3_finalize(pStmt); } if (closeErrorCode != SQLITE_OK) { if (_logsErrors) { NSLog(@"Unknown error finalizing or resetting statement (%d: %s)", closeErrorCode, sqlite3_errmsg(_db)); NSLog(@"DB Query: %@", sql); } } _isExecutingStatement = NO; return (rc == SQLITE_DONE || rc == SQLITE_OK); }
|