/ Check-in [cab8126b]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add support for the SQLITE_SQLLOG_CONDITIONAL environment variable to the logging code in test_sqllog.c. When defined, logging is only performed if the "<database>-sqllog" file is present in the file system when the main database is opened.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: cab8126be9f63dd596719b12704ba77c128282bc
User & Date: dan 2015-11-12 20:12:51
Context
2015-11-12
21:42
Add a space before each line of error output in the test scripts so that all errors can be conveniently located in logs by doing "grep '^ '". check-in: 9d532fb5 user: drh tags: trunk
20:12
Add support for the SQLITE_SQLLOG_CONDITIONAL environment variable to the logging code in test_sqllog.c. When defined, logging is only performed if the "<database>-sqllog" file is present in the file system when the main database is opened. check-in: cab8126b user: dan tags: trunk
16:44
Enhance the "PRAGMA cache_spill" statement to accept an integer argument which is the threshold at which spilling will begin. check-in: f79d264d user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/main.c.

   216    216     ** methods.  The sqlite3_pcache_methods.xInit() all is embedded in the
   217    217     ** call to sqlite3PcacheInitialize().
   218    218     */
   219    219     sqlite3_mutex_enter(sqlite3GlobalConfig.pInitMutex);
   220    220     if( sqlite3GlobalConfig.isInit==0 && sqlite3GlobalConfig.inProgress==0 ){
   221    221       FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
   222    222       sqlite3GlobalConfig.inProgress = 1;
          223  +#ifdef SQLITE_INIT_SQLLOG
          224  +    {
          225  +      extern void SQLITE_INIT_SQLLOG(void);
          226  +      SQLITE_INIT_SQLLOG();
          227  +    }
          228  +#endif
   223    229       memset(pHash, 0, sizeof(sqlite3GlobalFunctions));
   224    230       sqlite3RegisterGlobalFunctions();
   225    231       if( sqlite3GlobalConfig.isPCacheInit==0 ){
   226    232         rc = sqlite3PcacheInitialize();
   227    233       }
   228    234       if( rc==SQLITE_OK ){
   229    235         sqlite3GlobalConfig.isPCacheInit = 1;

Changes to src/sqliteInt.h.

   523    523   ** number of pages.  A negative number N translations means that a buffer
   524    524   ** of -1024*N bytes is allocated and used for as many pages as it will hold.
   525    525   */
   526    526   #ifndef SQLITE_DEFAULT_PCACHE_INITSZ
   527    527   # define SQLITE_DEFAULT_PCACHE_INITSZ 100
   528    528   #endif
   529    529   
          530  +/* 
          531  +** If SQLITE_INIT_SQLLOG is defined, then SQLITE_ENABLE_SQLLOG is 
          532  +** automatically defined as well.
          533  +*/
          534  +#if defined(SQLITE_INIT_SQLLOG) && !defined(SQLITE_ENABLE_SQLLOG)
          535  +# define SQLITE_ENABLE_SQLLOG 1
          536  +#endif
          537  +
   530    538   
   531    539   /*
   532    540   ** GCC does not define the offsetof() macro so we'll have to do it
   533    541   ** ourselves.
   534    542   */
   535    543   #ifndef offsetof
   536    544   #define offsetof(STRUCTURE,FIELD) ((int)((char*)&((STRUCTURE*)0)->FIELD))

Changes to src/test1.c.

  2222   2222     }
  2223   2223     if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
  2224   2224     sqlite3_stmt_scanstatus_reset(pStmt);
  2225   2225     return TCL_OK;
  2226   2226   }
  2227   2227   #endif
  2228   2228   
         2229  +#ifdef SQLITE_ENABLE_SQLLOG
         2230  +/*
         2231  +** Usage:  sqlite3_config_sqllog
         2232  +**
         2233  +** Zero the SQLITE_CONFIG_SQLLOG configuration
         2234  +*/
         2235  +static int test_config_sqllog(
         2236  +  void * clientData,
         2237  +  Tcl_Interp *interp,
         2238  +  int objc,
         2239  +  Tcl_Obj *CONST objv[]
         2240  +){
         2241  +  sqlite3_stmt *pStmt;            /* First argument */
         2242  +  if( objc!=1 ){
         2243  +    Tcl_WrongNumArgs(interp, 1, objv, "");
         2244  +    return TCL_ERROR;
         2245  +  }
         2246  +  sqlite3_config(SQLITE_CONFIG_SQLLOG, 0, 0);
         2247  +  return TCL_OK;
         2248  +}
         2249  +#endif
         2250  +
  2229   2251   /*
  2230   2252   ** Usage:  sqlite3_next_stmt  DB  STMT
  2231   2253   **
  2232   2254   ** Return the next statment in sequence after STMT.
  2233   2255   */
  2234   2256   static int test_next_stmt(
  2235   2257     void * clientData,
................................................................................
  7032   7054        { "sqlite3_user_change",       test_user_change,       0 },
  7033   7055        { "sqlite3_user_delete",       test_user_delete,       0 },
  7034   7056   #endif
  7035   7057   #ifdef SQLITE_ENABLE_STMT_SCANSTATUS
  7036   7058        { "sqlite3_stmt_scanstatus",       test_stmt_scanstatus,   0 },
  7037   7059        { "sqlite3_stmt_scanstatus_reset", test_stmt_scanstatus_reset,   0 },
  7038   7060   #endif
         7061  +#ifdef SQLITE_ENABLE_SQLLOG
         7062  +     { "sqlite3_config_sqllog",         test_config_sqllog,   0 },
         7063  +#endif
  7039   7064   
  7040   7065     };
  7041   7066     static int bitmask_size = sizeof(Bitmask)*8;
  7042   7067     static int longdouble_size = sizeof(LONGDOUBLE_TYPE);
  7043   7068     int i;
  7044   7069     extern int sqlite3_sync_count, sqlite3_fullsync_count;
  7045   7070     extern int sqlite3_opentemp_count;

Changes to src/test_config.c.

   652    652   #endif
   653    653   
   654    654   #ifdef YYTRACKMAXSTACKDEPTH
   655    655     Tcl_SetVar2(interp, "sqlite_options", "yytrackmaxstackdepth", "1", TCL_GLOBAL_ONLY);
   656    656   #else
   657    657     Tcl_SetVar2(interp, "sqlite_options", "yytrackmaxstackdepth", "0", TCL_GLOBAL_ONLY);
   658    658   #endif
          659  +
          660  +#ifdef SQLITE_ENABLE_SQLLOG
          661  +  Tcl_SetVar2(interp, "sqlite_options", "sqllog", "1", TCL_GLOBAL_ONLY);
          662  +#else
          663  +  Tcl_SetVar2(interp, "sqlite_options", "sqllog", "0", TCL_GLOBAL_ONLY);
          664  +#endif
   659    665   
   660    666   #define LINKVAR(x) { \
   661    667       static const int cv_ ## x = SQLITE_ ## x; \
   662    668       Tcl_LinkVar(interp, "SQLITE_" #x, (char *)&(cv_ ## x), \
   663    669                   TCL_LINK_INT | TCL_LINK_READ_ONLY); }
   664    670   
   665    671     LINKVAR( MAX_LENGTH );

Changes to src/test_sqllog.c.

    42     42   **
    43     43   **   Usually, if the application opens the same database file more than once
    44     44   **   (either by attaching it or by using more than one database handle), only
    45     45   **   a single copy is made. This behavior may be overridden (so that a 
    46     46   **   separate copy is taken each time the database file is opened or attached)
    47     47   **   by setting the environment variable SQLITE_SQLLOG_REUSE_FILES to 0.
    48     48   **
           49  +**   If the environment variable SQLITE_SQLLOG_CONDITIONAL is defined, then
           50  +**   logging is only done for database connections if a file named
           51  +**   "<database>-sqllog" exists in the same directly as the main database
           52  +**   file when it is first opened ("<database>" is replaced by the actual 
           53  +**   name of the main database file).
           54  +**
    49     55   ** OUTPUT:
    50     56   **
    51     57   **   The SQLITE_SQLLOG_DIR is populated with three types of files:
    52     58   **
    53     59   **      sqllog_N.db   - Copies of database files. N may be any integer.
    54     60   **
    55     61   **      sqllog_N.sql  - A list of SQL statements executed by a single
................................................................................
    84     90     return (int)getpid();
    85     91   #endif
    86     92   }
    87     93   
    88     94   /* Names of environment variables to be used */
    89     95   #define ENVIRONMENT_VARIABLE1_NAME "SQLITE_SQLLOG_DIR"
    90     96   #define ENVIRONMENT_VARIABLE2_NAME "SQLITE_SQLLOG_REUSE_FILES"
           97  +#define ENVIRONMENT_VARIABLE3_NAME "SQLITE_SQLLOG_CONDITIONAL"
    91     98   
    92     99   /* Assume that all database and database file names are shorted than this. */
    93    100   #define SQLLOG_NAMESZ 512
    94    101   
    95    102   /* Maximum number of simultaneous database connections the process may
    96    103   ** open (if any more are opened an error is logged using sqlite3_log()
    97    104   ** and processing is halted).
................................................................................
   112    119   */
   113    120   static struct SLGlobal {
   114    121     /* Protected by MUTEX_STATIC_MASTER */
   115    122     sqlite3_mutex *mutex;           /* Recursive mutex */
   116    123     int nConn;                      /* Size of aConn[] array */
   117    124   
   118    125     /* Protected by SLGlobal.mutex */
          126  +  int bConditional;               /* Only trace if *-sqllog file is present */
   119    127     int bReuse;                     /* True to avoid extra copies of db files */
   120    128     char zPrefix[SQLLOG_NAMESZ];    /* Prefix for all created files */
   121    129     char zIdx[SQLLOG_NAMESZ];       /* Full path to *.idx file */
   122    130     int iNextLog;                   /* Used to allocate file names */
   123    131     int iNextDb;                    /* Used to allocate database file names */
   124    132     int bRec;                       /* True if testSqllog() is called rec. */
   125    133     int iClock;                     /* Clock value */
................................................................................
   211    219     }
   212    220   
   213    221     fclose(fd);
   214    222     return zRet;
   215    223   }
   216    224   
   217    225   static int sqllogFindAttached(
   218         -  struct SLConn *p,               /* Database connection */
          226  +  sqlite3 *db,                    /* Database connection */
   219    227     const char *zSearch,            /* Name to search for (or NULL) */
   220    228     char *zName,                    /* OUT: Name of attached database */
   221    229     char *zFile                     /* OUT: Name of attached file */
   222    230   ){
   223    231     sqlite3_stmt *pStmt;
   224    232     int rc;
   225    233   
   226    234     /* The "PRAGMA database_list" command returns a list of databases in the
   227    235     ** order that they were attached. So a newly attached database is 
   228    236     ** described by the last row returned.  */
   229    237     assert( sqllogglobal.bRec==0 );
   230    238     sqllogglobal.bRec = 1;
   231         -  rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);
          239  +  rc = sqlite3_prepare_v2(db, "PRAGMA database_list", -1, &pStmt, 0);
   232    240     if( rc==SQLITE_OK ){
   233    241       while( SQLITE_ROW==sqlite3_step(pStmt) ){
   234    242         const char *zVal1; int nVal1;
   235    243         const char *zVal2; int nVal2;
   236    244   
   237    245         zVal1 = (const char*)sqlite3_column_text(pStmt, 1);
   238    246         nVal1 = sqlite3_column_bytes(pStmt, 1);
   239         -      memcpy(zName, zVal1, nVal1+1);
          247  +      if( zName ){
          248  +        memcpy(zName, zVal1, nVal1+1);
          249  +      }
   240    250   
   241    251         zVal2 = (const char*)sqlite3_column_text(pStmt, 2);
   242    252         nVal2 = sqlite3_column_bytes(pStmt, 2);
   243    253         memcpy(zFile, zVal2, nVal2+1);
   244    254   
   245    255         if( zSearch && strlen(zSearch)==nVal1 
   246    256          && 0==sqlite3_strnicmp(zSearch, zVal1, nVal1)
................................................................................
   281    291   static void sqllogCopydb(struct SLConn *p, const char *zSearch, int bLog){
   282    292     char zName[SQLLOG_NAMESZ];      /* Attached database name */
   283    293     char zFile[SQLLOG_NAMESZ];      /* Database file name */
   284    294     char *zFree;
   285    295     char *zInit = 0;
   286    296     int rc;
   287    297   
   288         -  rc = sqllogFindAttached(p, zSearch, zName, zFile);
          298  +  rc = sqllogFindAttached(p->db, zSearch, zName, zFile);
   289    299     if( rc!=SQLITE_OK ) return;
   290    300   
   291    301     if( zFile[0]=='\0' ){
   292    302       zInit = sqlite3_mprintf("");
   293    303     }else{
   294    304       if( sqllogglobal.bReuse ){
   295    305         zInit = sqllogFindFile(zFile);
................................................................................
   400    410       /* Not an ATTACH statement. Write this directly to the log. */
   401    411       fprintf(p->fd, "%s; -- clock=%d\n", zSql, sqllogglobal.iClock++);
   402    412     }else{
   403    413       /* This is an ATTACH statement. Copy the database. */
   404    414       sqllogCopydb(p, 0, 1);
   405    415     }
   406    416   }
          417  +
          418  +/*
          419  +** The database handle passed as the only argument has just been opened.
          420  +** Return true if this module should log initial databases and SQL 
          421  +** statements for this connection, or false otherwise.
          422  +**
          423  +** If an error occurs, sqlite3_log() is invoked to report it to the user
          424  +** and zero returned.
          425  +*/
          426  +static int sqllogTraceDb(sqlite3 *db){
          427  +  int bRet = 1;
          428  +  if( sqllogglobal.bConditional ){
          429  +    char zFile[SQLLOG_NAMESZ];      /* Attached database name */
          430  +    int rc = sqllogFindAttached(db, "main", 0, zFile);
          431  +    if( rc==SQLITE_OK ){
          432  +      int nFile = strlen(zFile);
          433  +      if( (SQLLOG_NAMESZ-nFile)<8 ){
          434  +        sqlite3_log(SQLITE_IOERR, 
          435  +            "sqllogTraceDb(): database name too long (%d bytes)", nFile
          436  +        );
          437  +        bRet = 0;
          438  +      }else{
          439  +        memcpy(&zFile[nFile], "-sqllog", 8);
          440  +        bRet = !access(zFile, F_OK);
          441  +      }
          442  +    }
          443  +  }
          444  +  return bRet;
          445  +}
   407    446   
   408    447   /*
   409    448   ** The SQLITE_CONFIG_SQLLOG callback registered by sqlite3_init_sqllog().
   410    449   **
   411    450   ** The eType parameter has the following values:
   412    451   **
   413    452   **    0:  Opening a new database connection.  zSql is the name of the
................................................................................
   435    474   
   436    475     /* This is a database open command. */
   437    476     if( eType==0 ){
   438    477       sqlite3_mutex_enter(master);
   439    478       if( sqllogglobal.mutex==0 ){
   440    479         sqllogglobal.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_RECURSIVE);
   441    480       }
   442         -    p = &sqllogglobal.aConn[sqllogglobal.nConn++];
   443         -    p->fd = 0;
   444         -    p->db = db;
   445         -    p->iLog = sqllogglobal.iNextLog++;
   446    481       sqlite3_mutex_leave(master);
   447    482   
   448         -    /* Open the log and take a copy of the main database file */
   449    483       sqlite3_mutex_enter(sqllogglobal.mutex);
   450         -    if( sqllogglobal.bRec==0 ){
          484  +    if( sqllogglobal.bRec==0 && sqllogTraceDb(db) ){
          485  +
          486  +      sqlite3_mutex_enter(master);
          487  +      p = &sqllogglobal.aConn[sqllogglobal.nConn++];
          488  +      p->fd = 0;
          489  +      p->db = db;
          490  +      p->iLog = sqllogglobal.iNextLog++;
          491  +      sqlite3_mutex_leave(master);
          492  +
          493  +      /* Open the log and take a copy of the main database file */
   451    494         sqllogOpenlog(p);
   452    495         if( p->fd ) sqllogCopydb(p, "main", 0);
   453    496       }
   454    497       sqlite3_mutex_leave(sqllogglobal.mutex);
   455    498     }
   456    499   
   457    500     else{
   458    501   
   459    502       int i;
   460    503       for(i=0; i<sqllogglobal.nConn; i++){
   461    504         p = &sqllogglobal.aConn[i];
   462    505         if( p->db==db ) break;
   463    506       }
   464         -    if( i==sqllogglobal.nConn ) return;
   465    507   
   466    508       /* A database handle close command */
   467    509       if( eType==2 ){
   468    510         sqlite3_mutex_enter(master);
   469         -      if( p->fd ) fclose(p->fd);
   470         -      p->db = 0;
   471         -      p->fd = 0;
          511  +      if( i<sqllogglobal.nConn ){
          512  +        if( p->fd ) fclose(p->fd);
          513  +        p->db = 0;
          514  +        p->fd = 0;
          515  +        sqllogglobal.nConn--;
          516  +      }
   472    517   
   473         -      sqllogglobal.nConn--;
   474    518         if( sqllogglobal.nConn==0 ){
   475    519           sqlite3_mutex_free(sqllogglobal.mutex);
   476    520           sqllogglobal.mutex = 0;
   477         -      }else{
          521  +      }else if( i<sqllogglobal.nConn ){
   478    522           int nShift = &sqllogglobal.aConn[sqllogglobal.nConn] - p;
   479    523           if( nShift>0 ){
   480    524             memmove(p, &p[1], nShift*sizeof(struct SLConn));
   481    525           }
   482    526         }
   483    527         sqlite3_mutex_leave(master);
   484    528   
   485    529       /* An ordinary SQL command. */
   486         -    }else if( p->fd ){
          530  +    }else if( i<sqllogglobal.nConn && p->fd ){
   487    531         sqlite3_mutex_enter(sqllogglobal.mutex);
   488    532         if( sqllogglobal.bRec==0 ){
   489    533           testSqllogStmt(p, zSql);
   490    534         }
   491    535         sqlite3_mutex_leave(sqllogglobal.mutex);
   492    536       }
   493    537     }
................................................................................
   500    544   ** database activity.
   501    545   */
   502    546   void sqlite3_init_sqllog(void){
   503    547     if( getenv(ENVIRONMENT_VARIABLE1_NAME) ){
   504    548       if( SQLITE_OK==sqlite3_config(SQLITE_CONFIG_SQLLOG, testSqllog, 0) ){
   505    549         memset(&sqllogglobal, 0, sizeof(sqllogglobal));
   506    550         sqllogglobal.bReuse = 1;
          551  +      if( getenv(ENVIRONMENT_VARIABLE3_NAME) ){
          552  +        sqllogglobal.bConditional = 1;
          553  +      }
   507    554       }
   508    555     }
   509    556   }

Added test/sqllog.test.

            1  +# 2015 November 13
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +# This file implements regression tests for SQLite library.  The
           12  +# focus of this file is testing the test_sqllog.c module.
           13  +#
           14  +
           15  +set testdir [file dirname $argv0]
           16  +source $testdir/tester.tcl
           17  +set testprefix sqllog
           18  +
           19  +ifcapable !sqllog {
           20  +  finish_test
           21  +  return
           22  +}
           23  +
           24  +proc readfile {f} {
           25  +  set fd [open $f]
           26  +  set txt [read $fd]
           27  +  close $fd
           28  +  set txt
           29  +}
           30  +
           31  +proc delete_all_sqllog_files {} {
           32  +  forcedelete {*}[glob -nocomplain sqllog_*.sql]
           33  +  forcedelete {*}[glob -nocomplain sqllog_*.db]
           34  +  forcedelete {*}[glob -nocomplain sqllog_*.idx]
           35  +}
           36  +
           37  +proc touch {f} {
           38  +  set fd [open $f w+]
           39  +  close $fd
           40  +}
           41  +
           42  +db close
           43  +sqlite3_shutdown
           44  +set ::env(SQLITE_SQLLOG_DIR) [pwd]
           45  +
           46  +delete_all_sqllog_files
           47  +
           48  +sqlite3 db test.db
           49  +set a a
           50  +set b b
           51  +do_execsql_test 1.0 {
           52  +  CREATE TABLE t1(x, y);
           53  +  INSERT INTO t1 VALUES(1, 2);
           54  +  INSERT INTO t1 VALUES($a, $b);
           55  +  SELECT * FROM t1;
           56  +} {1 2 a b}
           57  +db close
           58  +
           59  +do_test 1.1 {
           60  +  readfile [lindex [glob sqllog_*.sql] 0]
           61  +} [string trimleft {
           62  +/-- Main database is '.*/sqllog_.*_0.db'
           63  +CREATE TABLE t1\(x, y\);; -- clock=0
           64  +INSERT INTO t1 VALUES\(1, 2\);; -- clock=1
           65  +INSERT INTO t1 VALUES\('a', 'b'\);; -- clock=2
           66  +SELECT . FROM t1;; -- clock=3
           67  +/}]
           68  +
           69  +do_test 1.2 {
           70  +  file size [lindex [glob sqllog_*_0.db] 0]
           71  +} 1024
           72  +
           73  +#-------------------------------------------------------------------------
           74  +catch { db close }
           75  +sqlite3_shutdown
           76  +delete_all_sqllog_files
           77  +forcedelete test.db-sqllog
           78  +
           79  +set ::env(SQLITE_SQLLOG_CONDITIONAL) 1
           80  +sqlite3 db test.db
           81  +do_execsql_test 2.1 {
           82  +  INSERT INTO t1 VALUES(4, 5);
           83  +  SELECT * FROM t1;
           84  +} {1 2 a b 4 5}
           85  +
           86  +do_test 2.2 {
           87  +  glob -nocomplain sqllog_*
           88  +} {}
           89  +
           90  +db close
           91  +touch test.db-sqllog
           92  +sqlite3 db test.db
           93  +do_execsql_test 2.3 {
           94  +  INSERT INTO t1 VALUES(6, 7);
           95  +  SELECT * FROM t1;
           96  +} {1 2 a b 4 5 6 7}
           97  +db close
           98  +
           99  +do_test 2.4 {
          100  +  readfile [lindex [glob sqllog_*.sql] 0]
          101  +} [string trimleft {
          102  +/-- Main database is '.*/sqllog_.*_0.db'
          103  +INSERT INTO t1 VALUES\(6, 7\);; -- clock=0
          104  +SELECT . FROM t1;; -- clock=1
          105  +/}]
          106  +
          107  +catch { db close }
          108  +sqlite3_shutdown
          109  +unset ::env(SQLITE_SQLLOG_DIR)
          110  +unset ::env(SQLITE_SQLLOG_CONDITIONAL)
          111  +sqlite3_config_sqllog
          112  +sqlite3_initialize
          113  +breakpoint
          114  +finish_test
          115  +
          116  +

Changes to test/trigger7.test.

    16     16   
    17     17   set testdir [file dirname $argv0]
    18     18   source $testdir/tester.tcl
    19     19   ifcapable {!trigger} {
    20     20     finish_test
    21     21     return
    22     22   }
    23         -
    24     23   
    25     24   # Error messages resulting from qualified trigger names.
    26     25   #
    27     26   do_test trigger7-1.1 {
    28     27     execsql {
    29     28       CREATE TABLE t1(x, y);
    30     29     }