SQLite
Check-in [f0843f885a]
Not logged in
Overview
SHA1 Hash:f0843f885ab3337f83fe3b304aab80bb7b5dd0a3
Date: 2012-11-27 21:22:54
User: drh
Comment:Add the SQLLOG capability to trunk.
Tags And Properties
Changes
hide diffs unified diffs patch

Changes to main.mk

253 $(TOP)/src/test_osinst.c \ 253 $(TOP)/src/test_osinst.c \ 254 $(TOP)/src/test_pcache.c \ 254 $(TOP)/src/test_pcache.c \ 255 $(TOP)/src/test_quota.c \ 255 $(TOP)/src/test_quota.c \ 256 $(TOP)/src/test_rtree.c \ 256 $(TOP)/src/test_rtree.c \ 257 $(TOP)/src/test_schema.c \ 257 $(TOP)/src/test_schema.c \ 258 $(TOP)/src/test_server.c \ 258 $(TOP)/src/test_server.c \ 259 $(TOP)/src/test_stat.c \ 259 $(TOP)/src/test_stat.c \ > 260 $(TOP)/src/test_sqllog.c \ 260 $(TOP)/src/test_superlock.c \ 261 $(TOP)/src/test_superlock.c \ 261 $(TOP)/src/test_syscall.c \ 262 $(TOP)/src/test_syscall.c \ 262 $(TOP)/src/test_tclvar.c \ 263 $(TOP)/src/test_tclvar.c \ 263 $(TOP)/src/test_thread.c \ 264 $(TOP)/src/test_thread.c \ 264 $(TOP)/src/test_vfs.c \ 265 $(TOP)/src/test_vfs.c \ 265 $(TOP)/src/test_wholenumber.c \ 266 $(TOP)/src/test_wholenumber.c \ 266 $(TOP)/src/test_wsd.c 267 $(TOP)/src/test_wsd.c

Changes to src/global.c

171 0, /* isMallocInit */ 171 0, /* isMallocInit */ 172 0, /* isPCacheInit */ 172 0, /* isPCacheInit */ 173 0, /* pInitMutex */ 173 0, /* pInitMutex */ 174 0, /* nRefInitMutex */ 174 0, /* nRefInitMutex */ 175 0, /* xLog */ 175 0, /* xLog */ 176 0, /* pLogArg */ 176 0, /* pLogArg */ 177 0, /* bLocaltimeFault */ 177 0, /* bLocaltimeFault */ > 178 #ifdef SQLITE_ENABLE_SQLLOG > 179 0, /* xSqllog */ > 180 0 /* pSqllogArg */ > 181 #endif 178 }; 182 }; 179 183 180 184 181 /* 185 /* 182 ** Hash table for global functions - functions common to all 186 ** Hash table for global functions - functions common to all 183 ** database connections. After initialization, this table is 187 ** database connections. After initialization, this table is 184 ** read-only. 188 ** read-only.

Changes to src/main.c

127 127 128 /* If SQLite is already completely initialized, then this call 128 /* If SQLite is already completely initialized, then this call 129 ** to sqlite3_initialize() should be a no-op. But the initialization 129 ** to sqlite3_initialize() should be a no-op. But the initialization 130 ** must be complete. So isInit must not be set until the very end 130 ** must be complete. So isInit must not be set until the very end 131 ** of this routine. 131 ** of this routine. 132 */ 132 */ 133 if( sqlite3GlobalConfig.isInit ) return SQLITE_OK; 133 if( sqlite3GlobalConfig.isInit ) return SQLITE_OK; > 134 > 135 #ifdef SQLITE_ENABLE_SQLLOG > 136 { > 137 extern void sqlite3_init_sqllog(void); > 138 sqlite3_init_sqllog(); > 139 } > 140 #endif 134 141 135 /* Make sure the mutex subsystem is initialized. If unable to 142 /* Make sure the mutex subsystem is initialized. If unable to 136 ** initialize the mutex subsystem, return early with the error. 143 ** initialize the mutex subsystem, return early with the error. 137 ** If the system is so sick that we are unable to allocate a mutex, 144 ** If the system is so sick that we are unable to allocate a mutex, 138 ** there is not much SQLite is going to be able to do. 145 ** there is not much SQLite is going to be able to do. 139 ** 146 ** 140 ** The mutex subsystem must take care of serializing its own 147 ** The mutex subsystem must take care of serializing its own ................................................................................................................................................................................ 475 break; 482 break; 476 } 483 } 477 484 478 case SQLITE_CONFIG_COVERING_INDEX_SCAN: { 485 case SQLITE_CONFIG_COVERING_INDEX_SCAN: { 479 sqlite3GlobalConfig.bUseCis = va_arg(ap, int); 486 sqlite3GlobalConfig.bUseCis = va_arg(ap, int); 480 break; 487 break; 481 } 488 } > 489 > 490 #ifdef SQLITE_ENABLE_SQLLOG > 491 case SQLITE_CONFIG_SQLLOG: { > 492 typedef void(*SQLLOGFUNC_t)(void*, sqlite3*, const char*, int); > 493 sqlite3GlobalConfig.xSqllog = va_arg(ap, SQLLOGFUNC_t); > 494 sqlite3GlobalConfig.pSqllogArg = va_arg(ap, void *); > 495 break; > 496 } > 497 #endif 482 498 483 default: { 499 default: { 484 rc = SQLITE_ERROR; 500 rc = SQLITE_ERROR; 485 break; 501 break; 486 } 502 } 487 } 503 } 488 va_end(ap); 504 va_end(ap); ................................................................................................................................................................................ 814 */ 830 */ 815 if( !forceZombie && connectionIsBusy(db) ){ 831 if( !forceZombie && connectionIsBusy(db) ){ 816 sqlite3Error(db, SQLITE_BUSY, "unable to close due to unfinalized " 832 sqlite3Error(db, SQLITE_BUSY, "unable to close due to unfinalized " 817 "statements or unfinished backups"); 833 "statements or unfinished backups"); 818 sqlite3_mutex_leave(db->mutex); 834 sqlite3_mutex_leave(db->mutex); 819 return SQLITE_BUSY; 835 return SQLITE_BUSY; 820 } 836 } > 837 > 838 #ifdef SQLITE_ENABLE_SQLLOG > 839 if( sqlite3GlobalConfig.xSqllog ){ > 840 /* Closing the handle. Fourth parameter is passed the value 2. */ > 841 sqlite3GlobalConfig.xSqllog(sqlite3GlobalConfig.pSqllogArg, db, 0, 2); > 842 } > 843 #endif 821 844 822 /* Convert the connection into a zombie and then close it. 845 /* Convert the connection into a zombie and then close it. 823 */ 846 */ 824 db->magic = SQLITE_MAGIC_ZOMBIE; 847 db->magic = SQLITE_MAGIC_ZOMBIE; 825 sqlite3LeaveMutexAndCloseZombie(db); 848 sqlite3LeaveMutexAndCloseZombie(db); 826 return SQLITE_OK; 849 return SQLITE_OK; 827 } 850 } ................................................................................................................................................................................ 2447 if( rc==SQLITE_NOMEM ){ 2470 if( rc==SQLITE_NOMEM ){ 2448 sqlite3_close(db); 2471 sqlite3_close(db); 2449 db = 0; 2472 db = 0; 2450 }else if( rc!=SQLITE_OK ){ 2473 }else if( rc!=SQLITE_OK ){ 2451 db->magic = SQLITE_MAGIC_SICK; 2474 db->magic = SQLITE_MAGIC_SICK; 2452 } 2475 } 2453 *ppDb = db; 2476 *ppDb = db; > 2477 #ifdef SQLITE_ENABLE_SQLLOG > 2478 if( sqlite3GlobalConfig.xSqllog ){ > 2479 /* Opening a db handle. Fourth parameter is passed 0. */ > 2480 void *pArg = sqlite3GlobalConfig.pSqllogArg; > 2481 sqlite3GlobalConfig.xSqllog(pArg, db, zFilename, 0); > 2482 } > 2483 #endif 2454 return sqlite3ApiExit(0, rc); 2484 return sqlite3ApiExit(0, rc); 2455 } 2485 } 2456 2486 2457 /* 2487 /* 2458 ** Open a new database handle. 2488 ** Open a new database handle. 2459 */ 2489 */ 2460 int sqlite3_open( 2490 int sqlite3_open(

Changes to src/sqlite.h.in

1589 ** without change even with newer versions of SQLite. 1589 ** without change even with newer versions of SQLite. 1590 ** 1590 ** 1591 ** [[SQLITE_CONFIG_PCACHE]] [[SQLITE_CONFIG_GETPCACHE]] 1591 ** [[SQLITE_CONFIG_PCACHE]] [[SQLITE_CONFIG_GETPCACHE]] 1592 ** <dt>SQLITE_CONFIG_PCACHE and SQLITE_CONFIG_GETPCACHE 1592 ** <dt>SQLITE_CONFIG_PCACHE and SQLITE_CONFIG_GETPCACHE 1593 ** <dd> These options are obsolete and should not be used by new code. 1593 ** <dd> These options are obsolete and should not be used by new code. 1594 ** They are retained for backwards compatibility but are now no-ops. 1594 ** They are retained for backwards compatibility but are now no-ops. 1595 ** </dl> 1595 ** </dl> > 1596 ** > 1597 ** [[SQLITE_CONFIG_SQLLOG]] > 1598 ** <dt>SQLITE_CONFIG_SQLLOG > 1599 ** <dd>This option is only available if sqlite is compiled with the > 1600 ** SQLITE_ENABLE_SQLLOG pre-processor macro defined. The first argument should > 1601 ** be a pointer to a function of type void(*)(void*,sqlite3*,const char*, int). > 1602 ** The second should be of type (void*). The callback is invoked by the library > 1603 ** in three separate circumstances, identified by the value passed as the > 1604 ** fourth parameter. If the fourth parameter is 0, then the database connection > 1605 ** passed as the second argument has just been opened. The third argument > 1606 ** points to a buffer containing the name of the main database file. If the > 1607 ** fourth parameter is 1, then the SQL statement that the third parameter > 1608 ** points to has just been executed. Or, if the fourth parameter is 2, then > 1609 ** the connection being passed as the second parameter is being closed. The > 1610 ** third parameter is passed NULL In this case. > 1611 ** </dl> 1596 */ 1612 */ 1597 #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ 1613 #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ 1598 #define SQLITE_CONFIG_MULTITHREAD 2 /* nil */ 1614 #define SQLITE_CONFIG_MULTITHREAD 2 /* nil */ 1599 #define SQLITE_CONFIG_SERIALIZED 3 /* nil */ 1615 #define SQLITE_CONFIG_SERIALIZED 3 /* nil */ 1600 #define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */ 1616 #define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */ 1601 #define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */ 1617 #define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */ 1602 #define SQLITE_CONFIG_SCRATCH 6 /* void*, int sz, int N */ 1618 #define SQLITE_CONFIG_SCRATCH 6 /* void*, int sz, int N */ ................................................................................................................................................................................ 1610 #define SQLITE_CONFIG_PCACHE 14 /* no-op */ 1626 #define SQLITE_CONFIG_PCACHE 14 /* no-op */ 1611 #define SQLITE_CONFIG_GETPCACHE 15 /* no-op */ 1627 #define SQLITE_CONFIG_GETPCACHE 15 /* no-op */ 1612 #define SQLITE_CONFIG_LOG 16 /* xFunc, void* */ 1628 #define SQLITE_CONFIG_LOG 16 /* xFunc, void* */ 1613 #define SQLITE_CONFIG_URI 17 /* int */ 1629 #define SQLITE_CONFIG_URI 17 /* int */ 1614 #define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */ 1630 #define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */ 1615 #define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */ 1631 #define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */ 1616 #define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */ 1632 #define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */ > 1633 #define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */ 1617 1634 1618 /* 1635 /* 1619 ** CAPI3REF: Database Connection Configuration Options 1636 ** CAPI3REF: Database Connection Configuration Options 1620 ** 1637 ** 1621 ** These constants are the available integer configuration options that 1638 ** These constants are the available integer configuration options that 1622 ** can be passed as the second argument to the [sqlite3_db_config()] interface. 1639 ** can be passed as the second argument to the [sqlite3_db_config()] interface. 1623 ** 1640 **

Changes to src/sqliteInt.h

2511 int isMallocInit; /* True after malloc is initialized */ 2511 int isMallocInit; /* True after malloc is initialized */ 2512 int isPCacheInit; /* True after malloc is initialized */ 2512 int isPCacheInit; /* True after malloc is initialized */ 2513 sqlite3_mutex *pInitMutex; /* Mutex used by sqlite3_initialize() */ 2513 sqlite3_mutex *pInitMutex; /* Mutex used by sqlite3_initialize() */ 2514 int nRefInitMutex; /* Number of users of pInitMutex */ 2514 int nRefInitMutex; /* Number of users of pInitMutex */ 2515 void (*xLog)(void*,int,const char*); /* Function for logging */ 2515 void (*xLog)(void*,int,const char*); /* Function for logging */ 2516 void *pLogArg; /* First argument to xLog() */ 2516 void *pLogArg; /* First argument to xLog() */ 2517 int bLocaltimeFault; /* True to fail localtime() calls */ 2517 int bLocaltimeFault; /* True to fail localtime() calls */ > 2518 #ifdef SQLITE_ENABLE_SQLLOG > 2519 void(*xSqllog)(void*,sqlite3*,const char*, int); > 2520 void *pSqllogArg; > 2521 #endif 2518 }; 2522 }; 2519 2523 2520 /* 2524 /* 2521 ** Context pointer passed down through the tree-walk. 2525 ** Context pointer passed down through the tree-walk. 2522 */ 2526 */ 2523 struct Walker { 2527 struct Walker { 2524 int (*xExprCallback)(Walker*, Expr*); /* Callback for expressions */ 2528 int (*xExprCallback)(Walker*, Expr*); /* Callback for expressions */

Added src/test_sqllog.c

> 1 /* > 2 ** 2012 November 26 > 3 ** > 4 ** The author disclaims copyright to this source code. In place of > 5 ** a legal notice, here is a blessing: > 6 ** > 7 ** May you do good and not evil. > 8 ** May you find forgiveness for yourself and forgive others. > 9 ** May you share freely, never taking more than you give. > 10 ** > 11 ************************************************************************* > 12 ** > 13 ** OVERVIEW > 14 ** > 15 ** This file contains experimental code used to record data from live > 16 ** SQLite applications that may be useful for offline analysis. Specifically: > 17 ** > 18 ** 1) The initial contents of all database files opened by the > 19 ** application, and > 20 ** > 21 ** 2) All SQL statements executed by the application. > 22 ** > 23 ** USAGE > 24 ** > 25 ** To use this module, SQLite must be compiled with the SQLITE_ENABLE_SQLLOG > 26 ** pre-processor symbol defined and this file linked into the application > 27 ** somehow. > 28 ** > 29 ** At runtime, logging is enabled by setting environment variable > 30 ** SQLITE_SQLLOG_DIR to the name of a directory in which to store logged > 31 ** data. The directory must already exist. > 32 ** > 33 ** Usually, if the application opens the same database file more than once > 34 ** (either by attaching it or by using more than one database handle), only > 35 ** a single copy is made. This behaviour may be overridden (so that a > 36 ** separate copy is taken each time the database file is opened or attached) > 37 ** by setting the environment variable SQLITE_SQLLOG_REUSE_FILES to 0. > 38 ** > 39 ** OUTPUT: > 40 ** > 41 ** The SQLITE_SQLLOG_DIR is populated with three types of files: > 42 ** > 43 ** sqllog_N.db - Copies of database files. N may be any integer. > 44 ** > 45 ** sqllog_N.sql - A list of SQL statements executed by a single > 46 ** connection. N may be any integer. > 47 ** > 48 ** sqllog.idx - An index mapping from integer N to a database > 49 ** file name - indicating the full path of the > 50 ** database from which sqllog_N.db was copied. > 51 ** > 52 ** ERROR HANDLING: > 53 ** > 54 ** This module attempts to make a best effort to continue logging if an > 55 ** IO or other error is encountered. For example, if a log file cannot > 56 ** be opened logs are not collected for that connection, but other > 57 ** logging proceeds as expected. Errors are logged by calling sqlite3_log(). > 58 */ > 59 > 60 #include "sqlite3.h" > 61 #include "stdio.h" > 62 #include "stdlib.h" > 63 #include "string.h" > 64 #include "assert.h" > 65 > 66 #include "sys/types.h" > 67 #include "unistd.h" > 68 static int getProcessId(void){ > 69 #if SQLITE_OS_WIN > 70 return (int)_getpid(); > 71 #else > 72 return (int)getpid(); > 73 #endif > 74 } > 75 > 76 > 77 #define ENVIRONMENT_VARIABLE1_NAME "SQLITE_SQLLOG_DIR" > 78 #define ENVIRONMENT_VARIABLE2_NAME "SQLITE_SQLLOG_REUSE_FILES" > 79 > 80 /* Assume that all database and database file names are shorted than this. */ > 81 #define SQLLOG_NAMESZ 512 > 82 > 83 /* Maximum number of simultaneous database connections the process may > 84 ** open (if any more are opened an error is logged using sqlite3_log() > 85 ** and processing is halted). > 86 */ > 87 #define MAX_CONNECTIONS 256 > 88 > 89 struct SLConn { > 90 int isErr; /* True if an error has occurred */ > 91 sqlite3 *db; /* Connection handle */ > 92 int iLog; /* First integer value used in file names */ > 93 FILE *fd; /* File descriptor for log file */ > 94 }; > 95 > 96 struct SLGlobal { > 97 /* Protected by MUTEX_STATIC_MASTER */ > 98 sqlite3_mutex *mutex; /* Recursive mutex */ > 99 int nConn; /* Size of aConn[] array */ > 100 > 101 /* Protected by SLGlobal.mutex */ > 102 int bReuse; /* True to avoid extra copies of db files */ > 103 char zPrefix[SQLLOG_NAMESZ]; /* Prefix for all created files */ > 104 char zIdx[SQLLOG_NAMESZ]; /* Full path to *.idx file */ > 105 int iNextLog; /* Used to allocate file names */ > 106 int iNextDb; /* Used to allocate database file names */ > 107 int bRec; /* True if testSqllog() is called rec. */ > 108 int iClock; /* Clock value */ > 109 struct SLConn aConn[MAX_CONNECTIONS]; > 110 } sqllogglobal; > 111 > 112 /* > 113 ** Return true if c is an ASCII whitespace character. > 114 */ > 115 static int sqllog_isspace(char c){ > 116 return (c==' ' || c=='\t' || c=='\n' || c=='\v' || c=='\f' || c=='\r'); > 117 } > 118 > 119 /* > 120 ** The first argument points to a nul-terminated string containing an SQL > 121 ** command. Before returning, this function sets *pz to point to the start > 122 ** of the first token in this command, and *pn to the number of bytes in > 123 ** the token. This is used to check if the SQL command is an "ATTACH" or > 124 ** not. > 125 */ > 126 static void sqllogTokenize(const char *z, const char **pz, int *pn){ > 127 const char *p = z; > 128 int n; > 129 > 130 /* Skip past any whitespace */ > 131 while( sqllog_isspace(*p) ){ > 132 p++; > 133 } > 134 > 135 /* Figure out how long the first token is */ > 136 *pz = p; > 137 n = 0; > 138 while( (p[n]>='a' && p[n]<='z') || (p[n]>='A' && p[n]<='Z') ) n++; > 139 *pn = n; > 140 } > 141 > 142 /* > 143 ** Check if the logs directory already contains a copy of database file > 144 ** zFile. If so, return a pointer to the full path of the copy. Otherwise, > 145 ** return NULL. > 146 ** > 147 ** If a non-NULL value is returned, then the caller must arrange to > 148 ** eventually free it using sqlite3_free(). > 149 */ > 150 static char *sqllogFindFile(const char *zFile){ > 151 char *zRet = 0; > 152 FILE *fd = 0; > 153 > 154 /* Open the index file for reading */ > 155 fd = fopen(sqllogglobal.zIdx, "r"); > 156 if( fd==0 ){ > 157 sqlite3_log(SQLITE_IOERR, "sqllogFindFile(): error in fopen()"); > 158 return 0; > 159 } > 160 > 161 /* Loop through each entry in the index file. If zFile is not NULL and the > 162 ** entry is a match, then set zRet to point to the filename of the existing > 163 ** copy and break out of the loop. */ > 164 while( feof(fd)==0 ){ > 165 char zLine[SQLLOG_NAMESZ*2+5]; > 166 if( fgets(zLine, sizeof(zLine), fd) ){ > 167 int n; > 168 char *z; > 169 > 170 zLine[sizeof(zLine)-1] = '\0'; > 171 z = zLine; > 172 while( *z>='0' && *z<='9' ) z++; > 173 while( *z==' ' ) z++; > 174 > 175 n = strlen(z); > 176 while( n>0 && sqllog_isspace(z[n-1]) ) n--; > 177 > 178 if( n==strlen(zFile) && 0==memcmp(zFile, z, n) ){ > 179 char zBuf[16]; > 180 memset(zBuf, 0, sizeof(zBuf)); > 181 z = zLine; > 182 while( *z>='0' && *z<='9' ){ > 183 zBuf[z-zLine] = *z; > 184 z++; > 185 } > 186 zRet = sqlite3_mprintf("%s_%s.db", sqllogglobal.zPrefix, zBuf); > 187 break; > 188 } > 189 } > 190 } > 191 > 192 if( ferror(fd) ){ > 193 sqlite3_log(SQLITE_IOERR, "sqllogFindFile(): error reading index file"); > 194 } > 195 > 196 fclose(fd); > 197 return zRet; > 198 } > 199 > 200 static int sqllogFindAttached( > 201 struct SLConn *p, /* Database connection */ > 202 const char *zSearch, /* Name to search for (or NULL) */ > 203 char *zName, /* OUT: Name of attached database */ > 204 char *zFile /* OUT: Name of attached file */ > 205 ){ > 206 sqlite3_stmt *pStmt; > 207 int rc; > 208 > 209 /* The "PRAGMA database_list" command returns a list of databases in the > 210 ** order that they were attached. So a newly attached database is > 211 ** described by the last row returned. */ > 212 assert( sqllogglobal.bRec==0 ); > 213 sqllogglobal.bRec = 1; > 214 rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0); > 215 if( rc==SQLITE_OK ){ > 216 while( SQLITE_ROW==sqlite3_step(pStmt) ){ > 217 const char *zVal1; int nVal1; > 218 const char *zVal2; int nVal2; > 219 > 220 zVal1 = (const char*)sqlite3_column_text(pStmt, 1); > 221 nVal1 = sqlite3_column_bytes(pStmt, 1); > 222 memcpy(zName, zVal1, nVal1+1); > 223 > 224 zVal2 = (const char*)sqlite3_column_text(pStmt, 2); > 225 nVal2 = sqlite3_column_bytes(pStmt, 2); > 226 memcpy(zFile, zVal2, nVal2+1); > 227 > 228 if( zSearch && strlen(zSearch)==nVal1 > 229 && 0==sqlite3_strnicmp(zSearch, zVal1, nVal1) > 230 ){ > 231 break; > 232 } > 233 } > 234 rc = sqlite3_finalize(pStmt); > 235 } > 236 sqllogglobal.bRec = 0; > 237 > 238 if( rc!=SQLITE_OK ){ > 239 sqlite3_log(rc, "sqllogFindAttached(): error in \"PRAGMA database_list\""); > 240 } > 241 return rc; > 242 } > 243 > 244 > 245 /* > 246 ** Parameter zSearch is the name of a database attached to the database > 247 ** connection associated with the first argument. This function creates > 248 ** a backup of this database in the logs directory. > 249 ** > 250 ** The name used for the backup file is automatically generated. Call > 251 ** it zFile. > 252 ** > 253 ** If the bLog parameter is true, then a statement of the following form > 254 ** is written to the log file associated with *p: > 255 ** > 256 ** ATTACH 'zFile' AS 'zName'; > 257 ** > 258 ** Otherwise, if bLog is false, a comment is added to the log file: > 259 ** > 260 ** -- Main database file is 'zFile' > 261 ** > 262 ** The SLGlobal.mutex mutex is always held when this function is called. > 263 */ > 264 static void sqllogCopydb(struct SLConn *p, const char *zSearch, int bLog){ > 265 char zName[SQLLOG_NAMESZ]; /* Attached database name */ > 266 char zFile[SQLLOG_NAMESZ]; /* Database file name */ > 267 char *zFree; > 268 char *zInit = 0; > 269 int rc; > 270 > 271 rc = sqllogFindAttached(p, zSearch, zName, zFile); > 272 if( rc!=SQLITE_OK ) return; > 273 > 274 if( zFile[0]=='\0' ){ > 275 zInit = sqlite3_mprintf(""); > 276 }else{ > 277 if( sqllogglobal.bReuse ){ > 278 zInit = sqllogFindFile(zFile); > 279 }else{ > 280 zInit = 0; > 281 } > 282 if( zInit==0 ){ > 283 int rc; > 284 sqlite3 *copy = 0; > 285 int iDb; > 286 > 287 /* Generate a file-name to use for the copy of this database */ > 288 iDb = sqllogglobal.iNextDb++; > 289 zInit = sqlite3_mprintf("%s_%d.db", sqllogglobal.zPrefix, iDb); > 290 > 291 /* Create the backup */ > 292 assert( sqllogglobal.bRec==0 ); > 293 sqllogglobal.bRec = 1; > 294 rc = sqlite3_open(zInit, &copy); > 295 if( rc==SQLITE_OK ){ > 296 sqlite3_backup *pBak; > 297 sqlite3_exec(copy, "PRAGMA synchronous = 0", 0, 0, 0); > 298 pBak = sqlite3_backup_init(copy, "main", p->db, zName); > 299 if( pBak ){ > 300 sqlite3_backup_step(pBak, -1); > 301 rc = sqlite3_backup_finish(pBak); > 302 }else{ > 303 rc = sqlite3_errcode(copy); > 304 } > 305 sqlite3_close(copy); > 306 } > 307 sqllogglobal.bRec = 0; > 308 > 309 if( rc==SQLITE_OK ){ > 310 /* Write an entry into the database index file */ > 311 FILE *fd = fopen(sqllogglobal.zIdx, "a"); > 312 if( fd ){ > 313 fprintf(fd, "%d %s\n", iDb, zFile); > 314 fclose(fd); > 315 } > 316 }else{ > 317 sqlite3_log(rc, "sqllogCopydb(): error backing up database"); > 318 } > 319 } > 320 } > 321 > 322 if( bLog ){ > 323 zFree = sqlite3_mprintf("ATTACH '%q' AS '%q'; -- clock=%d\n", > 324 zInit, zName, sqllogglobal.iClock++ > 325 ); > 326 }else{ > 327 zFree = sqlite3_mprintf("-- Main database is '%q'\n", zInit); > 328 } > 329 fprintf(p->fd, "%s", zFree); > 330 sqlite3_free(zFree); > 331 > 332 sqlite3_free(zInit); > 333 } > 334 > 335 /* > 336 ** If it is not already open, open the log file for connection *p. > 337 ** > 338 ** The SLGlobal.mutex mutex is always held when this function is called. > 339 */ > 340 static void sqllogOpenlog(struct SLConn *p){ > 341 /* If the log file has not yet been opened, open it now. */ > 342 if( p->fd==0 ){ > 343 char *zLog; > 344 > 345 /* If it is still NULL, have global.zPrefix point to a copy of > 346 ** environment variable $ENVIRONMENT_VARIABLE1_NAME. */ > 347 if( sqllogglobal.zPrefix[0]==0 ){ > 348 FILE *fd; > 349 char *zVar = getenv(ENVIRONMENT_VARIABLE1_NAME); > 350 if( zVar==0 || strlen(zVar)+10>=(sizeof(sqllogglobal.zPrefix)) ) return; > 351 sprintf(sqllogglobal.zPrefix, "%s/sqllog_%d", zVar, getProcessId()); > 352 sprintf(sqllogglobal.zIdx, "%s.idx", sqllogglobal.zPrefix); > 353 if( getenv(ENVIRONMENT_VARIABLE2_NAME) ){ > 354 sqllogglobal.bReuse = atoi(getenv(ENVIRONMENT_VARIABLE2_NAME)); > 355 } > 356 fd = fopen(sqllogglobal.zIdx, "w"); > 357 if( fd ) fclose(fd); > 358 } > 359 > 360 /* Open the log file */ > 361 zLog = sqlite3_mprintf("%s_%d.sql", sqllogglobal.zPrefix, p->iLog); > 362 p->fd = fopen(zLog, "w"); > 363 sqlite3_free(zLog); > 364 if( p->fd==0 ){ > 365 sqlite3_log(SQLITE_IOERR, "sqllogOpenlog(): Failed to open log file"); > 366 } > 367 } > 368 } > 369 > 370 /* > 371 ** This function is called if the SQLLOG callback is invoked to report > 372 ** execution of an SQL statement. Parameter p is the connection the statement > 373 ** was executed by and parameter zSql is the text of the statement itself. > 374 */ > 375 static void testSqllogStmt(struct SLConn *p, const char *zSql){ > 376 const char *zFirst; /* Pointer to first token in zSql */ > 377 int nFirst; /* Size of token zFirst in bytes */ > 378 > 379 sqllogTokenize(zSql, &zFirst, &nFirst); > 380 if( nFirst!=6 || 0!=sqlite3_strnicmp("ATTACH", zFirst, 6) ){ > 381 /* Not an ATTACH statement. Write this directly to the log. */ > 382 fprintf(p->fd, "%s; -- clock=%d\n", zSql, sqllogglobal.iClock++); > 383 }else{ > 384 /* This is an ATTACH statement. Copy the database. */ > 385 sqllogCopydb(p, 0, 1); > 386 } > 387 } > 388 > 389 /* > 390 ** The SQLITE_CONFIG_SQLLOG callback registered by sqlite3_init_sqllog(). > 391 */ > 392 static void testSqllog(void *pCtx, sqlite3 *db, const char *zSql, int eType){ > 393 struct SLConn *p; > 394 sqlite3_mutex *master = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); > 395 > 396 assert( eType==0 || eType==1 || eType==2 ); > 397 assert( (eType==2)==(zSql==0) ); > 398 > 399 /* This is a database open command. */ > 400 if( eType==0 ){ > 401 sqlite3_mutex_enter(master); > 402 if( sqllogglobal.mutex==0 ){ > 403 sqllogglobal.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_RECURSIVE); > 404 } > 405 p = &sqllogglobal.aConn[sqllogglobal.nConn++]; > 406 p->fd = 0; > 407 p->db = db; > 408 p->iLog = sqllogglobal.iNextLog++; > 409 sqlite3_mutex_leave(master); > 410 > 411 /* Open the log and take a copy of the main database file */ > 412 sqlite3_mutex_enter(sqllogglobal.mutex); > 413 if( sqllogglobal.bRec==0 ){ > 414 sqllogOpenlog(p); > 415 if( p->fd ) sqllogCopydb(p, "main", 0); > 416 } > 417 sqlite3_mutex_leave(sqllogglobal.mutex); > 418 } > 419 > 420 else{ > 421 > 422 int i; > 423 for(i=0; i<sqllogglobal.nConn; i++){ > 424 p = &sqllogglobal.aConn[i]; > 425 if( p->db==db ) break; > 426 } > 427 if( i==sqllogglobal.nConn ) return; > 428 > 429 /* A database handle close command */ > 430 if( eType==2 ){ > 431 sqlite3_mutex_enter(master); > 432 if( p->fd ) fclose(p->fd); > 433 p->db = 0; > 434 p->fd = 0; > 435 > 436 sqllogglobal.nConn--; > 437 if( sqllogglobal.nConn==0 ){ > 438 sqlite3_mutex_free(sqllogglobal.mutex); > 439 sqllogglobal.mutex = 0; > 440 }else{ > 441 int nShift = &sqllogglobal.aConn[sqllogglobal.nConn] - p; > 442 if( nShift>0 ){ > 443 memmove(p, &p[1], nShift*sizeof(struct SLConn)); > 444 } > 445 } > 446 sqlite3_mutex_leave(master); > 447 > 448 /* An ordinary SQL command. */ > 449 }else if( p->fd ){ > 450 sqlite3_mutex_enter(sqllogglobal.mutex); > 451 if( sqllogglobal.bRec==0 ){ > 452 testSqllogStmt(p, zSql); > 453 } > 454 sqlite3_mutex_leave(sqllogglobal.mutex); > 455 } > 456 } > 457 } > 458 > 459 /* > 460 ** This function is called either before sqlite3_initialized() or by it. > 461 ** It checks if the SQLITE_SQLLOG_DIR variable is defined, and if so > 462 ** registers an SQLITE_CONFIG_SQLLOG callback to record the applications > 463 ** database activity. > 464 */ > 465 void sqlite3_init_sqllog(void){ > 466 if( getenv(ENVIRONMENT_VARIABLE1_NAME) ){ > 467 if( SQLITE_OK==sqlite3_config(SQLITE_CONFIG_SQLLOG, testSqllog, 0) ){ > 468 memset(&sqllogglobal, 0, sizeof(sqllogglobal)); > 469 sqllogglobal.bReuse = 1; > 470 } > 471 } > 472 }

Changes to src/vdbeaux.c

49 49 50 /* 50 /* 51 ** Remember the SQL string for a prepared statement. 51 ** Remember the SQL string for a prepared statement. 52 */ 52 */ 53 void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, int isPrepareV2){ 53 void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, int isPrepareV2){ 54 assert( isPrepareV2==1 || isPrepareV2==0 ); 54 assert( isPrepareV2==1 || isPrepareV2==0 ); 55 if( p==0 ) return; 55 if( p==0 ) return; 56 #ifdef SQLITE_OMIT_TRACE | 56 #if defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_ENABLE_SQLLOG) 57 if( !isPrepareV2 ) return; 57 if( !isPrepareV2 ) return; 58 #endif 58 #endif 59 assert( p->zSql==0 ); 59 assert( p->zSql==0 ); 60 p->zSql = sqlite3DbStrNDup(p->db, z, n); 60 p->zSql = sqlite3DbStrNDup(p->db, z, n); 61 p->isPrepareV2 = (u8)isPrepareV2; 61 p->isPrepareV2 = (u8)isPrepareV2; 62 } 62 } 63 63 ................................................................................................................................................................................ 2322 db->errCode = rc; 2322 db->errCode = rc; 2323 }else{ 2323 }else{ 2324 sqlite3Error(db, rc, 0); 2324 sqlite3Error(db, rc, 0); 2325 } 2325 } 2326 return rc; 2326 return rc; 2327 } 2327 } 2328 2328 > 2329 #ifdef SQLITE_ENABLE_SQLLOG > 2330 /* > 2331 ** If an SQLITE_CONFIG_SQLLOG hook is registered and the VM has been run, > 2332 ** invoke it. > 2333 */ > 2334 static void vdbeInvokeSqllog(Vdbe *v){ > 2335 if( sqlite3GlobalConfig.xSqllog && v->rc==SQLITE_OK && v->zSql && v->pc>=0 ){ > 2336 char *zExpanded = sqlite3VdbeExpandSql(v, v->zSql); > 2337 assert( v->db->init.busy==0 ); > 2338 if( zExpanded ){ > 2339 sqlite3GlobalConfig.xSqllog( > 2340 sqlite3GlobalConfig.pSqllogArg, v->db, zExpanded, 1 > 2341 ); > 2342 sqlite3DbFree(v->db, zExpanded); > 2343 } > 2344 } > 2345 } > 2346 #else > 2347 # define vdbeInvokeSqllog(x) > 2348 #endif > 2349 2329 /* 2350 /* 2330 ** Clean up a VDBE after execution but do not delete the VDBE just yet. 2351 ** Clean up a VDBE after execution but do not delete the VDBE just yet. 2331 ** Write any error messages into *pzErrMsg. Return the result code. 2352 ** Write any error messages into *pzErrMsg. Return the result code. 2332 ** 2353 ** 2333 ** After this routine is run, the VDBE should be ready to be executed 2354 ** After this routine is run, the VDBE should be ready to be executed 2334 ** again. 2355 ** again. 2335 ** 2356 ** ................................................................................................................................................................................ 2349 2370 2350 /* If the VDBE has be run even partially, then transfer the error code 2371 /* If the VDBE has be run even partially, then transfer the error code 2351 ** and error message from the VDBE into the main database structure. But 2372 ** and error message from the VDBE into the main database structure. But 2352 ** if the VDBE has just been set to run but has not actually executed any 2373 ** if the VDBE has just been set to run but has not actually executed any 2353 ** instructions yet, leave the main database error information unchanged. 2374 ** instructions yet, leave the main database error information unchanged. 2354 */ 2375 */ 2355 if( p->pc>=0 ){ 2376 if( p->pc>=0 ){ > 2377 vdbeInvokeSqllog(p); 2356 sqlite3VdbeTransferError(p); 2378 sqlite3VdbeTransferError(p); 2357 sqlite3DbFree(db, p->zErrMsg); 2379 sqlite3DbFree(db, p->zErrMsg); 2358 p->zErrMsg = 0; 2380 p->zErrMsg = 0; 2359 if( p->runOnlyOnce ) p->expired = 1; 2381 if( p->runOnlyOnce ) p->expired = 1; 2360 }else if( p->rc && p->expired ){ 2382 }else if( p->rc && p->expired ){ 2361 /* The expired flag was set on the VDBE before the first call 2383 /* The expired flag was set on the VDBE before the first call 2362 ** to sqlite3_step(). For consistency (since sqlite3_step() was 2384 ** to sqlite3_step(). For consistency (since sqlite3_step() was