Merge recent enhancements from trunk.

FossilOrigin-Name: 73d0fc027ddcc24e55cdc8c54443a96083cc9a29e57c0abe97e8586ff8a7f4c5
This commit is contained in:
drh 2017-07-07 14:26:43 +00:00
commit 4676462f92
37 changed files with 546 additions and 249 deletions

View File

@ -1707,6 +1707,19 @@ static void fts3CursorFinalizeStmt(Fts3Cursor *pCsr){
sqlite3_finalize(pCsr->pStmt);
}
/*
** Free all resources currently held by the cursor passed as the only
** argument.
*/
static void fts3ClearCursor(Fts3Cursor *pCsr){
fts3CursorFinalizeStmt(pCsr);
sqlite3Fts3FreeDeferredTokens(pCsr);
sqlite3_free(pCsr->aDoclist);
sqlite3Fts3MIBufferFree(pCsr->pMIBuffer);
sqlite3Fts3ExprFree(pCsr->pExpr);
memset(&(&pCsr->base)[1], 0, sizeof(Fts3Cursor)-sizeof(sqlite3_vtab_cursor));
}
/*
** Close the cursor. For additional information see the documentation
** on the xClose method of the virtual table interface.
@ -1714,11 +1727,7 @@ static void fts3CursorFinalizeStmt(Fts3Cursor *pCsr){
static int fts3CloseMethod(sqlite3_vtab_cursor *pCursor){
Fts3Cursor *pCsr = (Fts3Cursor *)pCursor;
assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 );
fts3CursorFinalizeStmt(pCsr);
sqlite3Fts3ExprFree(pCsr->pExpr);
sqlite3Fts3FreeDeferredTokens(pCsr);
sqlite3_free(pCsr->aDoclist);
sqlite3Fts3MIBufferFree(pCsr->pMIBuffer);
fts3ClearCursor(pCsr);
assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 );
sqlite3_free(pCsr);
return SQLITE_OK;
@ -3219,11 +3228,7 @@ static int fts3FilterMethod(
assert( iIdx==nVal );
/* In case the cursor has been used before, clear it now. */
fts3CursorFinalizeStmt(pCsr);
sqlite3_free(pCsr->aDoclist);
sqlite3Fts3MIBufferFree(pCsr->pMIBuffer);
sqlite3Fts3ExprFree(pCsr->pExpr);
memset(&pCursor[1], 0, sizeof(Fts3Cursor)-sizeof(sqlite3_vtab_cursor));
fts3ClearCursor(pCsr);
/* Set the lower and upper bounds on docids to return */
pCsr->iMinDocid = fts3DocidRange(pDocidGe, SMALLEST_INT64);
@ -3302,7 +3307,12 @@ static int fts3FilterMethod(
** routine to find out if it has reached the end of a result set.
*/
static int fts3EofMethod(sqlite3_vtab_cursor *pCursor){
return ((Fts3Cursor *)pCursor)->isEof;
Fts3Cursor *pCsr = (Fts3Cursor*)pCursor;
if( pCsr->isEof ){
fts3ClearCursor(pCsr);
pCsr->isEof = 1;
}
return pCsr->isEof;
}
/*

View File

@ -232,6 +232,12 @@ void testDatasourceFree(Datasource *);
void testDatasourceEntry(Datasource *, int, void **, int *, void **, int *);
/* End of test_datasource.c interface.
*************************************************************************/
void testDatasourceFetch(
TestDb *pDb, /* Database handle */
Datasource *pData,
int iKey,
int *pRc /* IN/OUT: Error code */
);
void testWriteDatasource(TestDb *, Datasource *, int, int *);
void testWriteDatasourceRange(TestDb *, Datasource *, int, int, int *);

View File

@ -81,12 +81,12 @@ struct Datatest2 {
** Generate a unique name for the test case pTest with database system
** zSystem.
*/
static char *getName(const char *zSystem, Datatest1 *pTest){
static char *getName(const char *zSystem, int bRecover, Datatest1 *pTest){
char *zRet;
char *zData;
zData = testDatasourceName(&pTest->defn);
zRet = testMallocPrintf("data.%s.%s.%d.%d",
zSystem, zData, pTest->nRow, pTest->nVerify
zRet = testMallocPrintf("data.%s.%s.rec=%d.%d.%d",
zSystem, zData, bRecover, pTest->nRow, pTest->nVerify
);
testFree(zData);
return zRet;
@ -251,8 +251,21 @@ static void printScanCb(
}
#endif
void testReopenRecover(TestDb **ppDb, int *pRc){
if( *pRc==0 ){
const char *zLib = tdb_library_name(*ppDb);
const char *zDflt = tdb_default_db(zLib);
testCopyLsmdb(zDflt, "bak.db");
testClose(ppDb);
testCopyLsmdb("bak.db", zDflt);
*pRc = tdb_open(zLib, 0, 0, ppDb);
}
}
static void doDataTest1(
const char *zSystem, /* Database system to test */
int bRecover,
Datatest1 *p, /* Structure containing test parameters */
int *pRc /* OUT: Error code */
){
@ -277,8 +290,11 @@ static void doDataTest1(
/* Check that the db content is correct. */
testDbContents(pDb, pData, p->nRow, 0, i-1, p->nTest, p->bTestScan, &rc);
/* Close and reopen the database. */
testReopen(&pDb, &rc);
if( bRecover ){
testReopenRecover(&pDb, &rc);
}else{
testReopen(&pDb, &rc);
}
/* Check that the db content is still correct. */
testDbContents(pDb, pData, p->nRow, 0, i-1, p->nTest, p->bTestScan, &rc);
@ -299,7 +315,11 @@ static void doDataTest1(
testDbContents(pDb, pData, p->nRow, i, p->nRow-1,p->nTest,p->bTestScan,&rc);
/* Close and reopen the database. */
testReopen(&pDb, &rc);
if( bRecover ){
testReopenRecover(&pDb, &rc);
}else{
testReopen(&pDb, &rc);
}
/* Check that the db content is still correct. */
testDbContents(pDb, pData, p->nRow, i, p->nRow-1,p->nTest,p->bTestScan,&rc);
@ -339,13 +359,17 @@ void test_data_1(
};
int i;
int bRecover;
for(i=0; *pRc==LSM_OK && i<ArraySize(aTest); i++){
char *zName = getName(zSystem, &aTest[i]);
if( testCaseBegin(pRc, zPattern, "%s", zName) ){
doDataTest1(zSystem, &aTest[i], pRc);
for(bRecover=0; bRecover<2; bRecover++){
if( bRecover==1 && memcmp(zSystem, "lsm", 3) ) break;
for(i=0; *pRc==LSM_OK && i<ArraySize(aTest); i++){
char *zName = getName(zSystem, bRecover, &aTest[i]);
if( testCaseBegin(pRc, zPattern, "%s", zName) ){
doDataTest1(zSystem, bRecover, &aTest[i], pRc);
}
testFree(zName);
}
testFree(zName);
}
}
@ -396,6 +420,7 @@ void testCompareDb(
static void doDataTest2(
const char *zSystem, /* Database system to test */
int bRecover,
Datatest2 *p, /* Structure containing test parameters */
int *pRc /* OUT: Error code */
){
@ -437,7 +462,11 @@ static void doDataTest2(
testFree(pKey1);
testCompareDb(pData, nRange, i, pControl, pDb, &rc);
testReopen(&pDb, &rc);
if( bRecover ){
testReopenRecover(&pDb, &rc);
}else{
testReopen(&pDb, &rc);
}
testCompareDb(pData, nRange, i, pControl, pDb, &rc);
/* Update the progress dots... */
@ -451,12 +480,12 @@ static void doDataTest2(
*pRc = rc;
}
static char *getName2(const char *zSystem, Datatest2 *pTest){
static char *getName2(const char *zSystem, int bRecover, Datatest2 *pTest){
char *zRet;
char *zData;
zData = testDatasourceName(&pTest->defn);
zRet = testMallocPrintf("data2.%s.%s.%d.%d.%d",
zSystem, zData, pTest->nRange, pTest->nWrite, pTest->nIter
zRet = testMallocPrintf("data2.%s.%s.rec=%d.%d.%d.%d",
zSystem, zData, bRecover, pTest->nRange, pTest->nWrite, pTest->nIter
);
testFree(zData);
return zRet;
@ -476,13 +505,17 @@ void test_data_2(
};
int i;
int bRecover;
for(i=0; *pRc==LSM_OK && i<ArraySize(aTest); i++){
char *zName = getName2(zSystem, &aTest[i]);
if( testCaseBegin(pRc, zPattern, "%s", zName) ){
doDataTest2(zSystem, &aTest[i], pRc);
for(bRecover=0; bRecover<2; bRecover++){
if( bRecover==1 && memcmp(zSystem, "lsm", 3) ) break;
for(i=0; *pRc==LSM_OK && i<ArraySize(aTest); i++){
char *zName = getName2(zSystem, bRecover, &aTest[i]);
if( testCaseBegin(pRc, zPattern, "%s", zName) ){
doDataTest2(zSystem, bRecover, &aTest[i], pRc);
}
testFree(zName);
}
testFree(zName);
}
}

View File

@ -242,6 +242,7 @@ static void testCompareCksumLsmdb(
}
}
#if 0 /* not used */
static void testCompareCksumBtdb(
const char *zFile, /* Path to LSM database */
const char *zExpect1, /* Expected checksum 1 */
@ -278,6 +279,7 @@ static void testCompareCksumBtdb(
}
}
}
#endif /* not used */
/* Above this point are reusable test routines. Not clear that they
** should really be in this file.
@ -484,4 +486,3 @@ void do_crash_test(const char *zPattern, int *pRc){
}
}
}

View File

@ -44,6 +44,7 @@ static void doDataTest4(
int i;
int rc = 0;
int iDot = 0;
int bMultiThreaded = 0; /* True for MT LSM database */
int nRecOn3 = (p->nRec / 3);
int iData = 0;
@ -52,7 +53,10 @@ static void doDataTest4(
rc = testControlDb(&pControl);
pDb = testOpen(zSystem, 1, &rc);
pData = testDatasourceNew(&p->defn);
if( rc==0 ) db = tdb_lsm(pDb);
if( rc==0 ){
db = tdb_lsm(pDb);
bMultiThreaded = tdb_lsm_multithread(pDb);
}
testWriteDatasourceRange(pControl, pData, iData, nRecOn3*3, &rc);
testWriteDatasourceRange(pDb, pData, iData, nRecOn3*3, &rc);
@ -71,6 +75,7 @@ static void doDataTest4(
nDone = 0;
rc = lsm_work(db, 1, (1<<30), &nDone);
}while( rc==0 && nDone>0 );
if( bMultiThreaded && rc==LSM_BUSY ) rc = LSM_OK;
#if 0
fprintf(stderr, "lsm_work() done...\n"); fflush(stderr);
#endif

View File

@ -26,7 +26,7 @@ void test_failed(){
static void testSetErrorFunc(int rc, int *pRc, const char *zFile, int iLine){
if( rc ){
*pRc = rc;
printf("FAILED (%s:%d) rc=%d ", zFile, iLine, rc);
fprintf(stderr, "FAILED (%s:%d) rc=%d ", zFile, iLine, rc);
test_failed();
}
}
@ -115,6 +115,7 @@ void testCommit(TestDb *pDb, int iTrans, int *pRc){
testSetError(rc);
}
}
#if 0 /* unused */
static void testRollback(TestDb *pDb, int iTrans, int *pRc){
if( *pRc==0 ){
int rc;
@ -122,6 +123,7 @@ static void testRollback(TestDb *pDb, int iTrans, int *pRc){
testSetError(rc);
}
}
#endif
void testWriteStr(
TestDb *pDb, /* Database handle */
@ -133,10 +135,11 @@ void testWriteStr(
testWrite(pDb, (void *)zKey, strlen(zKey), (void *)zVal, nVal, pRc);
}
#if 0 /* unused */
static void testDeleteStr(TestDb *pDb, const char *zKey, int *pRc){
testDelete(pDb, (void *)zKey, strlen(zKey), pRc);
}
#endif
void testFetchStr(
TestDb *pDb, /* Database handle */
const char *zKey, /* Key to query database for */
@ -343,6 +346,7 @@ void testReopen(TestDb **ppDb, int *pRc){
}
#if 0 /* unused */
static void testSystemSelect(const char *zSys, int *piSel, int *pRc){
if( *pRc==0 ){
struct SysName { const char *zName; } *aName;
@ -359,6 +363,7 @@ static void testSystemSelect(const char *zSys, int *piSel, int *pRc){
free(aName);
}
}
#endif
char *testMallocVPrintf(const char *zFormat, va_list ap){
int nByte;
@ -541,6 +546,7 @@ static void flushPrev(FILE *pOut){
}
}
#if 0 /* unused */
static void do_speed_write_hook2(
void *pCtx,
int bLog,
@ -565,6 +571,7 @@ static void do_speed_write_hook2(
}
}
}
#endif
#define ST_REPEAT 0
#define ST_WRITE 1
@ -662,7 +669,6 @@ int do_speed_test2(int nArg, char **azArg){
if( aOpt[iSel].eVal>=0 ){
aParam[aOpt[iSel].eVal] = atoi(azArg[i+1]);
}else{
int j;
zSystem = azArg[i+1];
bLsm = 0;
#if 0

View File

@ -326,13 +326,13 @@ static void *tmLsmMalloc(int n){ return malloc(n); }
static void tmLsmFree(void *ptr){ free(ptr); }
static void *tmLsmRealloc(void *ptr, int n){ return realloc(ptr, n); }
static void *tmLsmEnvMalloc(lsm_env *p, int n){
static void *tmLsmEnvMalloc(lsm_env *p, size_t n){
return tmMalloc((TmGlobal *)(p->pMemCtx), n);
}
static void tmLsmEnvFree(lsm_env *p, void *ptr){
tmFree((TmGlobal *)(p->pMemCtx), ptr);
}
static void *tmLsmEnvRealloc(lsm_env *p, void *ptr, int n){
static void *tmLsmEnvRealloc(lsm_env *p, void *ptr, size_t n){
return tmRealloc((TmGlobal *)(p->pMemCtx), ptr, n);
}
@ -370,9 +370,9 @@ void testMallocUninstall(lsm_env *pEnv){
TmGlobal *p = (TmGlobal *)pEnv->pMemCtx;
pEnv->pMemCtx = 0;
if( p ){
pEnv->xMalloc = (void *(*)(lsm_env*, int))(p->xSaveMalloc);
pEnv->xRealloc = (void *(*)(lsm_env*, void*, int))(p->xSaveRealloc);
pEnv->xFree = (void (*)(lsm_env*, void*))(p->xSaveFree);
pEnv->xMalloc = p->xSaveMalloc;
pEnv->xRealloc = p->xSaveRealloc;
pEnv->xFree = p->xSaveFree;
p->xDelMutex(p);
tmLsmFree(p);
}

View File

@ -745,6 +745,14 @@ const char *tdb_system_name(int i){
return aLib[i].zName;
}
const char *tdb_default_db(const char *zSys){
int i;
for(i=0; i<ArraySize(aLib); i++){
if( strcmp(aLib[i].zName, zSys)==0 ) return aLib[i].zDefaultDb;
}
return 0;
}
int tdb_open(const char *zLib, const char *zDb, int bClear, TestDb **ppDb){
int i;
int rc = 1;

View File

@ -125,6 +125,7 @@ int tdb_scan(
);
const char *tdb_system_name(int i);
const char *tdb_default_db(const char *zSys);
int tdb_lsm_open(const char *zCfg, const char *zDb, int bClear, TestDb **ppDb);
@ -135,6 +136,12 @@ int tdb_lsm_open(const char *zCfg, const char *zDb, int bClear, TestDb **ppDb);
*/
lsm_db *tdb_lsm(TestDb *pDb);
/*
** Return true if the db passed as an argument is a multi-threaded LSM
** connection.
*/
int tdb_lsm_multithread(TestDb *pDb);
/*
** Return a pointer to the lsm_env object used by all lsm database
** connections initialized as a copy of the object returned by

View File

@ -1051,6 +1051,14 @@ lsm_db *tdb_lsm(TestDb *pDb){
return 0;
}
int tdb_lsm_multithread(TestDb *pDb){
int ret = 0;
if( tdb_lsm(pDb) ){
ret = ((LsmDb*)pDb)->eMode!=LSMTEST_MODE_SINGLETHREAD;
}
return ret;
}
void tdb_lsm_enable_log(TestDb *pDb, int bEnable){
lsm_db *db = tdb_lsm(pDb);
if( db ){

View File

@ -864,7 +864,7 @@ int lsmInfoFreelist(lsm_db *pDb, char **pzOut);
** Functions from file "lsm_log.c".
*/
int lsmLogBegin(lsm_db *pDb);
int lsmLogWrite(lsm_db *, void *, int, void *, int);
int lsmLogWrite(lsm_db *, int, void *, int, void *, int);
int lsmLogCommit(lsm_db *);
void lsmLogEnd(lsm_db *pDb, int bCommit);
void lsmLogTell(lsm_db *, LogMark *);
@ -874,6 +874,10 @@ void lsmLogClose(lsm_db *);
int lsmLogRecover(lsm_db *);
int lsmInfoLogStructure(lsm_db *pDb, char **pzVal);
/* Valid values for the second argument to lsmLogWrite(). */
#define LSM_WRITE 0x06
#define LSM_DELETE 0x08
#define LSM_DRANGE 0x0A
/**************************************************************************
** Functions from file "lsm_shared.c".

View File

@ -1093,7 +1093,7 @@ int lsmCheckpointSaveWorker(lsm_db *pDb, int bFlush){
memcpy(pShm->aSnap1, p, n);
lsmFree(pDb->pEnv, p);
assert( lsmFsIntegrityCheck(pDb) );
/* assert( lsmFsIntegrityCheck(pDb) ); */
return LSM_OK;
}

View File

@ -199,9 +199,13 @@
#define LSM_LOG_WRITE 0x06
#define LSM_LOG_WRITE_CKSUM 0x07
#define LSM_LOG_DELETE 0x08
#define LSM_LOG_DELETE_CKSUM 0x09
#define LSM_LOG_DRANGE 0x0A
#define LSM_LOG_DRANGE_CKSUM 0x0B
/* Require a checksum every 32KB. */
#define LSM_CKSUM_MAXDATA (32*1024)
@ -373,6 +377,7 @@ int lsmLogBegin(lsm_db *pDb){
lsmStringInit(&pNew->buf, pDb->pEnv);
rc = lsmStringExtend(&pNew->buf, 2);
}
pDb->pLogWriter = pNew;
}else{
pNew = pDb->pLogWriter;
assert( (u8 *)(&pNew[1])==(u8 *)(&((&pNew->buf)[1])) );
@ -464,7 +469,7 @@ int lsmLogBegin(lsm_db *pDb){
pNew->jump.iEnd = lastByteOnSector(pNew, pNew->jump.iEnd);
}
pDb->pLogWriter = pNew;
assert( pDb->pLogWriter==pNew );
return rc;
}
@ -653,6 +658,7 @@ static int logFlush(lsm_db *pDb, int eType){
*/
int lsmLogWrite(
lsm_db *pDb, /* Database handle */
int eType,
void *pKey, int nKey, /* Database key to write to log */
void *pVal, int nVal /* Database value (or nVal<0) to write */
){
@ -661,13 +667,19 @@ int lsmLogWrite(
int nReq; /* Bytes of space required in log */
int bCksum = 0; /* True to embed a checksum in this record */
assert( eType==LSM_WRITE || eType==LSM_DELETE || eType==LSM_DRANGE );
assert( LSM_LOG_WRITE==LSM_WRITE );
assert( LSM_LOG_DELETE==LSM_DELETE );
assert( LSM_LOG_DRANGE==LSM_DRANGE );
assert( (eType==LSM_LOG_DELETE)==(nVal<0) );
if( pDb->bUseLog==0 ) return LSM_OK;
pLog = pDb->pLogWriter;
/* Determine how many bytes of space are required, assuming that a checksum
** will be embedded in this record (even though it may not be). */
nReq = 1 + lsmVarintLen32(nKey) + 8 + nKey;
if( nVal>=0 ) nReq += lsmVarintLen32(nVal) + nVal;
if( eType!=LSM_LOG_DELETE ) nReq += lsmVarintLen32(nVal) + nVal;
/* Jump over the jump region if required. Set bCksum to true to tell the
** code below to include a checksum in the record if either (a) writing
@ -687,9 +699,10 @@ int lsmLogWrite(
** DELETE) or 2 (for WRITE) varints. */
assert( LSM_LOG_WRITE_CKSUM == (LSM_LOG_WRITE | 0x0001) );
assert( LSM_LOG_DELETE_CKSUM == (LSM_LOG_DELETE | 0x0001) );
*(a++) = (nVal>=0 ? LSM_LOG_WRITE : LSM_LOG_DELETE) | (u8)bCksum;
assert( LSM_LOG_DRANGE_CKSUM == (LSM_LOG_DRANGE | 0x0001) );
*(a++) = (u8)eType | (u8)bCksum;
a += lsmVarintPut32(a, nKey);
if( nVal>=0 ) a += lsmVarintPut32(a, nVal);
if( eType!=LSM_LOG_DELETE ) a += lsmVarintPut32(a, nVal);
if( bCksum ){
pLog->buf.n = (a - (u8 *)pLog->buf.z);
@ -699,7 +712,7 @@ int lsmLogWrite(
memcpy(a, pKey, nKey);
a += nKey;
if( nVal>=0 ){
if( eType!=LSM_LOG_DELETE ){
memcpy(a, pVal, nVal);
a += nVal;
}
@ -868,12 +881,14 @@ static void logReaderBlob(
}else{
int nCopy = LSM_MIN(nAvail, nReq);
if( nBlob==nReq ){
if( ppBlob ) *ppBlob = (u8 *)pBuf->z;
pBuf->n = 0;
}
rc = lsmStringBinAppend(pBuf, (u8 *)&p->buf.z[p->iBuf], nCopy);
nReq -= nCopy;
p->iBuf += nCopy;
if( nReq==0 && ppBlob ){
*ppBlob = (u8*)pBuf->z;
}
}
}
@ -915,6 +930,7 @@ static void logReaderCksum(LogReader *p, LsmString *pBuf, int *pbEof, int *pRc){
logCksumUnaligned(&p->buf.z[p->iCksumBuf], nCksum, &p->cksum0, &p->cksum1);
p->iCksumBuf = p->iBuf + 8;
logReaderBlob(p, pBuf, 8, &pPtr, pRc);
assert( pPtr || *pRc );
/* Read the checksums from the log file. Set *pbEof if they do not match. */
if( pPtr ){
@ -1002,6 +1018,8 @@ int lsmLogRecover(lsm_db *pDb){
break;
}
case LSM_LOG_DRANGE:
case LSM_LOG_DRANGE_CKSUM:
case LSM_LOG_WRITE:
case LSM_LOG_WRITE_CKSUM: {
int nKey;
@ -1010,7 +1028,7 @@ int lsmLogRecover(lsm_db *pDb){
logReaderVarint(&reader, &buf1, &nKey, &rc);
logReaderVarint(&reader, &buf2, &nVal, &rc);
if( eType==LSM_LOG_WRITE_CKSUM ){
if( eType==LSM_LOG_WRITE_CKSUM || eType==LSM_LOG_DRANGE_CKSUM ){
logReaderCksum(&reader, &buf1, &bEof, &rc);
}else{
bEof = logRequireCksum(&reader, nKey+nVal);
@ -1020,7 +1038,11 @@ int lsmLogRecover(lsm_db *pDb){
logReaderBlob(&reader, &buf1, nKey, 0, &rc);
logReaderBlob(&reader, &buf2, nVal, &aVal, &rc);
if( iPass==1 && rc==LSM_OK ){
rc = lsmTreeInsert(pDb, (u8 *)buf1.z, nKey, aVal, nVal);
if( eType==LSM_LOG_WRITE || eType==LSM_LOG_WRITE_CKSUM ){
rc = lsmTreeInsert(pDb, (u8 *)buf1.z, nKey, aVal, nVal);
}else{
rc = lsmTreeDelete(pDb, (u8 *)buf1.z, nKey, aVal, nVal);
}
}
break;
}

View File

@ -226,7 +226,7 @@ int lsm_close(lsm_db *pDb){
lsmDbDatabaseRelease(pDb);
lsmLogClose(pDb);
lsmFsClose(pDb->pFS);
assert( pDb->mLock==0 );
/* assert( pDb->mLock==0 ); */
/* Invoke any destructors registered for the compression or
** compression factory callbacks. */
@ -669,11 +669,8 @@ static int doWriteOp(
}
if( rc==LSM_OK ){
if( bDeleteRange==0 ){
rc = lsmLogWrite(pDb, (void *)pKey, nKey, (void *)pVal, nVal);
}else{
/* TODO */
}
int eType = (bDeleteRange ? LSM_DRANGE : (nVal>=0?LSM_WRITE:LSM_DELETE));
rc = lsmLogWrite(pDb, eType, (void *)pKey, nKey, (void *)pVal, nVal);
}
lsmSortedSaveTreeCursors(pDb);
@ -923,12 +920,14 @@ int lsm_commit(lsm_db *pDb, int iLevel){
if( iLevel<pDb->nTransOpen ){
if( iLevel==0 ){
int rc2;
/* Commit the transaction to disk. */
if( rc==LSM_OK ) rc = lsmLogCommit(pDb);
if( rc==LSM_OK && pDb->eSafety==LSM_SAFETY_FULL ){
rc = lsmFsSyncLog(pDb->pFS);
}
lsmFinishWriteTrans(pDb, (rc==LSM_OK));
rc2 = lsmFinishWriteTrans(pDb, (rc==LSM_OK));
if( rc==LSM_OK ) rc = rc2;
}
pDb->nTransOpen = iLevel;
}

View File

@ -1952,7 +1952,17 @@ static int seekInLevel(
rtTopic(pPtr->eType), pPtr->pKey, pPtr->nKey,
pLvl->iSplitTopic, pLvl->pSplitKey, pLvl->nSplitKey
);
if( res<0 ) segmentPtrReset(pPtr, LSM_SEGMENTPTR_FREE_THRESHOLD);
if( res<0 ){
if( pPtr->eType & LSM_START_DELETE ){
pPtr->eType &= ~LSM_INSERT;
pPtr->pKey = pLvl->pSplitKey;
pPtr->nKey = pLvl->nSplitKey;
pPtr->pVal = 0;
pPtr->nVal = 0;
}else{
segmentPtrReset(pPtr, LSM_SEGMENTPTR_FREE_THRESHOLD);
}
}
}
if( aPtr[i].pKey ) bHit = 1;
@ -3864,7 +3874,7 @@ static int mergeWorkerData(
int rc = LSM_OK; /* Return code */
int nRem = nWrite; /* Number of bytes still to write */
while( nRem>0 ){
while( rc==LSM_OK && nRem>0 ){
Merge *pMerge = pMW->pLevel->pMerge;
int nCopy; /* Number of bytes to copy */
u8 *aData; /* Pointer to buffer of current output page */
@ -5396,7 +5406,9 @@ int lsmSortedAutoWork(
lsmMCursorFreeCache(pDb);
lsmFreeSnapshot(pDb->pEnv, pDb->pClient);
pDb->pClient = 0;
rc = lsmCheckpointLoad(pDb, 0);
if( rc==LSM_OK ){
rc = lsmCheckpointLoad(pDb, 0);
}
if( rc==LSM_OK ){
rc = lsmCheckpointDeserialize(pDb, 0, pDb->aSnapshot, &pDb->pClient);
}

View File

@ -39,11 +39,9 @@ int lsmStringExtend(LsmString *pStr, int nNew){
lsmFree(pStr->pEnv, pStr->z);
nAlloc = 0;
pStr->n = -1;
pStr->z = 0;
}else{
pStr->nAlloc = nAlloc;
pStr->z = zNew;
}
pStr->nAlloc = nAlloc;
pStr->z = zNew;
}
return (pStr->z ? LSM_OK : LSM_NOMEM_BKPT);
}

View File

@ -1470,6 +1470,7 @@ static int treeInsertEntry(
rc = lsmTreeCursorSeek(&csr, pKey, nKey, &res);
pRes = csrGetKey(&csr, &csr.blob, &rc);
if( rc!=LSM_OK ) return rc;
assert( pRes );
if( flags==LSM_START_DELETE ){
/* When inserting a start-delete-range entry, if the key that
@ -1944,12 +1945,11 @@ void lsmTreeCursorReset(TreeCursor *pCsr){
}
#ifndef NDEBUG
static int treeCsrCompare(TreeCursor *pCsr, void *pKey, int nKey){
static int treeCsrCompare(TreeCursor *pCsr, void *pKey, int nKey, int *pRc){
TreeKey *p;
int cmp = 0;
int rc = LSM_OK;
assert( pCsr->iNode>=0 );
p = csrGetKey(pCsr, &pCsr->blob, &rc);
p = csrGetKey(pCsr, &pCsr->blob, pRc);
if( p ){
cmp = treeKeycmp(TKV_KEY(p), p->nKey, pKey, nKey);
}
@ -2051,8 +2051,8 @@ int lsmTreeCursorSeek(TreeCursor *pCsr, void *pKey, int nKey, int *pRes){
/* assert() that *pRes has been set properly */
#ifndef NDEBUG
if( rc==LSM_OK && lsmTreeCursorValid(pCsr) ){
int cmp = treeCsrCompare(pCsr, pKey, nKey);
assert( *pRes==cmp || (*pRes ^ cmp)>0 );
int cmp = treeCsrCompare(pCsr, pKey, nKey, &rc);
assert( rc!=LSM_OK || *pRes==cmp || (*pRes ^ cmp)>0 );
}
#endif

View File

@ -459,7 +459,10 @@ static int lsm1Column(
if( aVal[0]==SQLITE_INTEGER ){
sqlite3_result_int64(ctx, *(sqlite3_int64*)&x);
}else{
sqlite3_result_double(ctx, *(double*)&x);
double r;
assert( sizeof(r)==sizeof(x) );
memcpy(&r, &x, sizeof(r));
sqlite3_result_double(ctx, r);
}
break;
}
@ -666,7 +669,9 @@ int lsm1Update(
if( eType==SQLITE_INTEGER ){
*(sqlite3_int64*)&x = sqlite3_value_int64(pValue);
}else{
*(double*)&x = sqlite3_value_double(pValue);
double r = sqlite3_value_double(pValue);
assert( sizeof(r)==sizeof(x) );
memcpy(&x, &r, sizeof(r));
}
for(i=8; x>0 && i>=1; i--){
aVal[i] = x & 0xff;

View File

@ -3437,6 +3437,10 @@ static int getNodeSize(
rc = getIntFromStmt(db, zSql, &pRtree->iNodeSize);
if( rc!=SQLITE_OK ){
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
}else if( pRtree->iNodeSize<(512-64) ){
rc = SQLITE_CORRUPT;
*pzErr = sqlite3_mprintf("undersize RTree blobs in \"%q_node\"",
pRtree->zName);
}
}

View File

@ -216,5 +216,18 @@ do_corruption_tests rtreeA-6.1 {
2 "UPDATE t1 SET x1=x1+1, x2=x2+1"
}
#-------------------------------------------------------------------------
# Truncated blobs in the _node table.
#
create_t1
populate_t1
sqlite3 db test.db
do_execsql_test rtreeA-7.100 {
UPDATE t1_node SET data=x'' WHERE rowid=1;
} {}
do_catchsql_test rtreeA-7.110 {
SELECT * FROM t1 WHERE x1>0 AND x1<100 AND x2>0 AND x2<100;
} {1 {undersize RTree blobs in "t1_node"}}
finish_test

View File

@ -474,7 +474,7 @@ TESTOPTS = --verbose=file --output=test-out.txt
# Extra compiler options for various shell tools
#
SHELL_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS5
SHELL_OPT += -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS5
SHELL_OPT += -DSQLITE_ENABLE_EXPLAIN_COMMENTS
SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB

View File

@ -1,5 +1,5 @@
C Update\sthe\scarray()\sand\sremember()\sextension\sfunctions\sso\sthat\sthey\suser\nthe\snew\ssqlite3_value_pointer()\sinterface.
D 2017-06-30T23:46:16.781
C Merge\srecent\senhancements\sfrom\strunk.
D 2017-07-07T14:26:43.473
F Makefile.in 081e48dfe7f995d57ce1a88ddf4d2917b4349158648a6cd45b42beae30de3a12
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc 4ebb1d257cac7fb1bcb4ba59278416d410ff1c4bf59447a9c37a415f3516056a
@ -70,7 +70,7 @@ F ext/fts3/README.content fdc666a70d5257a64fee209f97cf89e0e6e32b51
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
F ext/fts3/README.tokenizers e0a8b81383ea60d0334d274fadf305ea14a8c314
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
F ext/fts3/fts3.c 6c5543ce771db11d27793fb696564ef5e977116671353a0d5c22056aba73055e
F ext/fts3/fts3.c b47d3ba5c00f550d1f436e62017264fed818665819471b4699aac9527906459b
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
F ext/fts3/fts3Int.h eb2502000148e80913b965db3e59f29251266d0a
F ext/fts3/fts3_aux.c 9edc3655fcb287f0467d0a4b886a01c6185fe9f1
@ -212,44 +212,44 @@ F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
F ext/lsm1/Makefile a2ea4975162be8932b5efa727080f4982715d34c32035d9eb7a015ae78404981
F ext/lsm1/Makefile.msc c8140509750fb207f0e984991bc426e91a11adb2f6434f218c52103b9d33a8e1
F ext/lsm1/lsm-test/README 87ea529d2abe615e856d4714bfe8bb185e6c2771b8612aa6298588b7b43e6f86
F ext/lsm1/lsm-test/lsmtest.h ba9c3cdd4dee660f14de8fe0a5b8c36d72bb5524730f0ce7641aa08f0ef56da5
F ext/lsm1/lsm-test/lsmtest1.c 27c3cf6512514b25a145154ae4e54d053d883b2f7f52ed214747b5ebaceedd3e
F ext/lsm1/lsm-test/lsmtest2.c 385efd49f3411bb2c8e0f9ffbd4f87450d5ac368aeee62d509d2c0ce10e4215b
F ext/lsm1/lsm-test/lsmtest.h 346295688c4b304689950f10e4dcd4640321f3c860112b72cb0691ca075b6a71
F ext/lsm1/lsm-test/lsmtest1.c 2570b0e21e854d3d079dc04a535ce58abe50ed512da23117ab95b01fecdb90a0
F ext/lsm1/lsm-test/lsmtest2.c 188b09aec776516aeedcfd13b9c6faf85ba16b3671a0897a2c740ee00a5dc4f8
F ext/lsm1/lsm-test/lsmtest3.c 9ab87528a36dbf4a61d7c8ad954f5ee368c0878c127b84b942b2e2abe522de26
F ext/lsm1/lsm-test/lsmtest4.c d258d6a245db5d8eaede096e2368d23f859c5e92c80ab9122463f708514fe10c
F ext/lsm1/lsm-test/lsmtest5.c 8d5242a0f870d65eeada191c8945781fed9cb8ece3886573790ebd373b62dac5
F ext/lsm1/lsm-test/lsmtest6.c 1f21509ea5d2b28b74539c2a70b8001619d0713091511067278f57871f4b753a
F ext/lsm1/lsm-test/lsmtest7.c 7a917455a0f956a8ed3f44f5c9387ec0ea6627714874464cc3fa5c5a9cabb2f2
F ext/lsm1/lsm-test/lsmtest8.c b87a1279b0cfbb39df1fff50074696fbf5d83822349f65706fab6d618a7a52fa
F ext/lsm1/lsm-test/lsmtest9.c 88245ce0fdd01678be548100e584cacdacab90208624223aac9029e4f90535fe
F ext/lsm1/lsm-test/lsmtest9.c dd1a0ebf41134933a744d1e00e60429a2a21fc50d587ae7dd6bdb6e96d805bdc
F ext/lsm1/lsm-test/lsmtest_bt.c d70d9a9be5eef9360af1251dd083948d74fd30137a08f61bef995f7ac04e037f
F ext/lsm1/lsm-test/lsmtest_datasource.c 5d770be191d0ca51315926723009b2c25c0b4b8136840494ef710ac324aa916c
F ext/lsm1/lsm-test/lsmtest_func.c 159aa401bc8032bfa3d8cf2977bd687abebab880255895a5eb45770d626fa38d
F ext/lsm1/lsm-test/lsmtest_io.c ba678e052f497b4c2ff41d47672a1f2a02f495d14083845ee66e0bda678f5b80
F ext/lsm1/lsm-test/lsmtest_main.c dd062fe16d778aaaade3147199749ba9d8743e1408d249823ee9ecf3c24b5466
F ext/lsm1/lsm-test/lsmtest_mem.c 996b1e76cc876e8d765182a2f14159b1acbf56cbf86d286173e13e970b79a945
F ext/lsm1/lsm-test/lsmtest_tdb.c d85694a9e5cd3908cb3e10bb5cb5d6a47ad101adb9fb477ca61f1e3725253b06
F ext/lsm1/lsm-test/lsmtest_tdb.h de1ee8c71a7ef61d964e40e057cffea387d7b58a51d95905ab909937d24e4a91
F ext/lsm1/lsm-test/lsmtest_main.c f1d18e3a3e9315ec4198901a11c9d2ec6cb96d1a40089fd60b6a64e0b6b8db35
F ext/lsm1/lsm-test/lsmtest_mem.c c2980abdbc5024628d10910acb703354f2606b4a6f9624679da4e9a56bcee3e9
F ext/lsm1/lsm-test/lsmtest_tdb.c e46c3f44880d45fd444daf2b2a53bca7a64f9df3f6480cbb1b47a039cc95626a
F ext/lsm1/lsm-test/lsmtest_tdb.h 8733eee249b12956a9df8322994b43d19bd8c02ad2e8b0bb5164db4d6ccc1735
F ext/lsm1/lsm-test/lsmtest_tdb2.cc 99ea7f2dd9c7536c8fb9bdd329e4cfeb76899f3ddf6f48bdd3926e016922b715
F ext/lsm1/lsm-test/lsmtest_tdb3.c 105ef644ad03c8d7f21f8d1f6514adaf30a7c26f4e21cccb3874b70a14985041
F ext/lsm1/lsm-test/lsmtest_tdb3.c 91b7f16b7cf7d883552bcf5301c1ce59396d7c3ec73fb7e2c5f673341dfbd0d4
F ext/lsm1/lsm-test/lsmtest_tdb4.c 47e8bb5eba266472d690fb8264f1855ebdba0ae5a0e541e35fcda61ebf1d277f
F ext/lsm1/lsm-test/lsmtest_util.c 241622db5a332a09c8e6e7606b617d288a37b557f7d3bce0bb97809f67cc2806
F ext/lsm1/lsm-test/lsmtest_win32.c 5605aac3bf3852dcc2509fb1d097f5f11556418c1cc9cf0fdd09f9af53c97fb4
F ext/lsm1/lsm.h 0f6f64ff071471cb87bf98beb8386566f30ea001
F ext/lsm1/lsmInt.h b5d6d073aa5d233614cf4d97d81ba313e9f2c50cfaf12952f7efd9cd945bcd04
F ext/lsm1/lsm_ckpt.c 239a8442693f1de6a06c9136a235757ab63f5a772ff44e1e81f00d71cc96151e
F ext/lsm1/lsmInt.h 68945f00c4fc97a5c82bd285a15d0baacd0019cf2e0b7d535759f000459462e1
F ext/lsm1/lsm_ckpt.c 6ab5f08f60f802601eef0d2bad968d8f3729b908f88131e72311b2c2deaa7734
F ext/lsm1/lsm_file.c fc95548f8cf8e47fda4120215d2c1fc22dfa85e09294e5656a99a846dc80a62b
F ext/lsm1/lsm_log.c 5b3e855fcfb85de9fb86fcbf65696cc6886d3231
F ext/lsm1/lsm_main.c f52eada2910f8a57bd4cafcee39c6c375f6b7ed8
F ext/lsm1/lsm_log.c 8308714659b9fe4a995c239528520c57d26a03baf1d1c973967493a089a79cc6
F ext/lsm1/lsm_main.c 15e73ccdafdd44ddeefc29e332079d88ba8f00c12c797b3c2b63d3171b5afce8
F ext/lsm1/lsm_mem.c 4c51ea9fa285ee6e35301b33491642d071740a0a
F ext/lsm1/lsm_mutex.c 378edf0a2b142b4f7640ee982df06d50b98788ea
F ext/lsm1/lsm_shared.c 54cc3a5157c6abd77f7d3ae60708b9f7bf022b3c
F ext/lsm1/lsm_sorted.c 62cc605a66cf8e0e6ab3593281c2476a787fc4b2013c618dd17568d18c730070
F ext/lsm1/lsm_str.c 77ebdd5040ddf267a6f724d4c83132d2dce8a226
F ext/lsm1/lsm_tree.c 5d9fb2bc58a1a70c75126bd8d7198f7b627e165b
F ext/lsm1/lsm_sorted.c 9bc5251a54a5cb24c2f003c10595fa81ffc7178c4f200c6b0f83d50a2272bb1d
F ext/lsm1/lsm_str.c 65e361b488c87b10bf3e5c0070b14ffc602cf84f094880bece77bbf6678bca82
F ext/lsm1/lsm_tree.c 53b657439e0fcb1117b0559ad3567ac417f81f2ed0fff9bab79948a00ea3cacb
F ext/lsm1/lsm_unix.c 57361bcf5b1a1a028f5d66571ee490e9064d2cfb145a2cc9e5ddade467bb551b
F ext/lsm1/lsm_varint.c b19ae9bd26b5a1e8402fb8a564b25d9542338a41
F ext/lsm1/lsm_vtab.c fff303ce03168eca9e333add3c1429b3471674b0
F ext/lsm1/lsm_vtab.c 812b74a9a7539e8cab49761591ffddc1b3580735fac5d638826c8d2be95ff38b
F ext/lsm1/lsm_win32.c 69eb9fd25197432b084037efd69b365d8182ab1e4372a9c45a9c47e542105c5c
F ext/misc/README.md 8e008c8d2b02e09096b31dfba033253ac27c6c06a18aa5826e299fa7601d90b2
F ext/misc/amatch.c 6db4607cb17c54b853a2d7c7c36046d004853f65b9b733e6f019d543d5dfae87
@ -317,7 +317,7 @@ F ext/rbu/sqlite3rbu.c d1438580a451eebda3bfd42ef69b677512f00125285e0e4e789b6131a
F ext/rbu/sqlite3rbu.h fc25e1fcd99b5c6d32b1b5b1c73122632e873ac89bd0be9bf646db362b7ce02c
F ext/rbu/test_rbu.c ec18cfc69a104309df23c359e3c80306c9a6bdd1d2c53c8b70ae158e9832dcd6
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
F ext/rtree/rtree.c 9c55ff738ac3cd466f2eb23a91fb9bd6bf882ec30fed567066a0d95a6c757605
F ext/rtree/rtree.c c5886d4ba7e7c66d0f9ee0b788d5532f8537ca04db19cec7f2f64dcf46e9be37
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
F ext/rtree/rtree1.test d5f0ba215b3bd1d05269ada86e74073b8445852aa0d33a63e10ec63a09c39473
F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba
@ -328,7 +328,7 @@ F ext/rtree/rtree6.test 773a90db2dce6a8353dd0d5b64bca69b29761196
F ext/rtree/rtree7.test 1fa710b9e6bf997a0c1a537b81be7bb6fded1971
F ext/rtree/rtree8.test db79c812f9e4a11f9b1f3f9934007884610a713a
F ext/rtree/rtree9.test b5eb13849545dfd271a54ff16784cb00d8792aea
F ext/rtree/rtreeA.test ac8b503931f2f397cc3c3303354e1e085dcadb86
F ext/rtree/rtreeA.test e25d76c1701f8591e7a0b6de8224d5dbc1418c562654c7240e6f33f37b1e36f7
F ext/rtree/rtreeB.test c85f9ce78766c4e68b8b89fbf2979ee9cfa82b4e
F ext/rtree/rtreeC.test c0a9c67f2efa98b6fae12acb8a28348d231a481d
F ext/rtree/rtreeD.test bdfaaf26df8b4eea7364039aca9150bc1e1f8825
@ -372,7 +372,7 @@ F ext/userauth/userauth.c 3410be31283abba70255d71fd24734e017a4497f
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
F main.mk b57f019e6cd9d8770b019726c544098fe38f3b5db997d2af739352bbd7c7a14c
F main.mk 0288de0e6b44c2fa709b354d4fab5bce423259cc1653c35305c6e50d23ec561a
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
@ -394,19 +394,19 @@ F src/btmutex.c 0e9ce2d56159b89b9bc8e197e023ee11e39ff8ca
F src/btree.c 00579ff9c2831d6f98cc993f8f2a34c0ff996e89b3cd2f27928f75796bc3a58a
F src/btree.h 3edc5329bc59534d2d15b4f069a9f54b779a7e51289e98fa481ae3c0e526a5ca
F src/btreeInt.h a392d353104b4add58b4a59cb185f5d5693dde832c565b77d8d4c343ed98f610
F src/build.c b24e0889ba18ba0e93e03e2ef5c9f1a2ca043d77c5abbd3d333858a76b795da3
F src/callback.c 2e76147783386374bf01b227f752c81ec872d730
F src/build.c 74108007d286232fb4290464ee5452fa860c26215f8caa0e6c7cbf69a6fafe8f
F src/callback.c 8e14b60d1ed1c87c02cb5f121ecda99224f2aea6524a77ee6f72c9b5c7110f84
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
F src/ctime.c 928954802b1397d9fb1378c7eb702c94b4735bbab1d5793e21b6a77734f56a1b
F src/date.c cc42a41c7422389860d40419a5e3bce5eaf6e7835c3ba2677751dc653550a5c7
F src/dbstat.c 19ee7a4e89979d4df8e44cfac7a8f905ec89b77d
F src/delete.c 3213547e97b676c6fa79948b7a9ede4801ea04a01a2043241deafedf132ecf5d
F src/expr.c cc024ddd19aa37b6672caedab90e2a5ec69a4a1a97da94c2f1a0bd81cf0cd922
F src/expr.c f3f0f7a1a8f91e980244152e9e0263144a9db862e715a80c70422faa2fde4f2f
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c 5ff2c895fe087756d8085dc1a9bc229b5670e2a65c3929dd87c71e43649af333
F src/func.c 9d52522cc8ae7f5cdadfe14594262f1618bc1f86083c4cd6da861b4cf5af6174
F src/func.c 7647140a8624c66cc6e34bdf8005a92390253d6272e87c7901dc8065b563d435
F src/global.c 8a6ab6b4d91effb96ffa81b39f0d70c862abca157f8aaa194600a4a8b7923344
F src/hash.c 63d0ee752a3b92d4695b2b1f5259c4621b2cfebd
F src/hash.c a12580e143f10301ed5166ea4964ae2853d3905a511d4e0c44497245c7ce1f7a
F src/hash.h ab34c5c54a9e9de2e790b24349ba5aab3dbb4fd4
F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
@ -437,7 +437,7 @@ F src/os_win.c 2a6c73eef01c51a048cc4ddccd57f981afbec18a
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
F src/pager.c 14f6982c470c05b8e85575c69e9c1712010602e20400f8670d8699e21283e0e4
F src/pager.h f2a99646c5533ffe11afa43e9e0bea74054e4efa
F src/parse.y b13c9fc83cb634daf7fd5fef89127e8eafdf4904ab9a168d3e1862c5a3c7ae22
F src/parse.y 71bf06b02f567232deabe258641b03e833e93c4dee61a120765ad74c13e7faec
F src/pcache.c 62835bed959e2914edd26afadfecce29ece0e870
F src/pcache.h 521bb9610d38ef17a3cc9b5ddafd4546c2ea67fa3d0e464823d73c2a28d50e11
F src/pcache1.c 1195a21fe28e223e024f900b2011e80df53793f0356a24caace4188b098540dc
@ -446,14 +446,14 @@ F src/pragma.h 99d3df4a3d2f12c5227ad403f767334910e6356325b6d155a9a99b4037093460
F src/prepare.c 4b84ae7458febe1df3e04ae62ba56abc851f771340e460d14426e6802c5615f4
F src/printf.c 8757834f1b54dae512fb25eb1acc8e94a0d15dd2290b58f2563f65973265adb2
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
F src/resolve.c d1e69759e7a79c156c692793f5d16f82f9a60ce5e82efd95e4374b2423034946
F src/resolve.c 6aa1fb1212e601f65b983ee1215d69a591986c8f97a3805c425c625a53839539
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
F src/select.c 741937503c74d85e64828b63d5a4219d3cfce480a717efef635839606001b1ba
F src/select.c c9f7b7196e196e93979665680d055a789938b8e025556097bf484b184c0dd576
F src/shell.c a2b148e4ca8eb81b96e1050207c83d4a16ea6bf9182374faee4dd2a43628c291
F src/sqlite.h.in e1db5dd6c7058352f0853a789a1c5822a83c32450f0c30fa83dd74169e1d2e61
F src/sqlite.h.in ed59e2ea714cb04d25cabce9aa7a684676253be9692cb14c9e43c039fabede51
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 58fd0676d3111d02e62e5a35992a7d3da5d3f88753acc174f2d37b774fbbdd28
F src/sqliteInt.h 37f1a9a3266aa7b11126585314cd98cf11ba6f174b1244de2221270107ea754d
F src/sqliteInt.h 7a7cd6f682471cce4afe64216f71fd64c622712aeb9d947c33c38337a7cf19a9
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
F src/status.c a9e66593dfb28a9e746cba7153f84d49c1ddc4b1
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
@ -528,8 +528,8 @@ F src/vtab.c 35b9bdc2b41de32a417141d12097bcc4e29a77ed7cdb8f836d1d2305d946b61b
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c 40c543f0a2195d1b0dc88ef12142bea690009344
F src/wal.h 06b2a0b599cc0f53ea97f497cf8c6b758c999f71
F src/walker.c d46044e7a5842560dfe7122d93ff5145dd4a96f4d0bf5ba5910a7731b8c01e79
F src/where.c 715b84912bf85d833ff558d6de51c0d0427483c1f5efe1bb6818d4e683f4869e
F src/walker.c a7ca64ce08a83a20d32186fbe06bca9234e348cfcf07959ee322fdc3e8a6173a
F src/where.c e7cc80943459ade4ccaeb5c7c10f8a0db8b797e0b0f2509de7efc557b76bf7b6
F src/whereInt.h 2a4b634d63ce488b46d4b0da8f2eaa8f9aeab202bc25ef76f007de5e3fba1f20
F src/wherecode.c f17f5d51e372168db51af637e265aa5e80f99fcc81bfead96b66e71a7732bc62
F src/whereexpr.c fa51927cc6830b9d3155cafa4e589452ec023fe313a56550d2079dca6c52fbd8
@ -1554,14 +1554,14 @@ F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
F tool/kvtest-speed.sh 4761a9c4b3530907562314d7757995787f7aef8f
F tool/lemon.c 5a04dff28578a67415cea5bf981b893c50cebfdd4388fb21254d1892525edfd8
F tool/lempar.c f0dc07c2838febff4c34244651a6932fceb523065e6fe79bacfaa93019cc8cca
F tool/lempar.c 10579a61dc2290182725e7abdefe311dd8b521a8f7f0aabbfc571e9012a09eaf
F tool/libvers.c caafc3b689638a1d88d44bc5f526c2278760d9b9
F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862
F tool/logest.c 11346aa019e2e77a00902aa7d0cabd27bd2e8cca
F tool/max-limits.c cbb635fbb37ae4d05f240bfb5b5270bb63c54439
F tool/mkautoconfamal.sh e855df211ecbcc7131dee817110ff386cfb112f7
F tool/mkctimec.tcl dd183b73ae1c28249669741c250525f0407e579a70482371668fd5f130d9feb3
F tool/mkkeywordhash.c f7f3b342211ac6a14258b9726d5b97cf4f548f22
F tool/mkkeywordhash.c 2e852ac0dfdc5af18886dc1ce7e9676d11714ae3df0a282dc7d90b3a0fe2033c
F tool/mkmsvcmin.tcl cbd93f1cfa3a0a9ae56fc958510aa3fc3ac65e29cb111716199e3d0e66eefaa4
F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c
F tool/mkopcodeh.tcl a01d2c1d8a6205b03fc635adf3735b4c523befd3
@ -1628,7 +1628,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P d9f4a831ba957ead3890b36d0e33e30cfa4c79b7de6400e623b9746a0a5a02d0
R b4c2909e137aa3ef17d38c2e54e31341
P a99fa94db7185b8eaf3c9b184cb1479f8b3d5781f71f1717a4b3f2dd1d184fe4 aacbb9a461fdb34c7f9c8ce348e44c3e96c93334f210d438d92bfac1794dc686
R de3235313da2edf0ec9dde1456ad1cbb
U drh
Z 8bdfe5f6d40ad5cfb9816549ee2c5181
Z 209bf2cfeb4fa55eedc874c34ea72181

View File

@ -1 +1 @@
a99fa94db7185b8eaf3c9b184cb1479f8b3d5781f71f1717a4b3f2dd1d184fe4
73d0fc027ddcc24e55cdc8c54443a96083cc9a29e57c0abe97e8586ff8a7f4c5

View File

@ -3772,12 +3772,12 @@ SrcList *sqlite3SrcListAppend(
pDatabase = 0;
}
if( pDatabase ){
Token *pTemp = pDatabase;
pDatabase = pTable;
pTable = pTemp;
pItem->zName = sqlite3NameFromToken(db, pDatabase);
pItem->zDatabase = sqlite3NameFromToken(db, pTable);
}else{
pItem->zName = sqlite3NameFromToken(db, pTable);
pItem->zDatabase = 0;
}
pItem->zName = sqlite3NameFromToken(db, pTable);
pItem->zDatabase = sqlite3NameFromToken(db, pDatabase);
return pList;
}
@ -3966,36 +3966,25 @@ void sqlite3BeginTransaction(Parse *pParse, int type){
}
/*
** Generate VDBE code for a COMMIT statement.
** Generate VDBE code for a COMMIT or ROLLBACK statement.
** Code for ROLLBACK is generated if eType==TK_ROLLBACK. Otherwise
** code is generated for a COMMIT.
*/
void sqlite3CommitTransaction(Parse *pParse){
void sqlite3EndTransaction(Parse *pParse, int eType){
Vdbe *v;
int isRollback;
assert( pParse!=0 );
assert( pParse->db!=0 );
if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "COMMIT", 0, 0) ){
assert( eType==TK_COMMIT || eType==TK_END || eType==TK_ROLLBACK );
isRollback = eType==TK_ROLLBACK;
if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION,
isRollback ? "ROLLBACK" : "COMMIT", 0, 0) ){
return;
}
v = sqlite3GetVdbe(pParse);
if( v ){
sqlite3VdbeAddOp1(v, OP_AutoCommit, 1);
}
}
/*
** Generate VDBE code for a ROLLBACK statement.
*/
void sqlite3RollbackTransaction(Parse *pParse){
Vdbe *v;
assert( pParse!=0 );
assert( pParse->db!=0 );
if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "ROLLBACK", 0, 0) ){
return;
}
v = sqlite3GetVdbe(pParse);
if( v ){
sqlite3VdbeAddOp2(v, OP_AutoCommit, 1, 1);
sqlite3VdbeAddOp2(v, OP_AutoCommit, 1, isRollback);
}
}

View File

@ -121,7 +121,7 @@ CollSeq *sqlite3GetCollSeq(
** from the main database is substituted, if one is available.
*/
int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){
if( pColl ){
if( pColl && pColl->xCmp==0 ){
const char *zName = pColl->zName;
sqlite3 *db = pParse->db;
CollSeq *p = sqlite3GetCollSeq(pParse, ENC(db), pColl, zName);
@ -157,8 +157,8 @@ static CollSeq *findCollSeqEntry(
pColl = sqlite3HashFind(&db->aCollSeq, zName);
if( 0==pColl && create ){
int nName = sqlite3Strlen30(zName);
pColl = sqlite3DbMallocZero(db, 3*sizeof(*pColl) + nName + 1);
int nName = sqlite3Strlen30(zName) + 1;
pColl = sqlite3DbMallocZero(db, 3*sizeof(*pColl) + nName);
if( pColl ){
CollSeq *pDel = 0;
pColl[0].zName = (char*)&pColl[3];
@ -168,7 +168,6 @@ static CollSeq *findCollSeqEntry(
pColl[2].zName = (char*)&pColl[3];
pColl[2].enc = SQLITE_UTF16BE;
memcpy(pColl[0].zName, zName, nName);
pColl[0].zName[nName] = 0;
pDel = sqlite3HashInsert(&db->aCollSeq, pColl[0].zName, pColl);
/* If a malloc() failure occurred in sqlite3HashInsert(), it will
@ -308,7 +307,8 @@ void sqlite3InsertBuiltinFuncs(
FuncDef *pOther;
const char *zName = aDef[i].zName;
int nName = sqlite3Strlen30(zName);
int h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % SQLITE_FUNC_HASH_SZ;
int h = (zName[0] + nName) % SQLITE_FUNC_HASH_SZ;
assert( zName[0]>='a' && zName[0]<='z' );
pOther = functionSearch(h, zName);
if( pOther ){
assert( pOther!=&aDef[i] && pOther->pNext!=&aDef[i] );

View File

@ -744,7 +744,7 @@ Expr *sqlite3ExprAlloc(
pNew->iAgg = -1;
if( pToken ){
if( nExtra==0 ){
pNew->flags |= EP_IntValue;
pNew->flags |= EP_IntValue|EP_Leaf;
pNew->u.iValue = iValue;
}else{
pNew->u.zToken = (char*)&pNew[1];
@ -1025,8 +1025,9 @@ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){
/* The Expr.x union is never used at the same time as Expr.pRight */
assert( p->x.pList==0 || p->pRight==0 );
if( p->pLeft && p->op!=TK_SELECT_COLUMN ) sqlite3ExprDeleteNN(db, p->pLeft);
sqlite3ExprDelete(db, p->pRight);
if( ExprHasProperty(p, EP_xIsSelect) ){
if( p->pRight ){
sqlite3ExprDeleteNN(db, p->pRight);
}else if( ExprHasProperty(p, EP_xIsSelect) ){
sqlite3SelectDelete(db, p->x.pSelect);
}else{
sqlite3ExprListDelete(db, p->x.pList);

View File

@ -76,16 +76,16 @@ static void typeofFunc(
int NotUsed,
sqlite3_value **argv
){
const char *z = 0;
static const char *azType[] = { "integer", "real", "text", "blob", "null" };
int i = sqlite3_value_type(argv[0]) - 1;
UNUSED_PARAMETER(NotUsed);
switch( sqlite3_value_type(argv[0]) ){
case SQLITE_INTEGER: z = "integer"; break;
case SQLITE_TEXT: z = "text"; break;
case SQLITE_FLOAT: z = "real"; break;
case SQLITE_BLOB: z = "blob"; break;
default: z = "null"; break;
}
sqlite3_result_text(context, z, -1, SQLITE_STATIC);
assert( i>=0 && i<ArraySize(azType) );
assert( SQLITE_INTEGER==1 );
assert( SQLITE_FLOAT==2 );
assert( SQLITE_TEXT==3 );
assert( SQLITE_BLOB==4 );
assert( SQLITE_NULL==5 );
sqlite3_result_text(context, azType[i], -1, SQLITE_STATIC);
}

View File

@ -140,8 +140,9 @@ static int rehash(Hash *pH, unsigned int new_size){
}
/* This function (for internal use only) locates an element in an
** hash table that matches the given key. The hash for this key is
** also computed and returned in the *pH parameter.
** hash table that matches the given key. If no element is found,
** a pointer to a static null element with HashElem.data==0 is returned.
** If pH is not NULL, then the hash for this key is written to *pH.
*/
static HashElem *findElementWithHash(
const Hash *pH, /* The pH to be searched */
@ -151,6 +152,7 @@ static HashElem *findElementWithHash(
HashElem *elem; /* Used to loop thru the element list */
int count; /* Number of elements left to test */
unsigned int h; /* The computed hash */
static HashElem nullElement = { 0, 0, 0, 0 };
if( pH->ht ){ /*OPTIMIZATION-IF-TRUE*/
struct _ht *pEntry;
@ -163,7 +165,7 @@ static HashElem *findElementWithHash(
elem = pH->first;
count = pH->count;
}
*pHash = h;
if( pHash ) *pHash = h;
while( count-- ){
assert( elem!=0 );
if( sqlite3StrICmp(elem->pKey,pKey)==0 ){
@ -171,7 +173,7 @@ static HashElem *findElementWithHash(
}
elem = elem->next;
}
return 0;
return &nullElement;
}
/* Remove a single entry from the hash table given a pointer to that
@ -213,13 +215,9 @@ static void removeElementGivenHash(
** found, or NULL if there is no match.
*/
void *sqlite3HashFind(const Hash *pH, const char *pKey){
HashElem *elem; /* The element that matches key */
unsigned int h; /* A hash on key */
assert( pH!=0 );
assert( pKey!=0 );
elem = findElementWithHash(pH, pKey, &h);
return elem ? elem->data : 0;
return findElementWithHash(pH, pKey, 0)->data;
}
/* Insert an element into the hash table pH. The key is pKey
@ -244,7 +242,7 @@ void *sqlite3HashInsert(Hash *pH, const char *pKey, void *data){
assert( pH!=0 );
assert( pKey!=0 );
elem = findElementWithHash(pH,pKey,&h);
if( elem ){
if( elem->data ){
void *old_data = elem->data;
if( data==0 ){
removeElementGivenHash(pH,elem,h);

View File

@ -140,9 +140,8 @@ transtype(A) ::= . {A = TK_DEFERRED;}
transtype(A) ::= DEFERRED(X). {A = @X; /*A-overwrites-X*/}
transtype(A) ::= IMMEDIATE(X). {A = @X; /*A-overwrites-X*/}
transtype(A) ::= EXCLUSIVE(X). {A = @X; /*A-overwrites-X*/}
cmd ::= COMMIT trans_opt. {sqlite3CommitTransaction(pParse);}
cmd ::= END trans_opt. {sqlite3CommitTransaction(pParse);}
cmd ::= ROLLBACK trans_opt. {sqlite3RollbackTransaction(pParse);}
cmd ::= COMMIT|END(X) trans_opt. {sqlite3EndTransaction(pParse,@X);}
cmd ::= ROLLBACK(X) trans_opt. {sqlite3EndTransaction(pParse,@X);}
savepoint_opt ::= SAVEPOINT.
savepoint_opt ::= .

View File

@ -478,6 +478,7 @@ static int lookupName(
sqlite3ExprDelete(db, pExpr->pRight);
pExpr->pRight = 0;
pExpr->op = (isTrigger ? TK_TRIGGER : TK_COLUMN);
ExprSetProperty(pExpr, EP_Leaf);
lookupname_end:
if( cnt==1 ){
assert( pNC!=0 );

View File

@ -5017,6 +5017,88 @@ static struct SrcList_item *isSelfJoinView(
return 0;
}
#ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION
/*
** Attempt to transform a query of the form
**
** SELECT count(*) FROM (SELECT x FROM t1 UNION ALL SELECT y FROM t2)
**
** Into this:
**
** SELECT (SELECT count(*) FROM t1)+(SELECT count(*) FROM t2)
**
** The transformation only works if all of the following are true:
**
** * The subquery is a UNION ALL of two or more terms
** * There is no WHERE or GROUP BY or HAVING clauses on the subqueries
** * The outer query is a simple count(*)
**
** Return TRUE if the optimization is undertaken.
*/
static int countOfViewOptimization(Parse *pParse, Select *p){
Select *pSub, *pPrior;
Expr *pExpr;
Expr *pCount;
sqlite3 *db;
if( (p->selFlags & SF_Aggregate)==0 ) return 0; /* This is an aggregate query */
if( p->pEList->nExpr!=1 ) return 0; /* Single result column */
pExpr = p->pEList->a[0].pExpr;
if( pExpr->op!=TK_AGG_FUNCTION ) return 0; /* Result is an aggregate */
if( sqlite3_stricmp(pExpr->u.zToken,"count") ) return 0; /* Must be count() */
if( pExpr->x.pList!=0 ) return 0; /* Must be count(*) */
if( p->pSrc->nSrc!=1 ) return 0; /* One table in the FROM clause */
pSub = p->pSrc->a[0].pSelect;
if( pSub==0 ) return 0; /* The FROM is a subquery */
if( pSub->pPrior==0 ) return 0; /* Must be a compound subquery */
do{
if( pSub->op!=TK_ALL && pSub->pPrior ) return 0; /* Must be UNION ALL */
if( pSub->pWhere ) return 0; /* No WHERE clause */
if( pSub->selFlags & SF_Aggregate ) return 0; /* Not an aggregate */
pSub = pSub->pPrior; /* Repeat over compound terms */
}while( pSub );
/* If we reach this point, that means it is OK to perform the transformation */
db = pParse->db;
pCount = pExpr;
pExpr = 0;
pSub = p->pSrc->a[0].pSelect;
p->pSrc->a[0].pSelect = 0;
sqlite3SrcListDelete(db, p->pSrc);
p->pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*p->pSrc));
while( pSub ){
Expr *pTerm;
pPrior = pSub->pPrior;
pSub->pPrior = 0;
pSub->pNext = 0;
pSub->selFlags |= SF_Aggregate;
pSub->selFlags &= ~SF_Compound;
pSub->nSelectRow = 0;
sqlite3ExprListDelete(db, pSub->pEList);
pTerm = pPrior ? sqlite3ExprDup(db, pCount, 0) : pCount;
pSub->pEList = sqlite3ExprListAppend(pParse, 0, pTerm);
pTerm = sqlite3PExpr(pParse, TK_SELECT, 0, 0);
sqlite3PExprAddSelect(pParse, pTerm, pSub);
if( pExpr==0 ){
pExpr = pTerm;
}else{
pExpr = sqlite3PExpr(pParse, TK_PLUS, pTerm, pExpr);
}
pSub = pPrior;
}
p->pEList->a[0].pExpr = pExpr;
p->selFlags &= ~SF_Aggregate;
#if SELECTTRACE_ENABLED
if( sqlite3SelectTrace & 0x400 ){
SELECTTRACE(0x400,pParse,p,("After count-of-view optimization:\n"));
sqlite3TreeViewSelect(0, p, 0);
}
#endif
return 1;
}
#endif /* SQLITE_COUNTOFVIEW_OPTIMIZATION */
/*
** Generate code for the SELECT statement given in the p argument.
**
@ -5329,6 +5411,16 @@ int sqlite3Select(
}
#endif
#ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION
if( OptimizationEnabled(db, SQLITE_QueryFlattener|SQLITE_CountOfView)
&& countOfViewOptimization(pParse, p)
){
if( db->mallocFailed ) goto select_end;
pEList = p->pEList;
pTabList = p->pSrc;
}
#endif
/* If the query is DISTINCT with an ORDER BY but is not an aggregate, and
** if the select-list is the same as the ORDER BY list, then this query
** can be rewritten as a GROUP BY. In other words, this:

View File

@ -4278,6 +4278,28 @@ int sqlite3_data_count(sqlite3_stmt *pStmt);
** KEYWORDS: {column access functions}
** METHOD: sqlite3_stmt
**
** <b>Summary:</b>
** <blockquote><table border=0 cellpadding=0 cellspacing=0>
** <tr><td><b>sqlite3_column_blob</b><td>&rarr;<td>BLOB result
** <tr><td><b>sqlite3_column_double</b><td>&rarr;<td>REAL result
** <tr><td><b>sqlite3_column_int</b><td>&rarr;<td>32-bit INTEGER result
** <tr><td><b>sqlite3_column_int64</b><td>&rarr;<td>64-bit INTEGER result
** <tr><td><b>sqlite3_column_text</b><td>&rarr;<td>UTF-8 TEXT result
** <tr><td><b>sqlite3_column_text16</b><td>&rarr;<td>UTF-16 TEXT result
** <tr><td><b>sqlite3_column_value</b><td>&rarr;<td>The result as an
** [sqlite3_value|unprotected sqlite3_value] object.
** <tr><td>&nbsp;<td>&nbsp;<td>&nbsp;
** <tr><td><b>sqlite3_column_bytes</b><td>&rarr;<td>Size of a BLOB
** or a UTF-8 TEXT result in bytes
** <tr><td><b>sqlite3_column_bytes16&nbsp;&nbsp;</b>
** <td>&rarr;&nbsp;&nbsp;<td>Size of UTF-16
** TEXT in bytes
** <tr><td><b>sqlite3_column_type</b><td>&rarr;<td>Default
** datatype of the result
** </table></blockquote>
**
** <b>Details:</b>
**
** ^These routines return information about a single column of the current
** result row of a query. ^In every case the first argument is a pointer
** to the [prepared statement] that is being evaluated (the [sqlite3_stmt*]
@ -4299,16 +4321,29 @@ int sqlite3_data_count(sqlite3_stmt *pStmt);
** are called from a different thread while any of these routines
** are pending, then the results are undefined.
**
** The first six interfaces (_blob, _double, _int, _int64, _text, and _text16)
** each return the value of a result column in a specific data format. If
** the result column is not initially in the requested format (for example,
** if the query returns an integer but the sqlite3_column_text() interface
** is used to extract the value) then an automatic type conversion is performed.
**
** ^The sqlite3_column_type() routine returns the
** [SQLITE_INTEGER | datatype code] for the initial data type
** of the result column. ^The returned value is one of [SQLITE_INTEGER],
** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL]. The value
** returned by sqlite3_column_type() is only meaningful if no type
** conversions have occurred as described below. After a type conversion,
** the value returned by sqlite3_column_type() is undefined. Future
** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL].
** The return value of sqlite3_column_type() can be used to decide which
** of the first six interface should be used to extract the column value.
** The value returned by sqlite3_column_type() is only meaningful if no
** automatic type conversions have occurred for the value in question.
** After a type conversion, the result of calling sqlite3_column_type()
** is undefined, though harmless. Future
** versions of SQLite may change the behavior of sqlite3_column_type()
** following a type conversion.
**
** If the result is a BLOB or a TEXT string, then the sqlite3_column_bytes()
** or sqlite3_column_bytes16() interfaces can be used to determine the size
** of that BLOB or string.
**
** ^If the result is a BLOB or UTF-8 string then the sqlite3_column_bytes()
** routine returns the number of bytes in that BLOB or string.
** ^If the result is a UTF-16 string, then sqlite3_column_bytes() converts
@ -4345,9 +4380,13 @@ int sqlite3_data_count(sqlite3_stmt *pStmt);
** [sqlite3_column_value()] is used in any other way, including calls
** to routines like [sqlite3_value_int()], [sqlite3_value_text()],
** or [sqlite3_value_bytes()], the behavior is not threadsafe.
** Hence, the sqlite3_column_value() interface
** is normally only useful within the implementation of
** [application-defined SQL functions] or [virtual tables], not within
** top-level application code.
**
** These routines attempt to convert the value where appropriate. ^For
** example, if the internal representation is FLOAT and a text result
** The these routines may attempt to convert the datatype of the result.
** ^For example, if the internal representation is FLOAT and a text result
** is requested, [sqlite3_snprintf()] is used internally to perform the
** conversion automatically. ^(The following table details the conversions
** that are applied:
@ -4419,7 +4458,7 @@ int sqlite3_data_count(sqlite3_stmt *pStmt);
** ^The pointers returned are valid until a type conversion occurs as
** described above, or until [sqlite3_step()] or [sqlite3_reset()] or
** [sqlite3_finalize()] is called. ^The memory space used to hold strings
** and BLOBs is freed automatically. Do <em>not</em> pass the pointers returned
** and BLOBs is freed automatically. Do not pass the pointers returned
** from [sqlite3_column_blob()], [sqlite3_column_text()], etc. into
** [sqlite3_free()].
**
@ -4430,15 +4469,15 @@ int sqlite3_data_count(sqlite3_stmt *pStmt);
** [SQLITE_NOMEM].)^
*/
const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
double sqlite3_column_double(sqlite3_stmt*, int iCol);
int sqlite3_column_int(sqlite3_stmt*, int iCol);
sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);
const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
int sqlite3_column_type(sqlite3_stmt*, int iCol);
sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
int sqlite3_column_type(sqlite3_stmt*, int iCol);
/*
** CAPI3REF: Destroy A Prepared Statement Object
@ -4672,21 +4711,39 @@ SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
** CAPI3REF: Obtaining SQL Values
** METHOD: sqlite3_value
**
** The C-language implementation of SQL functions and aggregates uses
** this set of interface routines to access the parameter values on
** the function or aggregate.
** <b>Summary:</b>
** <blockquote><table border=0 cellpadding=0 cellspacing=0>
** <tr><td><b>sqlite3_value_blob</b><td>&rarr;<td>BLOB value
** <tr><td><b>sqlite3_value_double</b><td>&rarr;<td>REAL value
** <tr><td><b>sqlite3_value_int</b><td>&rarr;<td>32-bit INTEGER value
** <tr><td><b>sqlite3_value_int64</b><td>&rarr;<td>64-bit INTEGER value
** <tr><td><b>sqlite3_value_text</b><td>&rarr;<td>UTF-8 TEXT value
** <tr><td><b>sqlite3_value_text16</b><td>&rarr;<td>UTF-16 TEXT value in
** the native byteorder
** <tr><td><b>sqlite3_value_text16be</b><td>&rarr;<td>UTF-16be TEXT value
** <tr><td><b>sqlite3_value_text16le</b><td>&rarr;<td>UTF-16le TEXT value
** <tr><td>&nbsp;<td>&nbsp;<td>&nbsp;
** <tr><td><b>sqlite3_value_bytes</b><td>&rarr;<td>Size of a BLOB
** or a UTF-8 TEXT in bytes
** <tr><td><b>sqlite3_value_bytes16&nbsp;&nbsp;</b>
** <td>&rarr;&nbsp;&nbsp;<td>Size of UTF-16
** TEXT in bytes
** <tr><td><b>sqlite3_value_type</b><td>&rarr;<td>Default
** datatype of the value
** <tr><td><b>sqlite3_value_numeric_type&nbsp;&nbsp;</b>
** <td>&rarr;&nbsp;&nbsp;<td>Best numeric datatype of the value
** </table></blockquote>
**
** The xFunc (for scalar functions) or xStep (for aggregates) parameters
** to [sqlite3_create_function()] and [sqlite3_create_function16()]
** define callbacks that implement the SQL functions and aggregates.
** The 3rd parameter to these callbacks is an array of pointers to
** [protected sqlite3_value] objects. There is one [sqlite3_value] object for
** each parameter to the SQL function. These routines are used to
** extract values from the [sqlite3_value] objects.
** <b>Details:</b>
**
** This routine extract type, size, and content information from
** [protected sqlite3_value] objects. Protected sqlite3_value objects
** are used to pass parameter information into implementation of
** [application-defined SQL functions] and [virtual tables].
**
** These routines work only with [protected sqlite3_value] objects.
** Any attempt to use these routines on an [unprotected sqlite3_value]
** object results in undefined behavior.
** is not threadsafe.
**
** ^These routines work just like the corresponding [column access functions]
** except that these routines take a single [protected sqlite3_value] object
@ -4731,8 +4788,6 @@ SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
** the SQL function that supplied the [sqlite3_value*] parameters.
*/
const void *sqlite3_value_blob(sqlite3_value*);
int sqlite3_value_bytes(sqlite3_value*);
int sqlite3_value_bytes16(sqlite3_value*);
double sqlite3_value_double(sqlite3_value*);
int sqlite3_value_int(sqlite3_value*);
sqlite3_int64 sqlite3_value_int64(sqlite3_value*);
@ -4741,6 +4796,8 @@ const void *sqlite3_value_text16(sqlite3_value*);
const void *sqlite3_value_text16le(sqlite3_value*);
const void *sqlite3_value_text16be(sqlite3_value*);
void *sqlite3_value_pointer(sqlite3_value*);
int sqlite3_value_bytes(sqlite3_value*);
int sqlite3_value_bytes16(sqlite3_value*);
int sqlite3_value_type(sqlite3_value*);
int sqlite3_value_numeric_type(sqlite3_value*);

View File

@ -1509,6 +1509,7 @@ struct sqlite3 {
#define SQLITE_Transitive 0x0200 /* Transitive constraints */
#define SQLITE_OmitNoopJoin 0x0400 /* Omit unused tables in joins */
#define SQLITE_Stat34 0x0800 /* Use STAT3 or STAT4 data */
#define SQLITE_CountOfView 0x1000 /* The count-of-view optimization */
#define SQLITE_CursorHints 0x2000 /* Add OP_CursorHint opcodes */
#define SQLITE_AllOpts 0xffff /* All optimizations */
@ -3803,8 +3804,7 @@ void sqlite3RollbackAll(sqlite3*,int);
void sqlite3CodeVerifySchema(Parse*, int);
void sqlite3CodeVerifyNamedSchema(Parse*, const char *zDb);
void sqlite3BeginTransaction(Parse*, int);
void sqlite3CommitTransaction(Parse*);
void sqlite3RollbackTransaction(Parse*);
void sqlite3EndTransaction(Parse*,int);
void sqlite3Savepoint(Parse*, int, Token*);
void sqlite3CloseSavepoints(sqlite3 *);
void sqlite3LeaveMutexAndCloseZombie(sqlite3*);

View File

@ -41,15 +41,17 @@ static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){
testcase( ExprHasProperty(pExpr, EP_TokenOnly) );
testcase( ExprHasProperty(pExpr, EP_Reduced) );
rc = pWalker->xExprCallback(pWalker, pExpr);
if( rc || ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){
return rc & WRC_Abort;
}
if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort;
if( pExpr->pRight && walkExpr(pWalker, pExpr->pRight) ) return WRC_Abort;
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort;
}else if( pExpr->x.pList ){
if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort;
if( rc ) return rc & WRC_Abort;
if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){
if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort;
assert( pExpr->x.pList==0 || pExpr->pRight==0 );
if( pExpr->pRight ){
if( walkExpr(pWalker, pExpr->pRight) ) return WRC_Abort;
}else if( ExprHasProperty(pExpr, EP_xIsSelect) ){
if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort;
}else if( pExpr->x.pList ){
if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort;
}
}
return WRC_Continue;
}
@ -104,7 +106,7 @@ int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){
pSrc = p->pSrc;
if( ALWAYS(pSrc) ){
for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
if( sqlite3WalkSelect(pWalker, pItem->pSelect) ){
if( pItem->pSelect && sqlite3WalkSelect(pWalker, pItem->pSelect) ){
return WRC_Abort;
}
if( pItem->fg.isTabFunc
@ -136,7 +138,8 @@ int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){
*/
int sqlite3WalkSelect(Walker *pWalker, Select *p){
int rc;
if( p==0 || pWalker->xSelectCallback==0 ) return WRC_Continue;
if( p==0 ) return WRC_Continue;
if( pWalker->xSelectCallback==0 ) return WRC_Continue;
do{
rc = pWalker->xSelectCallback(pWalker, p);
if( rc ) return rc & WRC_Abort;

View File

@ -4549,9 +4549,13 @@ WhereInfo *sqlite3WhereBegin(
sqlite3WhereTabFuncArgs(pParse, &pTabList->a[ii], &pWInfo->sWC);
}
#ifdef SQLITE_DEBUG
for(ii=0; ii<pTabList->nSrc; ii++){
Bitmask m = sqlite3WhereGetMask(pMaskSet, pTabList->a[ii].iCursor);
assert( m==MASKBIT(ii) );
{
Bitmask mx = 0;
for(ii=0; ii<pTabList->nSrc; ii++){
Bitmask m = sqlite3WhereGetMask(pMaskSet, pTabList->a[ii].iCursor);
assert( m>=mx );
mx = m;
}
}
#endif

View File

@ -339,7 +339,9 @@ void ParseInit(void *yypParser){
pParser->yytos = pParser->yystack;
pParser->yystack[0].stateno = 0;
pParser->yystack[0].major = 0;
#if YYSTACKDEPTH>0
pParser->yystackEnd = &pParser->yystack[YYSTACKDEPTH-1];
#endif
}
#ifndef Parse_ENGINEALWAYSONSTACK

View File

@ -336,8 +336,8 @@ int main(int argc, char **argv){
int count;
int nChar;
int totalLen = 0;
int aHash[1000]; /* 1000 is much bigger than nKeyword */
char zText[2000];
int aKWHash[1000]; /* 1000 is much bigger than nKeyword */
char zKWText[2000];
/* Remove entries from the list of keywords that have mask==0 */
for(i=j=0; i<nKeyword; i++){
@ -441,13 +441,13 @@ int main(int argc, char **argv){
bestSize = nKeyword;
bestCount = nKeyword*nKeyword;
for(i=nKeyword/2; i<=2*nKeyword; i++){
for(j=0; j<i; j++) aHash[j] = 0;
for(j=0; j<i; j++) aKWHash[j] = 0;
for(j=0; j<nKeyword; j++){
h = aKeywordTable[j].hash % i;
aHash[h] *= 2;
aHash[h]++;
aKWHash[h] *= 2;
aKWHash[h]++;
}
for(j=count=0; j<i; j++) count += aHash[j];
for(j=count=0; j<i; j++) count += aKWHash[j];
if( count<bestCount ){
bestCount = count;
bestSize = i;
@ -455,30 +455,29 @@ int main(int argc, char **argv){
}
/* Compute the hash */
for(i=0; i<bestSize; i++) aHash[i] = 0;
for(i=0; i<bestSize; i++) aKWHash[i] = 0;
for(i=0; i<nKeyword; i++){
h = aKeywordTable[i].hash % bestSize;
aKeywordTable[i].iNext = aHash[h];
aHash[h] = i+1;
aKeywordTable[i].iNext = aKWHash[h];
aKWHash[h] = i+1;
}
/* Begin generating code */
printf("%s", zHdr);
printf("/* Hash score: %d */\n", bestCount);
printf("static int keywordCode(const char *z, int n, int *pType){\n");
printf(" /* zText[] encodes %d bytes of keywords in %d bytes */\n",
printf("/* zKWText[] encodes %d bytes of keyword text in %d bytes */\n",
totalLen + nKeyword, nChar+1 );
for(i=j=k=0; i<nKeyword; i++){
Keyword *p = &aKeywordTable[i];
if( p->substrId ) continue;
memcpy(&zText[k], p->zName, p->len);
memcpy(&zKWText[k], p->zName, p->len);
k += p->len;
if( j+p->len>70 ){
printf("%*s */\n", 74-j, "");
j = 0;
}
if( j==0 ){
printf(" /* ");
printf("/* ");
j = 8;
}
printf("%s", p->zName);
@ -487,16 +486,16 @@ int main(int argc, char **argv){
if( j>0 ){
printf("%*s */\n", 74-j, "");
}
printf(" static const char zText[%d] = {\n", nChar);
zText[nChar] = 0;
printf("static const char zKWText[%d] = {\n", nChar);
zKWText[nChar] = 0;
for(i=j=0; i<k; i++){
if( j==0 ){
printf(" ");
printf(" ");
}
if( zText[i]==0 ){
if( zKWText[i]==0 ){
printf("0");
}else{
printf("'%c',", zText[i]);
printf("'%c',", zKWText[i]);
}
j += 4;
if( j>68 ){
@ -505,23 +504,27 @@ int main(int argc, char **argv){
}
}
if( j>0 ) printf("\n");
printf(" };\n");
printf("};\n");
printf(" static const unsigned char aHash[%d] = {\n", bestSize);
printf("/* aKWHash[i] is the hash value for the i-th keyword */\n");
printf("static const unsigned char aKWHash[%d] = {\n", bestSize);
for(i=j=0; i<bestSize; i++){
if( j==0 ) printf(" ");
printf(" %3d,", aHash[i]);
if( j==0 ) printf(" ");
printf(" %3d,", aKWHash[i]);
j++;
if( j>12 ){
printf("\n");
j = 0;
}
}
printf("%s };\n", j==0 ? "" : "\n");
printf("%s};\n", j==0 ? "" : "\n");
printf(" static const unsigned char aNext[%d] = {\n", nKeyword);
printf("/* aKWNext[] forms the hash collision chain. If aKWHash[i]==0\n");
printf("** then the i-th keyword has no more hash collisions. Otherwise,\n");
printf("** the next keyword with the same hash is aKWHash[i]-1. */\n");
printf("static const unsigned char aKWNext[%d] = {\n", nKeyword);
for(i=j=0; i<nKeyword; i++){
if( j==0 ) printf(" ");
if( j==0 ) printf(" ");
printf(" %3d,", aKeywordTable[i].iNext);
j++;
if( j>12 ){
@ -529,11 +532,12 @@ int main(int argc, char **argv){
j = 0;
}
}
printf("%s };\n", j==0 ? "" : "\n");
printf("%s};\n", j==0 ? "" : "\n");
printf(" static const unsigned char aLen[%d] = {\n", nKeyword);
printf("/* aKWLen[i] is the length (in bytes) of the i-th keyword */\n");
printf("static const unsigned char aKWLen[%d] = {\n", nKeyword);
for(i=j=0; i<nKeyword; i++){
if( j==0 ) printf(" ");
if( j==0 ) printf(" ");
printf(" %3d,", aKeywordTable[i].len+aKeywordTable[i].prefix);
j++;
if( j>12 ){
@ -541,11 +545,13 @@ int main(int argc, char **argv){
j = 0;
}
}
printf("%s };\n", j==0 ? "" : "\n");
printf("%s};\n", j==0 ? "" : "\n");
printf(" static const unsigned short int aOffset[%d] = {\n", nKeyword);
printf("/* aKWOffset[i] is the index into zKWText[] of the start of\n");
printf("** the text for the i-th keyword. */\n");
printf("static const unsigned short int aKWOffset[%d] = {\n", nKeyword);
for(i=j=0; i<nKeyword; i++){
if( j==0 ) printf(" ");
if( j==0 ) printf(" ");
printf(" %3d,", aKeywordTable[i].offset);
j++;
if( j>12 ){
@ -553,12 +559,13 @@ int main(int argc, char **argv){
j = 0;
}
}
printf("%s };\n", j==0 ? "" : "\n");
printf("%s};\n", j==0 ? "" : "\n");
printf(" static const unsigned char aCode[%d] = {\n", nKeyword);
printf("/* aKWCode[i] is the parser symbol code for the i-th keyword */\n");
printf("static const unsigned char aKWCode[%d] = {\n", nKeyword);
for(i=j=0; i<nKeyword; i++){
char *zToken = aKeywordTable[i].zTokenType;
if( j==0 ) printf(" ");
if( j==0 ) printf(" ");
printf("%s,%*s", zToken, (int)(14-strlen(zToken)), "");
j++;
if( j>=5 ){
@ -566,17 +573,20 @@ int main(int argc, char **argv){
j = 0;
}
}
printf("%s };\n", j==0 ? "" : "\n");
printf("%s};\n", j==0 ? "" : "\n");
printf("/* Check to see if z[0..n-1] is a keyword. If it is, write the\n");
printf("** parser symbol code for that keyword into *pType. Always\n");
printf("** return the integer n (the length of the token). */\n");
printf("static int keywordCode(const char *z, int n, int *pType){\n");
printf(" int i, j;\n");
printf(" const char *zKW;\n");
printf(" if( n>=2 ){\n");
printf(" i = ((charMap(z[0])*4) ^ (charMap(z[n-1])*3) ^ n) %% %d;\n",
bestSize);
printf(" for(i=((int)aHash[i])-1; i>=0; i=((int)aNext[i])-1){\n");
printf(" if( aLen[i]!=n ) continue;\n");
printf(" for(i=((int)aKWHash[i])-1; i>=0; i=((int)aKWNext[i])-1){\n");
printf(" if( aKWLen[i]!=n ) continue;\n");
printf(" j = 0;\n");
printf(" zKW = &zText[aOffset[i]];\n");
printf(" zKW = &zKWText[aKWOffset[i]];\n");
printf("#ifdef SQLITE_ASCII\n");
printf(" while( j<n && (z[j]&~0x20)==zKW[j] ){ j++; }\n");
printf("#endif\n");
@ -588,7 +598,7 @@ int main(int argc, char **argv){
printf(" testcase( i==%d ); /* %s */\n",
i, aKeywordTable[i].zOrigName);
}
printf(" *pType = aCode[i];\n");
printf(" *pType = aKWCode[i];\n");
printf(" break;\n");
printf(" }\n");
printf(" }\n");