/ Check-in [ba8d08b6]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

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

Overview
Comment:Update the sessions branch to include the SQLLOG enhancement, the SQLITE_IOERR_DELETE_NOENT fix, and a fix for the number-of-documents bug in FTS4.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | sessions
Files: files | file ages | folders
SHA1: ba8d08b67021a32fda069c18b7eb93523e6f0d1f
User & Date: drh 2012-11-27 21:56:28
Context
2012-12-08
23:37
Pull the latest trunk changes into the sessions branch, and in particular the collating-sequence refactorization. check-in: 4f6d69ae user: drh tags: sessions
2012-11-27
21:56
Update the sessions branch to include the SQLLOG enhancement, the SQLITE_IOERR_DELETE_NOENT fix, and a fix for the number-of-documents bug in FTS4. check-in: ba8d08b6 user: drh tags: sessions
21:22
Add the SQLLOG capability to trunk. check-in: f0843f88 user: drh tags: trunk
2012-11-10
01:27
Merge the latest changes from trunk: chiefly the outer/inner loop query optimizer scoring enhancement and the INSTR() function. check-in: 2993ca20 user: drh tags: sessions
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to ext/fts3/fts3_write.c.

   772    772   ** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code.
   773    773   */
   774    774   static int fts3PendingTermsAdd(
   775    775     Fts3Table *p,                   /* Table into which text will be inserted */
   776    776     int iLangid,                    /* Language id to use */
   777    777     const char *zText,              /* Text of document to be inserted */
   778    778     int iCol,                       /* Column into which text is being inserted */
   779         -  u32 *pnWord                     /* OUT: Number of tokens inserted */
          779  +  u32 *pnWord                     /* IN/OUT: Incr. by number tokens inserted */
   780    780   ){
   781    781     int rc;
   782    782     int iStart = 0;
   783    783     int iEnd = 0;
   784    784     int iPos = 0;
   785    785     int nWord = 0;
   786    786   
................................................................................
   836    836         rc = fts3PendingTermsAddOne(
   837    837             p, iCol, iPos, &pIndex->hPending, zToken, pIndex->nPrefix
   838    838         );
   839    839       }
   840    840     }
   841    841   
   842    842     pModule->xClose(pCsr);
   843         -  *pnWord = nWord;
          843  +  *pnWord += nWord;
   844    844     return (rc==SQLITE_DONE ? SQLITE_OK : rc);
   845    845   }
   846    846   
   847    847   /* 
   848    848   ** Calling this function indicates that subsequent calls to 
   849    849   ** fts3PendingTermsAdd() are to add term/position-list pairs for the
   850    850   ** contents of the document with docid iDocid.
................................................................................
  1040   1040   ** (an integer) of a row about to be deleted. Remove all terms from the
  1041   1041   ** full-text index.
  1042   1042   */
  1043   1043   static void fts3DeleteTerms( 
  1044   1044     int *pRC,               /* Result code */
  1045   1045     Fts3Table *p,           /* The FTS table to delete from */
  1046   1046     sqlite3_value *pRowid,  /* The docid to be deleted */
  1047         -  u32 *aSz                /* Sizes of deleted document written here */
         1047  +  u32 *aSz,               /* Sizes of deleted document written here */
         1048  +  int *pbFound            /* OUT: Set to true if row really does exist */
  1048   1049   ){
  1049   1050     int rc;
  1050   1051     sqlite3_stmt *pSelect;
  1051   1052   
         1053  +  assert( *pbFound==0 );
  1052   1054     if( *pRC ) return;
  1053   1055     rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pSelect, &pRowid);
  1054   1056     if( rc==SQLITE_OK ){
  1055   1057       if( SQLITE_ROW==sqlite3_step(pSelect) ){
  1056   1058         int i;
  1057   1059         int iLangid = langidFromSelect(p, pSelect);
  1058   1060         rc = fts3PendingTermsDocid(p, iLangid, sqlite3_column_int64(pSelect, 0));
................................................................................
  1062   1064           aSz[p->nColumn] += sqlite3_column_bytes(pSelect, i);
  1063   1065         }
  1064   1066         if( rc!=SQLITE_OK ){
  1065   1067           sqlite3_reset(pSelect);
  1066   1068           *pRC = rc;
  1067   1069           return;
  1068   1070         }
         1071  +      *pbFound = 1;
  1069   1072       }
  1070   1073       rc = sqlite3_reset(pSelect);
  1071   1074     }else{
  1072   1075       sqlite3_reset(pSelect);
  1073   1076     }
  1074   1077     *pRC = rc;
  1075   1078   }
................................................................................
  3286   3289         }
  3287   3290       }
  3288   3291   
  3289   3292       while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
  3290   3293         int iCol;
  3291   3294         int iLangid = langidFromSelect(p, pStmt);
  3292   3295         rc = fts3PendingTermsDocid(p, iLangid, sqlite3_column_int64(pStmt, 0));
  3293         -      aSz[p->nColumn] = 0;
         3296  +      memset(aSz, 0, sizeof(aSz[0]) * (p->nColumn+1));
  3294   3297         for(iCol=0; rc==SQLITE_OK && iCol<p->nColumn; iCol++){
  3295   3298           const char *z = (const char *) sqlite3_column_text(pStmt, iCol+1);
  3296   3299           rc = fts3PendingTermsAdd(p, iLangid, z, iCol, &aSz[iCol]);
  3297   3300           aSz[p->nColumn] += sqlite3_column_bytes(pStmt, iCol+1);
  3298   3301         }
  3299   3302         if( p->bHasDocsize ){
  3300   3303           fts3InsertDocsize(&rc, p, aSz);
................................................................................
  5190   5193   ** SQLite value pRowid contains the rowid of a row that may or may not be
  5191   5194   ** present in the FTS3 table. If it is, delete it and adjust the contents
  5192   5195   ** of subsiduary data structures accordingly.
  5193   5196   */
  5194   5197   static int fts3DeleteByRowid(
  5195   5198     Fts3Table *p, 
  5196   5199     sqlite3_value *pRowid, 
  5197         -  int *pnDoc,
         5200  +  int *pnChng,                    /* IN/OUT: Decrement if row is deleted */
  5198   5201     u32 *aSzDel
  5199   5202   ){
  5200         -  int isEmpty = 0;
  5201         -  int rc = fts3IsEmpty(p, pRowid, &isEmpty);
  5202         -  if( rc==SQLITE_OK ){
  5203         -    if( isEmpty ){
  5204         -      /* Deleting this row means the whole table is empty. In this case
  5205         -      ** delete the contents of all three tables and throw away any
  5206         -      ** data in the pendingTerms hash table.  */
  5207         -      rc = fts3DeleteAll(p, 1);
  5208         -      *pnDoc = *pnDoc - 1;
  5209         -    }else{
  5210         -      fts3DeleteTerms(&rc, p, pRowid, aSzDel);
  5211         -      if( p->zContentTbl==0 ){
  5212         -        fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, &pRowid);
  5213         -        if( sqlite3_changes(p->db) ) *pnDoc = *pnDoc - 1;
         5203  +  int rc = SQLITE_OK;             /* Return code */
         5204  +  int bFound = 0;                 /* True if *pRowid really is in the table */
         5205  +
         5206  +  fts3DeleteTerms(&rc, p, pRowid, aSzDel, &bFound);
         5207  +  if( bFound && rc==SQLITE_OK ){
         5208  +    int isEmpty = 0;              /* Deleting *pRowid leaves the table empty */
         5209  +    rc = fts3IsEmpty(p, pRowid, &isEmpty);
         5210  +    if( rc==SQLITE_OK ){
         5211  +      if( isEmpty ){
         5212  +        /* Deleting this row means the whole table is empty. In this case
         5213  +        ** delete the contents of all three tables and throw away any
         5214  +        ** data in the pendingTerms hash table.  */
         5215  +        rc = fts3DeleteAll(p, 1);
         5216  +        *pnChng = 0;
         5217  +        memset(aSzDel, 0, sizeof(u32) * (p->nColumn+1) * 2);
  5214   5218         }else{
  5215         -        *pnDoc = *pnDoc - 1;
  5216         -      }
  5217         -      if( p->bHasDocsize ){
  5218         -        fts3SqlExec(&rc, p, SQL_DELETE_DOCSIZE, &pRowid);
         5219  +        *pnChng = *pnChng - 1;
         5220  +        if( p->zContentTbl==0 ){
         5221  +          fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, &pRowid);
         5222  +        }
         5223  +        if( p->bHasDocsize ){
         5224  +          fts3SqlExec(&rc, p, SQL_DELETE_DOCSIZE, &pRowid);
         5225  +        }
  5219   5226         }
  5220   5227       }
  5221   5228     }
  5222   5229   
  5223   5230     return rc;
  5224   5231   }
  5225   5232   
................................................................................
  5270   5277   
  5271   5278     if( nArg>1 && sqlite3_value_int(apVal[2 + p->nColumn + 2])<0 ){
  5272   5279       rc = SQLITE_CONSTRAINT;
  5273   5280       goto update_out;
  5274   5281     }
  5275   5282   
  5276   5283     /* Allocate space to hold the change in document sizes */
  5277         -  aSzIns = sqlite3_malloc( sizeof(aSzIns[0])*(p->nColumn+1)*2 );
  5278         -  if( aSzIns==0 ){
         5284  +  aSzDel = sqlite3_malloc( sizeof(aSzDel[0])*(p->nColumn+1)*2 );
         5285  +  if( aSzDel==0 ){
  5279   5286       rc = SQLITE_NOMEM;
  5280   5287       goto update_out;
  5281   5288     }
  5282         -  aSzDel = &aSzIns[p->nColumn+1];
  5283         -  memset(aSzIns, 0, sizeof(aSzIns[0])*(p->nColumn+1)*2);
         5289  +  aSzIns = &aSzDel[p->nColumn+1];
         5290  +  memset(aSzDel, 0, sizeof(aSzDel[0])*(p->nColumn+1)*2);
  5284   5291   
  5285   5292     /* If this is an INSERT operation, or an UPDATE that modifies the rowid
  5286   5293     ** value, then this operation requires constraint handling.
  5287   5294     **
  5288   5295     ** If the on-conflict mode is REPLACE, this means that the existing row
  5289   5296     ** should be deleted from the database before inserting the new row. Or,
  5290   5297     ** if the on-conflict mode is other than REPLACE, then this method must
................................................................................
  5361   5368     }
  5362   5369   
  5363   5370     if( p->bFts4 ){
  5364   5371       fts3UpdateDocTotals(&rc, p, aSzIns, aSzDel, nChng);
  5365   5372     }
  5366   5373   
  5367   5374    update_out:
  5368         -  sqlite3_free(aSzIns);
         5375  +  sqlite3_free(aSzDel);
  5369   5376     sqlite3Fts3SegmentsClose(p);
  5370   5377     return rc;
  5371   5378   }
  5372   5379   
  5373   5380   /* 
  5374   5381   ** Flush any data in the pending-terms hash table to disk. If successful,
  5375   5382   ** merge all segments in the database (including the new segment, if 

Changes to main.mk.

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

Changes to src/global.c.

   171    171      0,                         /* isMallocInit */
   172    172      0,                         /* isPCacheInit */
   173    173      0,                         /* pInitMutex */
   174    174      0,                         /* nRefInitMutex */
   175    175      0,                         /* xLog */
   176    176      0,                         /* pLogArg */
   177    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    186   ** Hash table for global functions - functions common to all
   183    187   ** database connections.  After initialization, this table is
   184    188   ** read-only.

Changes to src/main.c.

   127    127   
   128    128     /* If SQLite is already completely initialized, then this call
   129    129     ** to sqlite3_initialize() should be a no-op.  But the initialization
   130    130     ** must be complete.  So isInit must not be set until the very end
   131    131     ** of this routine.
   132    132     */
   133    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    142     /* Make sure the mutex subsystem is initialized.  If unable to 
   136    143     ** initialize the mutex subsystem, return early with the error.
   137    144     ** If the system is so sick that we are unable to allocate a mutex,
   138    145     ** there is not much SQLite is going to be able to do.
   139    146     **
   140    147     ** The mutex subsystem must take care of serializing its own
................................................................................
   475    482         break;
   476    483       }
   477    484   
   478    485       case SQLITE_CONFIG_COVERING_INDEX_SCAN: {
   479    486         sqlite3GlobalConfig.bUseCis = va_arg(ap, int);
   480    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    499       default: {
   484    500         rc = SQLITE_ERROR;
   485    501         break;
   486    502       }
   487    503     }
   488    504     va_end(ap);
................................................................................
   814    830     */
   815    831     if( !forceZombie && connectionIsBusy(db) ){
   816    832       sqlite3Error(db, SQLITE_BUSY, "unable to close due to unfinalized "
   817    833          "statements or unfinished backups");
   818    834       sqlite3_mutex_leave(db->mutex);
   819    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    845     /* Convert the connection into a zombie and then close it.
   823    846     */
   824    847     db->magic = SQLITE_MAGIC_ZOMBIE;
   825    848     sqlite3LeaveMutexAndCloseZombie(db);
   826    849     return SQLITE_OK;
   827    850   }
................................................................................
  2468   2491     if( rc==SQLITE_NOMEM ){
  2469   2492       sqlite3_close(db);
  2470   2493       db = 0;
  2471   2494     }else if( rc!=SQLITE_OK ){
  2472   2495       db->magic = SQLITE_MAGIC_SICK;
  2473   2496     }
  2474   2497     *ppDb = db;
         2498  +#ifdef SQLITE_ENABLE_SQLLOG
         2499  +  if( sqlite3GlobalConfig.xSqllog ){
         2500  +    /* Opening a db handle. Fourth parameter is passed 0. */
         2501  +    void *pArg = sqlite3GlobalConfig.pSqllogArg;
         2502  +    sqlite3GlobalConfig.xSqllog(pArg, db, zFilename, 0);
         2503  +  }
         2504  +#endif
  2475   2505     return sqlite3ApiExit(0, rc);
  2476   2506   }
  2477   2507   
  2478   2508   /*
  2479   2509   ** Open a new database handle.
  2480   2510   */
  2481   2511   int sqlite3_open(

Changes to src/os_unix.c.

    42     42   **   *  Locking primitives for the proxy uber-locking-method. (MacOSX only)
    43     43   **   *  Definitions of sqlite3_vfs objects for all locking methods
    44     44   **      plus implementations of sqlite3_os_init() and sqlite3_os_end().
    45     45   */
    46     46   #include "sqliteInt.h"
    47     47   #if SQLITE_OS_UNIX              /* This file is used on unix only */
    48     48   
           49  +/* Use posix_fallocate() if it is available
           50  +*/
           51  +#if !defined(HAVE_POSIX_FALLOCATE) \
           52  +      && (_XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L)
           53  +# define HAVE_POSIX_FALLOCATE 1
           54  +#endif
           55  +
    49     56   /*
    50     57   ** There are various methods for file locking used for concurrency
    51     58   ** control:
    52     59   **
    53     60   **   1. POSIX locking (the default),
    54     61   **   2. No locking,
    55     62   **   3. Dot-file locking,
................................................................................
  4164   4171           /* The requested memory region does not exist. If bExtend is set to
  4165   4172           ** false, exit early. *pp will be set to NULL and SQLITE_OK returned.
  4166   4173           **
  4167   4174           ** Alternatively, if bExtend is true, use ftruncate() to allocate
  4168   4175           ** the requested memory region.
  4169   4176           */
  4170   4177           if( !bExtend ) goto shmpage_out;
         4178  +#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
         4179  +        if( osFallocate(pShmNode->h, sStat.st_size, nByte)!=0 ){
         4180  +          rc = unixLogError(SQLITE_IOERR_SHMSIZE, "fallocate",
         4181  +                            pShmNode->zFilename);
         4182  +          goto shmpage_out;
         4183  +        }
         4184  +#else
  4171   4185           if( robust_ftruncate(pShmNode->h, nByte) ){
  4172   4186             rc = unixLogError(SQLITE_IOERR_SHMSIZE, "ftruncate",
  4173   4187                               pShmNode->zFilename);
  4174   4188             goto shmpage_out;
  4175   4189           }
         4190  +#endif
  4176   4191         }
  4177   4192       }
  4178   4193   
  4179   4194       /* Map the requested memory region into this processes address space. */
  4180   4195       apNew = (char **)sqlite3_realloc(
  4181   4196           pShmNode->apRegion, (iRegion+1)*sizeof(char *)
  4182   4197       );

Changes to src/os_win.c.

  3884   3884   #if SQLITE_OS_WINRT
  3885   3885         WIN32_FILE_ATTRIBUTE_DATA sAttrData;
  3886   3886         memset(&sAttrData, 0, sizeof(sAttrData));
  3887   3887         if ( osGetFileAttributesExW(zConverted, GetFileExInfoStandard,
  3888   3888                                     &sAttrData) ){
  3889   3889           attr = sAttrData.dwFileAttributes;
  3890   3890         }else{
  3891         -        rc = SQLITE_OK; /* Already gone? */
         3891  +        lastErrno = osGetLastError();
         3892  +        if( lastErrno==ERROR_FILE_NOT_FOUND || lastErrno==ERROR_PATH_NOT_FOUND ){
         3893  +          rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */
         3894  +        }else{
         3895  +          rc = SQLITE_ERROR;
         3896  +        }
  3892   3897           break;
  3893   3898         }
  3894   3899   #else
  3895   3900         attr = osGetFileAttributesW(zConverted);
  3896   3901   #endif
  3897   3902         if ( attr==INVALID_FILE_ATTRIBUTES ){
  3898         -        rc = SQLITE_OK; /* Already gone? */
         3903  +        lastErrno = osGetLastError();
         3904  +        if( lastErrno==ERROR_FILE_NOT_FOUND || lastErrno==ERROR_PATH_NOT_FOUND ){
         3905  +          rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */
         3906  +        }else{
         3907  +          rc = SQLITE_ERROR;
         3908  +        }
  3899   3909           break;
  3900   3910         }
  3901   3911         if ( attr&FILE_ATTRIBUTE_DIRECTORY ){
  3902   3912           rc = SQLITE_ERROR; /* Files only. */
  3903   3913           break;
  3904   3914         }
  3905   3915         if ( osDeleteFileW(zConverted) ){
................................................................................
  3913   3923       } while(1);
  3914   3924     }
  3915   3925   #ifdef SQLITE_WIN32_HAS_ANSI
  3916   3926     else{
  3917   3927       do {
  3918   3928         attr = osGetFileAttributesA(zConverted);
  3919   3929         if ( attr==INVALID_FILE_ATTRIBUTES ){
  3920         -        rc = SQLITE_OK; /* Already gone? */
         3930  +        lastErrno = osGetLastError();
         3931  +        if( lastErrno==ERROR_FILE_NOT_FOUND || lastErrno==ERROR_PATH_NOT_FOUND ){
         3932  +          rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */
         3933  +        }else{
         3934  +          rc = SQLITE_ERROR;
         3935  +        }
  3921   3936           break;
  3922   3937         }
  3923   3938         if ( attr&FILE_ATTRIBUTE_DIRECTORY ){
  3924   3939           rc = SQLITE_ERROR; /* Files only. */
  3925   3940           break;
  3926   3941         }
  3927   3942         if ( osDeleteFileA(zConverted) ){
................................................................................
  3931   3946         if ( !retryIoerr(&cnt, &lastErrno) ){
  3932   3947           rc = SQLITE_ERROR; /* No more retries. */
  3933   3948           break;
  3934   3949         }
  3935   3950       } while(1);
  3936   3951     }
  3937   3952   #endif
  3938         -  if( rc ){
         3953  +  if( rc && rc!=SQLITE_IOERR_DELETE_NOENT ){
  3939   3954       rc = winLogError(SQLITE_IOERR_DELETE, lastErrno,
  3940   3955                "winDelete", zFilename);
  3941   3956     }else{
  3942   3957       logIoerr(cnt);
  3943   3958     }
  3944   3959     sqlite3_free(zConverted);
  3945   3960     OSTRACE(("DELETE \"%s\" %s\n", zFilename, (rc ? "failed" : "ok" )));

Changes to src/sqlite.h.in.

  1589   1589   ** without change even with newer versions of SQLite.
  1590   1590   **
  1591   1591   ** [[SQLITE_CONFIG_PCACHE]] [[SQLITE_CONFIG_GETPCACHE]]
  1592   1592   ** <dt>SQLITE_CONFIG_PCACHE and SQLITE_CONFIG_GETPCACHE
  1593   1593   ** <dd> These options are obsolete and should not be used by new code.
  1594   1594   ** They are retained for backwards compatibility but are now no-ops.
  1595   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   1613   #define SQLITE_CONFIG_SINGLETHREAD  1  /* nil */
  1598   1614   #define SQLITE_CONFIG_MULTITHREAD   2  /* nil */
  1599   1615   #define SQLITE_CONFIG_SERIALIZED    3  /* nil */
  1600   1616   #define SQLITE_CONFIG_MALLOC        4  /* sqlite3_mem_methods* */
  1601   1617   #define SQLITE_CONFIG_GETMALLOC     5  /* sqlite3_mem_methods* */
  1602   1618   #define SQLITE_CONFIG_SCRATCH       6  /* void*, int sz, int N */
................................................................................
  1610   1626   #define SQLITE_CONFIG_PCACHE       14  /* no-op */
  1611   1627   #define SQLITE_CONFIG_GETPCACHE    15  /* no-op */
  1612   1628   #define SQLITE_CONFIG_LOG          16  /* xFunc, void* */
  1613   1629   #define SQLITE_CONFIG_URI          17  /* int */
  1614   1630   #define SQLITE_CONFIG_PCACHE2      18  /* sqlite3_pcache_methods2* */
  1615   1631   #define SQLITE_CONFIG_GETPCACHE2   19  /* sqlite3_pcache_methods2* */
  1616   1632   #define SQLITE_CONFIG_COVERING_INDEX_SCAN 20  /* int */
         1633  +#define SQLITE_CONFIG_SQLLOG       21  /* xSqllog, void* */
  1617   1634   
  1618   1635   /*
  1619   1636   ** CAPI3REF: Database Connection Configuration Options
  1620   1637   **
  1621   1638   ** These constants are the available integer configuration options that
  1622   1639   ** can be passed as the second argument to the [sqlite3_db_config()] interface.
  1623   1640   **

Changes to src/sqliteInt.h.

  2523   2523     int isMallocInit;                 /* True after malloc is initialized */
  2524   2524     int isPCacheInit;                 /* True after malloc is initialized */
  2525   2525     sqlite3_mutex *pInitMutex;        /* Mutex used by sqlite3_initialize() */
  2526   2526     int nRefInitMutex;                /* Number of users of pInitMutex */
  2527   2527     void (*xLog)(void*,int,const char*); /* Function for logging */
  2528   2528     void *pLogArg;                       /* First argument to xLog() */
  2529   2529     int bLocaltimeFault;              /* True to fail localtime() calls */
         2530  +#ifdef SQLITE_ENABLE_SQLLOG
         2531  +  void(*xSqllog)(void*,sqlite3*,const char*, int);
         2532  +  void *pSqllogArg;
         2533  +#endif
  2530   2534   };
  2531   2535   
  2532   2536   /*
  2533   2537   ** Context pointer passed down through the tree-walk.
  2534   2538   */
  2535   2539   struct Walker {
  2536   2540     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     51   ** Remember the SQL string for a prepared statement.
    52     52   */
    53     53   void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, int isPrepareV2){
    54     54     assert( isPrepareV2==1 || isPrepareV2==0 );
    55     55     if( p==0 ) return;
    56         -#ifdef SQLITE_OMIT_TRACE
           56  +#if defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_ENABLE_SQLLOG)
    57     57     if( !isPrepareV2 ) return;
    58     58   #endif
    59     59     assert( p->zSql==0 );
    60     60     p->zSql = sqlite3DbStrNDup(p->db, z, n);
    61     61     p->isPrepareV2 = (u8)isPrepareV2;
    62     62   }
    63     63   
................................................................................
  2323   2323       db->errCode = rc;
  2324   2324     }else{
  2325   2325       sqlite3Error(db, rc, 0);
  2326   2326     }
  2327   2327     return rc;
  2328   2328   }
  2329   2329   
         2330  +#ifdef SQLITE_ENABLE_SQLLOG
         2331  +/*
         2332  +** If an SQLITE_CONFIG_SQLLOG hook is registered and the VM has been run, 
         2333  +** invoke it.
         2334  +*/
         2335  +static void vdbeInvokeSqllog(Vdbe *v){
         2336  +  if( sqlite3GlobalConfig.xSqllog && v->rc==SQLITE_OK && v->zSql && v->pc>=0 ){
         2337  +    char *zExpanded = sqlite3VdbeExpandSql(v, v->zSql);
         2338  +    assert( v->db->init.busy==0 );
         2339  +    if( zExpanded ){
         2340  +      sqlite3GlobalConfig.xSqllog(
         2341  +          sqlite3GlobalConfig.pSqllogArg, v->db, zExpanded, 1
         2342  +      );
         2343  +      sqlite3DbFree(v->db, zExpanded);
         2344  +    }
         2345  +  }
         2346  +}
         2347  +#else
         2348  +# define vdbeInvokeSqllog(x)
         2349  +#endif
         2350  +
  2330   2351   /*
  2331   2352   ** Clean up a VDBE after execution but do not delete the VDBE just yet.
  2332   2353   ** Write any error messages into *pzErrMsg.  Return the result code.
  2333   2354   **
  2334   2355   ** After this routine is run, the VDBE should be ready to be executed
  2335   2356   ** again.
  2336   2357   **
................................................................................
  2350   2371   
  2351   2372     /* If the VDBE has be run even partially, then transfer the error code
  2352   2373     ** and error message from the VDBE into the main database structure.  But
  2353   2374     ** if the VDBE has just been set to run but has not actually executed any
  2354   2375     ** instructions yet, leave the main database error information unchanged.
  2355   2376     */
  2356   2377     if( p->pc>=0 ){
         2378  +    vdbeInvokeSqllog(p);
  2357   2379       sqlite3VdbeTransferError(p);
  2358   2380       sqlite3DbFree(db, p->zErrMsg);
  2359   2381       p->zErrMsg = 0;
  2360   2382       if( p->runOnlyOnce ) p->expired = 1;
  2361   2383     }else if( p->rc && p->expired ){
  2362   2384       /* The expired flag was set on the VDBE before the first call
  2363   2385       ** to sqlite3_step(). For consistency (since sqlite3_step() was

Changes to test/fts3conf.test.

   132    132       INSERT INTO t1(docid, x) VALUES(1, 'a b c');
   133    133       REPLACE INTO t1(docid, x) VALUES('zero', 'd e f');
   134    134   } {1 {datatype mismatch}}
   135    135   do_execsql_test 2.2.2 { COMMIT }
   136    136   do_execsql_test 2.2.3 { SELECT * FROM t1 } {{a b c} {a b c}}
   137    137   fts3_integrity 2.2.4 db t1
   138    138   
          139  +do_execsql_test 3.1 {
          140  +  CREATE VIRTUAL TABLE t3 USING fts4;
          141  +  REPLACE INTO t3(docid, content) VALUES (1, 'one two');
          142  +  SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'one'
          143  +} {X'0100000002000000'}
          144  +
          145  +do_execsql_test 3.2 {
          146  +  REPLACE INTO t3(docid, content) VALUES (2, 'one two three four');
          147  +  SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'four'
          148  +} {X'0200000003000000'}
          149  +
          150  +do_execsql_test 3.3 {
          151  +  REPLACE INTO t3(docid, content) VALUES (1, 'one two three four five six');
          152  +  SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'six'
          153  +} {X'0200000005000000'}
          154  +
          155  +do_execsql_test 3.4 {
          156  +  UPDATE OR REPLACE t3 SET docid = 2 WHERE docid=1;
          157  +  SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'six'
          158  +} {X'0100000006000000'}
          159  +
          160  +do_execsql_test 3.5 {
          161  +  UPDATE OR REPLACE t3 SET docid = 3 WHERE docid=2;
          162  +  SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'six'
          163  +} {X'0100000006000000'}
          164  +
          165  +do_execsql_test 3.6 {
          166  +  REPLACE INTO t3(docid, content) VALUES (3, 'one two');
          167  +  SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'one'
          168  +} {X'0100000002000000'}
          169  +
          170  +do_execsql_test 3.7 {
          171  +  REPLACE INTO t3(docid, content) VALUES (NULL, 'one two three four');
          172  +  REPLACE INTO t3(docid, content) VALUES (NULL, 'one two three four five six');
          173  +  SELECT docid FROM t3;
          174  +} {3 4 5}
          175  +
          176  +do_execsql_test 3.8 {
          177  +  UPDATE OR REPLACE t3 SET docid = 5, content='three four' WHERE docid = 4;
          178  +  SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'one'
          179  +} {X'0200000002000000'}
          180  +
   139    181   finish_test

Changes to test/wal9.test.

    58     58     COMMIT;
    59     59   } {}
    60     60   
    61     61   # Check file sizes are as expected. The real requirement here is that 
    62     62   # the *shm file is now more than one chunk (>32KiB).
    63     63   do_test 1.3 { file size test.db     } {1024}
    64     64   do_test 1.4 { file size test.db-wal } {15421352}
    65         -do_test 1.5 { file size test.db-shm } {131072}
           65  +do_test 1.5 { expr {[file size test.db-shm]>32768} } {1}
    66     66   
    67     67   do_execsql_test 1.6 { PRAGMA wal_checkpoint } {0 14715 14715}
    68     68   
    69     69   # At this point connection [db2] has mapped the first 32KB of the *shm file
    70     70   # only. Because the entire WAL file has been checkpointed, it is not 
    71     71   # necessary to map any more of the *-shm file to read or write the database
    72     72   # (since all data will be read directly from the db file). 
................................................................................
    83     83         INSERT INTO t VALUES('hello');
    84     84       ROLLBACK;
    85     85     } db2
    86     86   } {}
    87     87   db2 close
    88     88   
    89     89   finish_test
    90         -