Fossil SCM
More reliably work around the problem experienced by the previous commit. Not sure if this is the right long-term solution since we seem to have an architectural problem: at least one of Fossil's custom SQL functions can change the schema (in this case, by creating a temporary table), thereby invalidating a prepared statement while it is running. See the comment in checkin.c for a bit more information. Of course, there are rearrangements that avoid the issue, but it is certainly a trap for the unwary.
Commit
5258a43d78fd433daa4ed36cae21b1d7e46c4efd
Parent
9d5de8d702e8b00…
2 files changed
+6
-13
+2
-2
+6
-13
| --- src/checkin.c | ||
| +++ src/checkin.c | ||
| @@ -173,23 +173,16 @@ | ||
| 173 | 173 | flags & C_MTIME ? "datetime(mtime, 'unixepoch', toLocal())" : "''", |
| 174 | 174 | flags & C_SIZE ? "size" : "0", |
| 175 | 175 | fossil_all_reserved_names(0), blob_sql_text(&where)); |
| 176 | 176 | } |
| 177 | 177 | |
| 178 | -#if 1 | |
| 179 | - /* SQLITE BUG WORKAROUND??? */ | |
| 180 | - /* If I step the query sans the ORDER BY clause, then I can run the full query | |
| 181 | - * without incident. But if I delete this workaround and run the query | |
| 182 | - * normally, I get SQLITE_ABORT due to ROLLBACK, which makes no sense. */ | |
| 183 | - db_prepare(&q, "%s", blob_sql_text(&sql)); | |
| 184 | - if( (flags & C_ALL) && (flags & C_MTIME) ){ | |
| 185 | - db_bind_int(&q, ":vid", db_lget_int("checkout", 0)); | |
| 186 | - } | |
| 187 | - db_step(&q); | |
| 188 | - db_finalize(&q); | |
| 189 | - /* SQLITE BUG WORKAROUND??? */ | |
| 190 | -#endif | |
| 178 | + /* Pre-create the "ok" temporary table so the checkin_mtime() SQL function | |
| 179 | + * does not lead to SQLITE_ABORT_ROLLBACK during execution of the OP_OpenRead | |
| 180 | + * SQLite opcode. checkin_mtime() calls mtime_of_manifest_file() which | |
| 181 | + * creates a temporary table if it doesn't already exist, thus invalidating | |
| 182 | + * the prepared statement in the middle of its execution. */ | |
| 183 | + db_multi_exec("CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY)"); | |
| 191 | 184 | |
| 192 | 185 | /* Append an ORDER BY clause then compile the query. */ |
| 193 | 186 | blob_append_sql(&sql, " ORDER BY pathname"); |
| 194 | 187 | db_prepare(&q, "%s", blob_sql_text(&sql)); |
| 195 | 188 | blob_reset(&sql); |
| 196 | 189 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -173,23 +173,16 @@ | |
| 173 | flags & C_MTIME ? "datetime(mtime, 'unixepoch', toLocal())" : "''", |
| 174 | flags & C_SIZE ? "size" : "0", |
| 175 | fossil_all_reserved_names(0), blob_sql_text(&where)); |
| 176 | } |
| 177 | |
| 178 | #if 1 |
| 179 | /* SQLITE BUG WORKAROUND??? */ |
| 180 | /* If I step the query sans the ORDER BY clause, then I can run the full query |
| 181 | * without incident. But if I delete this workaround and run the query |
| 182 | * normally, I get SQLITE_ABORT due to ROLLBACK, which makes no sense. */ |
| 183 | db_prepare(&q, "%s", blob_sql_text(&sql)); |
| 184 | if( (flags & C_ALL) && (flags & C_MTIME) ){ |
| 185 | db_bind_int(&q, ":vid", db_lget_int("checkout", 0)); |
| 186 | } |
| 187 | db_step(&q); |
| 188 | db_finalize(&q); |
| 189 | /* SQLITE BUG WORKAROUND??? */ |
| 190 | #endif |
| 191 | |
| 192 | /* Append an ORDER BY clause then compile the query. */ |
| 193 | blob_append_sql(&sql, " ORDER BY pathname"); |
| 194 | db_prepare(&q, "%s", blob_sql_text(&sql)); |
| 195 | blob_reset(&sql); |
| 196 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -173,23 +173,16 @@ | |
| 173 | flags & C_MTIME ? "datetime(mtime, 'unixepoch', toLocal())" : "''", |
| 174 | flags & C_SIZE ? "size" : "0", |
| 175 | fossil_all_reserved_names(0), blob_sql_text(&where)); |
| 176 | } |
| 177 | |
| 178 | /* Pre-create the "ok" temporary table so the checkin_mtime() SQL function |
| 179 | * does not lead to SQLITE_ABORT_ROLLBACK during execution of the OP_OpenRead |
| 180 | * SQLite opcode. checkin_mtime() calls mtime_of_manifest_file() which |
| 181 | * creates a temporary table if it doesn't already exist, thus invalidating |
| 182 | * the prepared statement in the middle of its execution. */ |
| 183 | db_multi_exec("CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY)"); |
| 184 | |
| 185 | /* Append an ORDER BY clause then compile the query. */ |
| 186 | blob_append_sql(&sql, " ORDER BY pathname"); |
| 187 | db_prepare(&q, "%s", blob_sql_text(&sql)); |
| 188 | blob_reset(&sql); |
| 189 |
+2
-2
| --- src/descendants.c | ||
| +++ src/descendants.c | ||
| @@ -216,12 +216,12 @@ | ||
| 216 | 216 | static int prevVid = -1; |
| 217 | 217 | static Stmt q; |
| 218 | 218 | |
| 219 | 219 | if( prevVid!=vid ){ |
| 220 | 220 | prevVid = vid; |
| 221 | - db_multi_exec("DROP TABLE IF EXISTS temp.ok;" | |
| 222 | - "CREATE TEMP TABLE ok(x INTEGER PRIMARY KEY);"); | |
| 221 | + db_multi_exec("CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);" | |
| 222 | + "DELETE FROM ok;"); | |
| 223 | 223 | compute_ancestors(vid, 100000000, 1); |
| 224 | 224 | } |
| 225 | 225 | db_static_prepare(&q, |
| 226 | 226 | "SELECT (max(event.mtime)-2440587.5)*86400 FROM mlink, event" |
| 227 | 227 | " WHERE mlink.mid=event.objid" |
| 228 | 228 |
| --- src/descendants.c | |
| +++ src/descendants.c | |
| @@ -216,12 +216,12 @@ | |
| 216 | static int prevVid = -1; |
| 217 | static Stmt q; |
| 218 | |
| 219 | if( prevVid!=vid ){ |
| 220 | prevVid = vid; |
| 221 | db_multi_exec("DROP TABLE IF EXISTS temp.ok;" |
| 222 | "CREATE TEMP TABLE ok(x INTEGER PRIMARY KEY);"); |
| 223 | compute_ancestors(vid, 100000000, 1); |
| 224 | } |
| 225 | db_static_prepare(&q, |
| 226 | "SELECT (max(event.mtime)-2440587.5)*86400 FROM mlink, event" |
| 227 | " WHERE mlink.mid=event.objid" |
| 228 |
| --- src/descendants.c | |
| +++ src/descendants.c | |
| @@ -216,12 +216,12 @@ | |
| 216 | static int prevVid = -1; |
| 217 | static Stmt q; |
| 218 | |
| 219 | if( prevVid!=vid ){ |
| 220 | prevVid = vid; |
| 221 | db_multi_exec("CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);" |
| 222 | "DELETE FROM ok;"); |
| 223 | compute_ancestors(vid, 100000000, 1); |
| 224 | } |
| 225 | db_static_prepare(&q, |
| 226 | "SELECT (max(event.mtime)-2440587.5)*86400 FROM mlink, event" |
| 227 | " WHERE mlink.mid=event.objid" |
| 228 |