diff options
| author | Nick Barnes | 2012-10-20 20:34:30 +0100 |
|---|---|---|
| committer | Nick Barnes | 2012-10-20 20:34:30 +0100 |
| commit | 1822b236377d1801c141b19014e751046e596a84 (patch) | |
| tree | 31c06084255221885da134bb2ec894c8c16053ba /mps/code | |
| parent | f0757a16404b0d4e90facee261b78101568a66cd (diff) | |
| download | emacs-1822b236377d1801c141b19014e751046e596a84.tar.gz emacs-1822b236377d1801c141b19014e751046e596a84.zip | |
Better table existence test.
Copied from Perforce
Change: 179985
ServerID: perforce.ravenbrook.com
Diffstat (limited to 'mps/code')
| -rw-r--r-- | mps/code/eventsql.c | 127 |
1 files changed, 60 insertions, 67 deletions
diff --git a/mps/code/eventsql.c b/mps/code/eventsql.c index 1e995bb0f67..d7cf6a3e3f5 100644 --- a/mps/code/eventsql.c +++ b/mps/code/eventsql.c | |||
| @@ -252,73 +252,6 @@ static void closeDatabase(sqlite3 *db) | |||
| 252 | log(LOG_SOMETIMES, "Closed %s.", databaseName); | 252 | log(LOG_SOMETIMES, "Closed %s.", databaseName); |
| 253 | } | 253 | } |
| 254 | 254 | ||
| 255 | /* We need to be able to test for the existence of a table. The | ||
| 256 | * SQLite3 API seems to have no way to explore metadata like this, | ||
| 257 | * unless it is compiled in a particular way (in which case the | ||
| 258 | * function sqlite3_table_column_metadata could be used). Without | ||
| 259 | * that assistance, we can use a simple SQL trick (which could also | ||
| 260 | * tell us the number of rows in the table if we cared). | ||
| 261 | * | ||
| 262 | * TODO: Update this to use the sqlite_master table: | ||
| 263 | * SELECT FROM sqlite_master WHERE type='table' AND name=? | ||
| 264 | * and fix the above comment. | ||
| 265 | */ | ||
| 266 | |||
| 267 | static int tableExists(sqlite3* db, const char *tableName) | ||
| 268 | { | ||
| 269 | const char *format = "SELECT SUM(1) FROM %s"; | ||
| 270 | char *sql; | ||
| 271 | int res; | ||
| 272 | |||
| 273 | sql = malloc(strlen(format) + strlen(tableName)); | ||
| 274 | if (!sql) | ||
| 275 | error("Out of memory."); | ||
| 276 | sprintf(sql, format, tableName); | ||
| 277 | log(LOG_SELDOM, "Testing for existence of table '%s' with SQL: %s", tableName, sql); | ||
| 278 | res = sqlite3_exec(db, | ||
| 279 | sql, | ||
| 280 | NULL, /* put in a callback here if we really want to know the number of rows */ | ||
| 281 | NULL, /* callback closure */ | ||
| 282 | NULL); /* error messages handled by sqlite_error */ | ||
| 283 | free(sql); | ||
| 284 | |||
| 285 | switch(res) { | ||
| 286 | case SQLITE_OK: | ||
| 287 | log(LOG_SELDOM, "Table '%s' exists.", tableName); | ||
| 288 | |||
| 289 | return 1; /* table exists */ | ||
| 290 | break; | ||
| 291 | case SQLITE_ERROR: | ||
| 292 | log(LOG_SELDOM, "Table '%s' does not exist.", tableName); | ||
| 293 | return 0; /* table does not exist; we can | ||
| 294 | probably do a better test for this case. */ | ||
| 295 | break; | ||
| 296 | default: | ||
| 297 | sqlite_error(res, db, "Table test failed: %s", tableName); | ||
| 298 | } | ||
| 299 | /* UNREACHED */ | ||
| 300 | return 0; | ||
| 301 | } | ||
| 302 | |||
| 303 | /* Unit test for tableExists() */ | ||
| 304 | |||
| 305 | static const char *tableTests[] = { | ||
| 306 | "event_kind", | ||
| 307 | "spong", | ||
| 308 | "EVENT_SegSplit", | ||
| 309 | }; | ||
| 310 | |||
| 311 | static void testTableExists(sqlite3 *db) | ||
| 312 | { | ||
| 313 | int i; | ||
| 314 | for (i=0; i < (sizeof(tableTests)/sizeof(tableTests[0])); ++i) { | ||
| 315 | if (tableExists(db, tableTests[i])) | ||
| 316 | printf("Table exists: %s\n", tableTests[i]); | ||
| 317 | else | ||
| 318 | printf("Table does not exist: %s\n", tableTests[i]); | ||
| 319 | } | ||
| 320 | } | ||
| 321 | |||
| 322 | /* Utility functions for SQLite statements. */ | 255 | /* Utility functions for SQLite statements. */ |
| 323 | 256 | ||
| 324 | static sqlite3_stmt *prepareStatement(sqlite3 *db, | 257 | static sqlite3_stmt *prepareStatement(sqlite3 *db, |
| @@ -360,6 +293,66 @@ static void runStatement(sqlite3 *db, | |||
| 360 | sqlite_error(res, db, "%s failed - statement %s", description, sql); | 293 | sqlite_error(res, db, "%s failed - statement %s", description, sql); |
| 361 | } | 294 | } |
| 362 | 295 | ||
| 296 | /* Test for the existence of a table using sqlite_master table. | ||
| 297 | */ | ||
| 298 | |||
| 299 | static int tableExists(sqlite3* db, const char *tableName) | ||
| 300 | { | ||
| 301 | int res; | ||
| 302 | int exists; | ||
| 303 | sqlite3_stmt *statement; | ||
| 304 | |||
| 305 | statement = prepareStatement(db, | ||
| 306 | "SELECT 1 FROM sqlite_master WHERE type='table' AND name=?"); | ||
| 307 | res = sqlite3_bind_text(statement, 1, tableName, -1, SQLITE_STATIC); | ||
| 308 | if (res != SQLITE_OK) | ||
| 309 | sqlite_error(res, db, "table existence bind of name failed."); | ||
| 310 | res = sqlite3_step(statement); | ||
| 311 | switch(res) { | ||
| 312 | case SQLITE_DONE: | ||
| 313 | exists = 0; | ||
| 314 | break; | ||
| 315 | case SQLITE_ROW: | ||
| 316 | exists = 1; | ||
| 317 | break; | ||
| 318 | default: | ||
| 319 | sqlite_error(res, db, "select from sqlite_master failed."); | ||
| 320 | } | ||
| 321 | finalizeStatement(db, statement); | ||
| 322 | return exists; | ||
| 323 | } | ||
| 324 | |||
| 325 | /* Unit test for tableExists() */ | ||
| 326 | |||
| 327 | static struct { | ||
| 328 | const char* name; | ||
| 329 | int exists; | ||
| 330 | } tableTests[] = { | ||
| 331 | {"event_kind", TRUE}, | ||
| 332 | {"spong", FALSE}, | ||
| 333 | {"EVENT_SegSplit", TRUE} | ||
| 334 | }; | ||
| 335 | |||
| 336 | static void testTableExists(sqlite3 *db) | ||
| 337 | { | ||
| 338 | int i; | ||
| 339 | int defects = 0; | ||
| 340 | int tests = 0; | ||
| 341 | for (i=0; i < (sizeof(tableTests)/sizeof(tableTests[0])); ++i) { | ||
| 342 | const char *name = tableTests[i].name; | ||
| 343 | int exists = tableExists(db, name); | ||
| 344 | if (exists) | ||
| 345 | log(LOG_OFTEN, "Table exists: %s", name); | ||
| 346 | else | ||
| 347 | log(LOG_OFTEN, "Table does not exist: %s", name); | ||
| 348 | if (exists != tableTests[i].exists) { | ||
| 349 | log(LOG_ALWAYS, "tableExists test failed on table %s", name); | ||
| 350 | ++ defects; | ||
| 351 | } | ||
| 352 | ++ tests; | ||
| 353 | } | ||
| 354 | log(LOG_ALWAYS, "%d tests, %d defects found.", tests, defects); | ||
| 355 | } | ||
| 363 | 356 | ||
| 364 | /* Every time we put events from a log file into a database file, we | 357 | /* Every time we put events from a log file into a database file, we |
| 365 | * add the log file to the event_log table, and get a serial number | 358 | * add the log file to the event_log table, and get a serial number |