Fossil SCM
When logging transaction errors on the error log, try to include information about where the transaction started.
Commit
43336f67c37beb7d1b4cad0804d1bd79da046cf69a77cb1626416dc539d4ba1e
Parent
c6ecf21f37a8091…
2 files changed
+24
-3
+2
-1
M
src/db.c
+24
-3
| --- src/db.c | ||
| +++ src/db.c | ||
| @@ -124,10 +124,12 @@ | ||
| 124 | 124 | } aHook[5]; |
| 125 | 125 | char *azDeleteOnFail[3]; /* Files to delete on a failure */ |
| 126 | 126 | char *azBeforeCommit[5]; /* Commands to run prior to COMMIT */ |
| 127 | 127 | int nBeforeCommit; /* Number of entries in azBeforeCommit */ |
| 128 | 128 | int nPriorChanges; /* sqlite3_total_changes() at transaction start */ |
| 129 | + const char *zStartFile; /* File in which transaction was started */ | |
| 130 | + int iStartLine; /* Line of zStartFile where transaction started */ | |
| 129 | 131 | } db = {0, 0, 0, 0, 0, 0, }; |
| 130 | 132 | |
| 131 | 133 | /* |
| 132 | 134 | ** Arrange for the given file to be deleted on a failure. |
| 133 | 135 | */ |
| @@ -141,10 +143,18 @@ | ||
| 141 | 143 | ** not in a transaction. |
| 142 | 144 | */ |
| 143 | 145 | int db_transaction_nesting_depth(void){ |
| 144 | 146 | return db.nBegin; |
| 145 | 147 | } |
| 148 | + | |
| 149 | +/* | |
| 150 | +** Return a pointer to a string that is the code point where the | |
| 151 | +** current transaction was started. | |
| 152 | +*/ | |
| 153 | +char *db_transaction_start_point(void){ | |
| 154 | + return mprintf("%s:%d", db.zStartFile, db.iStartLine); | |
| 155 | +} | |
| 146 | 156 | |
| 147 | 157 | /* |
| 148 | 158 | ** This routine is called by the SQLite commit-hook mechanism |
| 149 | 159 | ** just prior to each commit. All this routine does is verify |
| 150 | 160 | ** that nBegin really is zero. That insures that transactions |
| @@ -159,19 +169,29 @@ | ||
| 159 | 169 | return 1; |
| 160 | 170 | } |
| 161 | 171 | return 0; |
| 162 | 172 | } |
| 163 | 173 | |
| 174 | +/* | |
| 175 | +** Silently add the filename and line number as parameter to each | |
| 176 | +** db_begin_transaction call. | |
| 177 | +*/ | |
| 178 | +#if INTERFACE | |
| 179 | +#define db_begin_transaction() db_begin_transaction_real(__FILE__,__LINE__) | |
| 180 | +#endif | |
| 181 | + | |
| 164 | 182 | /* |
| 165 | 183 | ** Begin and end a nested transaction |
| 166 | 184 | */ |
| 167 | -void db_begin_transaction(void){ | |
| 185 | +void db_begin_transaction_real(const char *zStartFile, int iStartLine){ | |
| 168 | 186 | if( db.nBegin==0 ){ |
| 169 | 187 | db_multi_exec("BEGIN"); |
| 170 | 188 | sqlite3_commit_hook(g.db, db_verify_at_commit, 0); |
| 171 | 189 | db.nPriorChanges = sqlite3_total_changes(g.db); |
| 172 | 190 | db.doRollback = 0; |
| 191 | + db.zStartFile = zStartFile; | |
| 192 | + db.iStartLine = iStartLine; | |
| 173 | 193 | } |
| 174 | 194 | db.nBegin++; |
| 175 | 195 | } |
| 176 | 196 | void db_end_transaction(int rollbackFlag){ |
| 177 | 197 | if( g.db==0 ) return; |
| @@ -522,11 +542,11 @@ | ||
| 522 | 542 | blob_append(pBlob, sqlite3_column_blob(pStmt->pStmt, N), |
| 523 | 543 | sqlite3_column_bytes(pStmt->pStmt, N)); |
| 524 | 544 | } |
| 525 | 545 | Blob db_column_text_as_blob(Stmt *pStmt, int N){ |
| 526 | 546 | Blob x; |
| 527 | - blob_init(&x, sqlite3_column_text(pStmt->pStmt,N), | |
| 547 | + blob_init(&x, (char*)sqlite3_column_text(pStmt->pStmt,N), | |
| 528 | 548 | sqlite3_column_bytes(pStmt->pStmt,N)); |
| 529 | 549 | return x; |
| 530 | 550 | } |
| 531 | 551 | |
| 532 | 552 | /* |
| @@ -1783,11 +1803,12 @@ | ||
| 1783 | 1803 | } |
| 1784 | 1804 | while( db.pAllStmt ){ |
| 1785 | 1805 | db_finalize(db.pAllStmt); |
| 1786 | 1806 | } |
| 1787 | 1807 | if( db.nBegin && reportErrors ){ |
| 1788 | - fossil_warning("Missed call to db_end_transaction(). Rolling back."); | |
| 1808 | + fossil_warning("Transaction started at %s:%d never commits", | |
| 1809 | + db.zStartFile, db.iStartLine); | |
| 1789 | 1810 | db_end_transaction(1); |
| 1790 | 1811 | } |
| 1791 | 1812 | pStmt = 0; |
| 1792 | 1813 | g.dbIgnoreErrors++; /* Stop "database locked" warnings from PRAGMA optimize */ |
| 1793 | 1814 | sqlite3_exec(g.db, "PRAGMA optimize", 0, 0, 0); |
| 1794 | 1815 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -124,10 +124,12 @@ | |
| 124 | } aHook[5]; |
| 125 | char *azDeleteOnFail[3]; /* Files to delete on a failure */ |
| 126 | char *azBeforeCommit[5]; /* Commands to run prior to COMMIT */ |
| 127 | int nBeforeCommit; /* Number of entries in azBeforeCommit */ |
| 128 | int nPriorChanges; /* sqlite3_total_changes() at transaction start */ |
| 129 | } db = {0, 0, 0, 0, 0, 0, }; |
| 130 | |
| 131 | /* |
| 132 | ** Arrange for the given file to be deleted on a failure. |
| 133 | */ |
| @@ -141,10 +143,18 @@ | |
| 141 | ** not in a transaction. |
| 142 | */ |
| 143 | int db_transaction_nesting_depth(void){ |
| 144 | return db.nBegin; |
| 145 | } |
| 146 | |
| 147 | /* |
| 148 | ** This routine is called by the SQLite commit-hook mechanism |
| 149 | ** just prior to each commit. All this routine does is verify |
| 150 | ** that nBegin really is zero. That insures that transactions |
| @@ -159,19 +169,29 @@ | |
| 159 | return 1; |
| 160 | } |
| 161 | return 0; |
| 162 | } |
| 163 | |
| 164 | /* |
| 165 | ** Begin and end a nested transaction |
| 166 | */ |
| 167 | void db_begin_transaction(void){ |
| 168 | if( db.nBegin==0 ){ |
| 169 | db_multi_exec("BEGIN"); |
| 170 | sqlite3_commit_hook(g.db, db_verify_at_commit, 0); |
| 171 | db.nPriorChanges = sqlite3_total_changes(g.db); |
| 172 | db.doRollback = 0; |
| 173 | } |
| 174 | db.nBegin++; |
| 175 | } |
| 176 | void db_end_transaction(int rollbackFlag){ |
| 177 | if( g.db==0 ) return; |
| @@ -522,11 +542,11 @@ | |
| 522 | blob_append(pBlob, sqlite3_column_blob(pStmt->pStmt, N), |
| 523 | sqlite3_column_bytes(pStmt->pStmt, N)); |
| 524 | } |
| 525 | Blob db_column_text_as_blob(Stmt *pStmt, int N){ |
| 526 | Blob x; |
| 527 | blob_init(&x, sqlite3_column_text(pStmt->pStmt,N), |
| 528 | sqlite3_column_bytes(pStmt->pStmt,N)); |
| 529 | return x; |
| 530 | } |
| 531 | |
| 532 | /* |
| @@ -1783,11 +1803,12 @@ | |
| 1783 | } |
| 1784 | while( db.pAllStmt ){ |
| 1785 | db_finalize(db.pAllStmt); |
| 1786 | } |
| 1787 | if( db.nBegin && reportErrors ){ |
| 1788 | fossil_warning("Missed call to db_end_transaction(). Rolling back."); |
| 1789 | db_end_transaction(1); |
| 1790 | } |
| 1791 | pStmt = 0; |
| 1792 | g.dbIgnoreErrors++; /* Stop "database locked" warnings from PRAGMA optimize */ |
| 1793 | sqlite3_exec(g.db, "PRAGMA optimize", 0, 0, 0); |
| 1794 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -124,10 +124,12 @@ | |
| 124 | } aHook[5]; |
| 125 | char *azDeleteOnFail[3]; /* Files to delete on a failure */ |
| 126 | char *azBeforeCommit[5]; /* Commands to run prior to COMMIT */ |
| 127 | int nBeforeCommit; /* Number of entries in azBeforeCommit */ |
| 128 | int nPriorChanges; /* sqlite3_total_changes() at transaction start */ |
| 129 | const char *zStartFile; /* File in which transaction was started */ |
| 130 | int iStartLine; /* Line of zStartFile where transaction started */ |
| 131 | } db = {0, 0, 0, 0, 0, 0, }; |
| 132 | |
| 133 | /* |
| 134 | ** Arrange for the given file to be deleted on a failure. |
| 135 | */ |
| @@ -141,10 +143,18 @@ | |
| 143 | ** not in a transaction. |
| 144 | */ |
| 145 | int db_transaction_nesting_depth(void){ |
| 146 | return db.nBegin; |
| 147 | } |
| 148 | |
| 149 | /* |
| 150 | ** Return a pointer to a string that is the code point where the |
| 151 | ** current transaction was started. |
| 152 | */ |
| 153 | char *db_transaction_start_point(void){ |
| 154 | return mprintf("%s:%d", db.zStartFile, db.iStartLine); |
| 155 | } |
| 156 | |
| 157 | /* |
| 158 | ** This routine is called by the SQLite commit-hook mechanism |
| 159 | ** just prior to each commit. All this routine does is verify |
| 160 | ** that nBegin really is zero. That insures that transactions |
| @@ -159,19 +169,29 @@ | |
| 169 | return 1; |
| 170 | } |
| 171 | return 0; |
| 172 | } |
| 173 | |
| 174 | /* |
| 175 | ** Silently add the filename and line number as parameter to each |
| 176 | ** db_begin_transaction call. |
| 177 | */ |
| 178 | #if INTERFACE |
| 179 | #define db_begin_transaction() db_begin_transaction_real(__FILE__,__LINE__) |
| 180 | #endif |
| 181 | |
| 182 | /* |
| 183 | ** Begin and end a nested transaction |
| 184 | */ |
| 185 | void db_begin_transaction_real(const char *zStartFile, int iStartLine){ |
| 186 | if( db.nBegin==0 ){ |
| 187 | db_multi_exec("BEGIN"); |
| 188 | sqlite3_commit_hook(g.db, db_verify_at_commit, 0); |
| 189 | db.nPriorChanges = sqlite3_total_changes(g.db); |
| 190 | db.doRollback = 0; |
| 191 | db.zStartFile = zStartFile; |
| 192 | db.iStartLine = iStartLine; |
| 193 | } |
| 194 | db.nBegin++; |
| 195 | } |
| 196 | void db_end_transaction(int rollbackFlag){ |
| 197 | if( g.db==0 ) return; |
| @@ -522,11 +542,11 @@ | |
| 542 | blob_append(pBlob, sqlite3_column_blob(pStmt->pStmt, N), |
| 543 | sqlite3_column_bytes(pStmt->pStmt, N)); |
| 544 | } |
| 545 | Blob db_column_text_as_blob(Stmt *pStmt, int N){ |
| 546 | Blob x; |
| 547 | blob_init(&x, (char*)sqlite3_column_text(pStmt->pStmt,N), |
| 548 | sqlite3_column_bytes(pStmt->pStmt,N)); |
| 549 | return x; |
| 550 | } |
| 551 | |
| 552 | /* |
| @@ -1783,11 +1803,12 @@ | |
| 1803 | } |
| 1804 | while( db.pAllStmt ){ |
| 1805 | db_finalize(db.pAllStmt); |
| 1806 | } |
| 1807 | if( db.nBegin && reportErrors ){ |
| 1808 | fossil_warning("Transaction started at %s:%d never commits", |
| 1809 | db.zStartFile, db.iStartLine); |
| 1810 | db_end_transaction(1); |
| 1811 | } |
| 1812 | pStmt = 0; |
| 1813 | g.dbIgnoreErrors++; /* Stop "database locked" warnings from PRAGMA optimize */ |
| 1814 | sqlite3_exec(g.db, "PRAGMA optimize", 0, 0, 0); |
| 1815 |
+2
-1
| --- src/email.c | ||
| +++ src/email.c | ||
| @@ -2064,11 +2064,12 @@ | ||
| 2064 | 2064 | */ |
| 2065 | 2065 | void email_auto_exec(void){ |
| 2066 | 2066 | int iJulianDay; |
| 2067 | 2067 | if( g.db==0 ) return; |
| 2068 | 2068 | if( db_transaction_nesting_depth()!=0 ){ |
| 2069 | - fossil_warning("Called email_auto_exec() from within a transaction"); | |
| 2069 | + fossil_warning("Called email_auto_exec() from within transaction " | |
| 2070 | + "started at %z", db_transaction_start_point()); | |
| 2070 | 2071 | return; |
| 2071 | 2072 | } |
| 2072 | 2073 | db_begin_transaction(); |
| 2073 | 2074 | if( !email_tables_exist() ) goto autoexec_done; |
| 2074 | 2075 | if( !db_get_boolean("email-autoexec",0) ) goto autoexec_done; |
| 2075 | 2076 |
| --- src/email.c | |
| +++ src/email.c | |
| @@ -2064,11 +2064,12 @@ | |
| 2064 | */ |
| 2065 | void email_auto_exec(void){ |
| 2066 | int iJulianDay; |
| 2067 | if( g.db==0 ) return; |
| 2068 | if( db_transaction_nesting_depth()!=0 ){ |
| 2069 | fossil_warning("Called email_auto_exec() from within a transaction"); |
| 2070 | return; |
| 2071 | } |
| 2072 | db_begin_transaction(); |
| 2073 | if( !email_tables_exist() ) goto autoexec_done; |
| 2074 | if( !db_get_boolean("email-autoexec",0) ) goto autoexec_done; |
| 2075 |
| --- src/email.c | |
| +++ src/email.c | |
| @@ -2064,11 +2064,12 @@ | |
| 2064 | */ |
| 2065 | void email_auto_exec(void){ |
| 2066 | int iJulianDay; |
| 2067 | if( g.db==0 ) return; |
| 2068 | if( db_transaction_nesting_depth()!=0 ){ |
| 2069 | fossil_warning("Called email_auto_exec() from within transaction " |
| 2070 | "started at %z", db_transaction_start_point()); |
| 2071 | return; |
| 2072 | } |
| 2073 | db_begin_transaction(); |
| 2074 | if( !email_tables_exist() ) goto autoexec_done; |
| 2075 | if( !db_get_boolean("email-autoexec",0) ) goto autoexec_done; |
| 2076 |