1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Merge recent performance enhancements and the CAST operator enhancements

into the sessions branch.

FossilOrigin-Name: 08ae974ac80fabe53f515bbbd93ccf55de8ee671
This commit is contained in:
drh
2014-08-26 02:15:07 +00:00
39 changed files with 966 additions and 782 deletions

View File

@@ -2736,12 +2736,22 @@ static int spellfix1Update(
return SQLITE_NOMEM;
}
if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
spellfix1DbExec(&rc, db,
"INSERT INTO \"%w\".\"%w_vocab\"(rank,langid,word,k1,k2) "
"VALUES(%d,%d,%Q,%Q,%Q)",
p->zDbName, p->zTableName,
iRank, iLang, zWord, zK1, zK2
);
if( sqlite3_value_type(argv[1])==SQLITE_NULL ){
spellfix1DbExec(&rc, db,
"INSERT INTO \"%w\".\"%w_vocab\"(rank,langid,word,k1,k2) "
"VALUES(%d,%d,%Q,%Q,%Q)",
p->zDbName, p->zTableName,
iRank, iLang, zWord, zK1, zK2
);
}else{
newRowid = sqlite3_value_int64(argv[1]);
spellfix1DbExec(&rc, db,
"INSERT INTO \"%w\".\"%w_vocab\"(id,rank,langid,word,k1,k2) "
"VALUES(%lld,%d,%d,%Q,%Q,%Q)",
p->zDbName, p->zTableName,
newRowid, iRank, iLang, zWord, zK1, zK2
);
}
*pRowid = sqlite3_last_insert_rowid(db);
}else{
rowid = sqlite3_value_int64(argv[0]);

View File

@@ -1,5 +1,5 @@
C Merge\sall\srecent\strunk\schanges,\sespecially\sthe\sfix\sfor\nticket\s[369d57fb8e5ccdff06f1],\sbut\salso\sthe\sskip-scan\simprovement\sand\nperformance\simprovements\sin\sthe\sb-tree\scode.
D 2014-08-21T16:09:36.975
C Merge\srecent\sperformance\senhancements\sand\sthe\sCAST\soperator\senhancements\ninto\sthe\ssessions\sbranch.
D 2014-08-26T02:15:07.293
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in d5ad373b7a23525414b8843b3084cf90c560d92f
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -116,7 +116,7 @@ F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342
F ext/misc/percentile.c bcbee3c061b884eccb80e21651daaae8e1e43c63
F ext/misc/regexp.c af92cdaa5058fcec1451e49becc7ba44dba023dc
F ext/misc/rot13.c 1ac6f95f99b575907b9b09c81a349114cf9be45a
F ext/misc/spellfix.c cb016c2dab951ffd7b819a7bc8a750ebd6c26c0f
F ext/misc/spellfix.c 56739fab8c2ed6a9e2dac5592a88d281a999c43b
F ext/misc/totype.c 4a167594e791abeed95e0a8db028822b5e8fe512
F ext/misc/vfslog.c fe40fab5c077a40477f7e5eba994309ecac6cc95
F ext/misc/vtshim.c babb0dc2bf116029e3e7c9a618b8a1377045303e
@@ -181,33 +181,33 @@ F src/alter.c b00900877f766f116f9e16116f1ccacdc21d82f1
F src/analyze.c f98a351908da29f7b44741cfeb9eb20dda648ba0
F src/attach.c 3801129015ef59d76bf23c95ef9b0069d18a0c52
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
F src/backup.c a729e63cf5cd1829507cb7b8e89f99b95141bb53
F src/backup.c a31809c65623cc41849b94d368917f8bb66e6a7e
F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
F src/btree.c 4195fed5741b4dbcc9831b623aec487258f3e62d
F src/btree.h 4245a349bfe09611d7ff887dbc3a80cee8b7955a
F src/btmutex.c ec9d3f1295dafeb278c3830211cc5584132468f4
F src/btree.c 4737cb5bdb2eb8989cb292f6ff921f7ff45f0c46
F src/btree.h a79aa6a71e7f1055f01052b7f821bd1c2dce95c8
F src/btreeInt.h cf180d86b2e9e418f638d65baa425c4c69c0e0e3
F src/build.c 5abf794fe8a605f2005b422e98a3cedad9b9ef5b
F src/callback.c fcff28cf0df2403dd2f313bb8d1b8f31f6f3cd64
F src/build.c 058e3aadb1376521ff291735237edf4c10f438fb
F src/callback.c b97d0695ffcf6a8710ee445ffe56ee387d4d8a6f
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a
F src/date.c 593c744b2623971e45affd0bde347631bdfa4625
F src/delete.c cb7a757eb829ebb046c66f6399435c6636fe1314
F src/expr.c f749009cf4a8534efb5e0d5cd7c9fb1fb0f2836c
F src/expr.c 358634f4ddeeb4e69643cb6db5819104a7834c60
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c 8545f3b36da47473e10800ea4fb0810fd4062514
F src/fkey.c 8d81a780ad78d16ec9082585758a8f1d6bf02ca3
F src/func.c bbb724b74ed96ca42675a7274646a71dd52bcda7
F src/global.c 1e4bd956dc2f608f87d2a929abc4a20db65f30e4
F src/hash.c d139319967164f139c8d1bb8a11b14db9c4ba3cd
F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22
F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5
F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
F src/insert.c 3d41db1398a5863c4a1c064d2082d0dc43274628
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
F src/legacy.c febc2a9e7ad6c1a6191c7b5b9170b325d263f343
F src/legacy.c 87c92f4a08e2f70220e3b22a9c3b2482d36a134a
F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
F src/loadext.c 867c7b330b740c6c917af9956b13b81d0a048303
F src/main.c 7f8200240d0ca790804b04deeca9f2461013355e
F src/malloc.c 0203ebce9152c6a0e5de520140b8ba65187350be
F src/loadext.c 31c2122b7dd05a179049bbf163fd4839f181cbab
F src/main.c f375a8d81960b5ff3a7a765e1367b0d0cd90f222
F src/malloc.c 954de5f998c23237e04474a3f2159bf483bba65a
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c c0c990fcaddff810ea277b4fb5d9138603dd5d4b
F src/mem2.c dce31758da87ec2cfa52ba4c5df1aed6e07d8e8f
@@ -219,7 +219,7 @@ F src/mutex.h 5bc526e19dccc412b7ff04642f6fdad3fdfdabea
F src/mutex_noop.c f3f09fd7a2eb4287cfc799753ffc30380e7b71a1
F src/mutex_unix.c 1b10d5413dfc794364a8adf3eb3a192926b43fa3
F src/mutex_w32.c 06bfff9a3a83b53389a51a967643db3967032e1e
F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30
F src/notify.c 9711a7575036f0d3040ba61bc6e217f13a9888e7
F src/os.c 1b147e4cf7cc39e618115c14a086aed44bc91ace
F src/os.h 60d419395e32a8029fa380a80a3da2e9030f635e
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
@@ -227,15 +227,15 @@ F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa
F src/os_unix.c bd7df3094a60915c148517504c76df4fca24e542
F src/os_win.c d067fce558a5032e6e6afe62899e5397bf63cf3e
F src/os_win.h 09e751b20bbc107ffbd46e13555dc73576d88e21
F src/pager.c f6bb1fa6cdf2062f2d8aec3e64db302bca519ab8
F src/pager.c 53cc5e9d73afb74add79f49755c8ee240fbdbef7
F src/pager.h ffd5607f7b3e4590b415b007a4382f693334d428
F src/parse.y 22d6a074e5f5a7258947a1dc55a9bf946b765dd0
F src/pcache.c d8eafac28290d4bb80332005435db44991d07fc2
F src/pcache.c da602c5447051705cab41604bf3276815eb569d0
F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
F src/pcache1.c 102e6f5a2fbc646154463eb856d1fd716867b64c
F src/pcache1.c c5af6403a55178c9d1c09e4f77b0f9c88822762c
F src/pragma.c d10ef67c4de79f78188b965b4b7988aff1d66f2e
F src/prepare.c 677521ab7132615a8a26107a1d1c3132f44ae337
F src/printf.c af06f66927919730f03479fed6ae9854f73419f4
F src/prepare.c 3842c1dfc0b053458e3adcf9f6efc48e03e3fe3d
F src/printf.c 00986c86ddfffefc2fd3c73667ff51b3b9709c74
F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece
F src/resolve.c 0ea356d32a5e884add23d1b9b4e8736681dd5697
F src/rowset.c a9c9aae3234b44a6d7c6f5a3cadf90dce1e627be
@@ -244,7 +244,7 @@ F src/shell.c 34be9dc9e7b96081488acebecae6cd92632397a6
F src/sqlite.h.in 021a1f5c50e83060675d994a6014fd409e611d9e
F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
F src/sqliteInt.h d60dbbadfd64374a5a2f362fc6f45899540c2c8e
F src/sqliteInt.h 2ecc10cd81d38e8617e24ed425e6ec792195b0f0
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
@@ -295,25 +295,25 @@ F src/test_vfs.c f84075a388527892ff184988f43b69ce69b8083c
F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/tokenize.c ae45399d6252b4d736af43bee1576ce7bff86aec
F src/trigger.c 66f3470b03b52b395e839155786966e3e037fddb
F src/trigger.c 4bddd12803275aa98f1c7ce0118fceb02b2167f6
F src/update.c b0f38fda25d532343d54b7dc49f55ab73e92ca45
F src/utf.c a0314e637768a030e6e84a957d0c4f6ba910cc05
F src/util.c 3076bdd51cdbf60a6e2e57fada745be37133c73e
F src/utf.c 77abb5e6d27f3d236e50f7c8fff1d00e15262359
F src/util.c 068dcd26354a3898ccc64ad5c4bdb95a7a15d33a
F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
F src/vdbe.c ff9bec31cc128e98d852ebee6e5d4e160846e0c5
F src/vdbe.c 5e576d164e6cfb8ef1c6324c3d6eca56322fd656
F src/vdbe.h ca3b6df299adce6e2f499c57e42ae54f142ae823
F src/vdbeInt.h 5eee1752eff410de9373196e2b327f7deefb3920
F src/vdbeapi.c 11d97cd50ca78f6c6ce796d0c78913ef27f5383d
F src/vdbeaux.c 22aabbdea2394cea26e35b2190fa9111e4bc18c2
F src/vdbeblob.c d7c232d1c6afc7ee1176c38b7d81b2e17af15ceb
F src/vdbemem.c d90a1e8acf8b63dc9d14cbbea12bfec6cec31394
F src/vdbeInt.h 6a50eb240aac711ac609f624daa225781711c6fd
F src/vdbeapi.c ce34bb80571f72463dbd45380e3eae65ddc52018
F src/vdbeaux.c 236cc1afd82ab542fc752ed760471ac816cb7902
F src/vdbeblob.c d65b01f439df63911ac3d7a9a85c15503965f2c3
F src/vdbemem.c 4e08ea087aea367dae7c45129b75487e0056e819
F src/vdbesort.c f7f5563bf7d4695ca8f3203f3bf9de96d04ed0b3
F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767
F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd
F src/vtab.c 019dbfd0406a7447c990e1f7bd1dfcdb8895697f
F src/wal.c 264df50a1b33124130b23180ded2e2c5663c652a
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
F src/walker.c 11edb74d587bc87b33ca96a5173e3ec1b8389e45
F src/where.c 4c499d185827a492643cf017ae5e3aa0523f9f18
F src/where.c 4e2770a1914b8ce30f3e44ad954b720eca3b5efd
F src/whereInt.h 923820bee9726033a501a08d2fc69b9c1ee4feb3
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
@@ -323,7 +323,7 @@ F test/all.test 6ff7b43c2b4b905c74dc4a813d201d0fa64c5783
F test/alter.test 547dc2d292644301ac9a7dda22b319b74f9c08d2
F test/alter2.test 7ea05c7d92ac99349a802ef7ada17294dd647060
F test/alter3.test 49c9d9fba2b8fcdce2dedeca97bbf1f369cc548d
F test/alter4.test d6c011fa0d6227abba762498cafbb607c9609e93
F test/alter4.test c461150723ac957f3b2214aa0b11552cd72023ec
F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc
F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f
F test/analyze.test 1772936d66471c65221e437b6d1999c3a03166c4
@@ -333,8 +333,8 @@ F test/analyze5.test 765c4e284aa69ca172772aa940946f55629bc8c4
F test/analyze6.test f1c552ce39cca4ec922a7e4e0e5d0203d6b3281f
F test/analyze7.test bb1409afc9e8629e414387ef048b8e0e3e0bdc4f
F test/analyze8.test 093d15c1c888eed5034304a98c992f7360130b88
F test/analyze9.test 3ef1b471247308e710a794b6e50a6ab536c5604b
F test/analyzeA.test 1a5c40079894847976d983ca39c707aaa44b6944
F test/analyze9.test 72795c8113604b5dcd47a1498a61d6d7fb5d041a
F test/analyzeA.test 3335697f6700c7052295cfd0067fc5b2aacddf9a
F test/analyzeB.test 8bf35ee0a548aea831bf56762cb8e7fdb1db083d
F test/analyzeC.test 555a6cc388b9818b6eda6df816f01ce0a75d3a93
F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b
@@ -864,7 +864,7 @@ F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b
F test/speedtest1.c d29c8048beb7ea9254191f3fde9414709166a920
F test/spellfix.test 61309f5efbec53603b3f86457d34a504f80abafe
F test/spellfix.test 24f676831acddd2f4056a598fd731a72c6311f49
F test/sqllimits1.test b1aae27cc98eceb845e7f7adf918561256e31298
F test/stat.test 76fd746b85459e812a0193410fb599f0531f22de
F test/stmt.test 25d64e3dbf9a3ce89558667d7f39d966fe2a71b9
@@ -1205,7 +1205,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P 6d5b9332e8d8bb572ac98b0f4e47e59ad12aac26 7029b3404d3f5f698a496934f3a3f2972051b257
R a953db417f3d0f990497f5e1512b276c
P 0b9e2c3269695713b538561d999c68097db70f0c af364cce9da0961593ef876b646197f82df08ad5
R 7c6d04c5134339ec2be8d6e1d0b0aa83
U drh
Z d706f9a9d70b2e75b205ef1091dd3b5f
Z 9ac7a7803f5fd67d6db4d00d2f3fd4ea

View File

@@ -1 +1 @@
0b9e2c3269695713b538561d999c68097db70f0c
08ae974ac80fabe53f515bbbd93ccf55de8ee671

View File

@@ -87,12 +87,12 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
int rc = 0;
pParse = sqlite3StackAllocZero(pErrorDb, sizeof(*pParse));
if( pParse==0 ){
sqlite3Error(pErrorDb, SQLITE_NOMEM, "out of memory");
sqlite3ErrorWithMsg(pErrorDb, SQLITE_NOMEM, "out of memory");
rc = SQLITE_NOMEM;
}else{
pParse->db = pDb;
if( sqlite3OpenTempDatabase(pParse) ){
sqlite3Error(pErrorDb, pParse->rc, "%s", pParse->zErrMsg);
sqlite3ErrorWithMsg(pErrorDb, pParse->rc, "%s", pParse->zErrMsg);
rc = SQLITE_ERROR;
}
sqlite3DbFree(pErrorDb, pParse->zErrMsg);
@@ -105,7 +105,7 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
}
if( i<0 ){
sqlite3Error(pErrorDb, SQLITE_ERROR, "unknown database %s", zDb);
sqlite3ErrorWithMsg(pErrorDb, SQLITE_ERROR, "unknown database %s", zDb);
return 0;
}
@@ -150,7 +150,7 @@ sqlite3_backup *sqlite3_backup_init(
sqlite3_mutex_enter(pDestDb->mutex);
if( pSrcDb==pDestDb ){
sqlite3Error(
sqlite3ErrorWithMsg(
pDestDb, SQLITE_ERROR, "source and destination must be distinct"
);
p = 0;
@@ -161,7 +161,7 @@ sqlite3_backup *sqlite3_backup_init(
** sqlite3_backup_finish(). */
p = (sqlite3_backup *)sqlite3MallocZero(sizeof(sqlite3_backup));
if( !p ){
sqlite3Error(pDestDb, SQLITE_NOMEM, 0);
sqlite3Error(pDestDb, SQLITE_NOMEM);
}
}
@@ -602,7 +602,7 @@ int sqlite3_backup_finish(sqlite3_backup *p){
/* Set the error code of the destination database handle. */
rc = (p->rc==SQLITE_DONE) ? SQLITE_OK : p->rc;
if( p->pDestDb ){
sqlite3Error(p->pDestDb, rc, 0);
sqlite3Error(p->pDestDb, rc);
/* Exit the mutexes and free the backup context structure. */
sqlite3LeaveMutexAndCloseZombie(p->pDestDb);

View File

@@ -38,7 +38,7 @@ static void lockBtreeMutex(Btree *p){
** Release the BtShared mutex associated with B-Tree handle p and
** clear the p->locked boolean.
*/
static void unlockBtreeMutex(Btree *p){
static void SQLITE_NOINLINE unlockBtreeMutex(Btree *p){
BtShared *pBt = p->pBt;
assert( p->locked==1 );
assert( sqlite3_mutex_held(pBt->mutex) );
@@ -49,6 +49,9 @@ static void unlockBtreeMutex(Btree *p){
p->locked = 0;
}
/* Forward reference */
static void SQLITE_NOINLINE btreeLockCarefully(Btree *p);
/*
** Enter a mutex on the given BTree object.
**
@@ -66,8 +69,6 @@ static void unlockBtreeMutex(Btree *p){
** subsequent Btrees that desire a lock.
*/
void sqlite3BtreeEnter(Btree *p){
Btree *pLater;
/* Some basic sanity checking on the Btree. The list of Btrees
** connected by pNext and pPrev should be in sorted order by
** Btree.pBt value. All elements of the list should belong to
@@ -92,6 +93,17 @@ void sqlite3BtreeEnter(Btree *p){
if( !p->sharable ) return;
p->wantToLock++;
if( p->locked ) return;
btreeLockCarefully(p);
}
/* This is a helper function for sqlite3BtreeLock(). By moving
** complex, but seldom used logic, out of sqlite3BtreeLock() and
** into this routine, we avoid unnecessary stack pointer changes
** and thus help the sqlite3BtreeLock() routine to run much faster
** in the common case.
*/
static void SQLITE_NOINLINE btreeLockCarefully(Btree *p){
Btree *pLater;
/* In most cases, we should be able to acquire the lock we
** want without having to go throught the ascending lock
@@ -124,6 +136,7 @@ void sqlite3BtreeEnter(Btree *p){
}
}
/*
** Exit the recursive mutex on a Btree.
*/

View File

@@ -629,16 +629,42 @@ static int saveCursorPosition(BtCursor *pCur){
return rc;
}
/* Forward reference */
static int SQLITE_NOINLINE saveCursorsOnList(BtCursor*,Pgno,BtCursor*);
/*
** Save the positions of all cursors (except pExcept) that are open on
** the table with root-page iRoot. Usually, this is called just before cursor
** pExcept is used to modify the table (BtreeDelete() or BtreeInsert()).
** the table with root-page iRoot. "Saving the cursor position" means that
** the location in the btree is remembered in such a way that it can be
** moved back to the same spot after the btree has been modified. This
** routine is called just before cursor pExcept is used to modify the
** table, for example in BtreeDelete() or BtreeInsert().
**
** Implementation note: This routine merely checks to see if any cursors
** need to be saved. It calls out to saveCursorsOnList() in the (unusual)
** event that cursors are in need to being saved.
*/
static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){
BtCursor *p;
assert( sqlite3_mutex_held(pBt->mutex) );
assert( pExcept==0 || pExcept->pBt==pBt );
for(p=pBt->pCursor; p; p=p->pNext){
if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) ) break;
}
return p ? saveCursorsOnList(p, iRoot, pExcept) : SQLITE_OK;
}
/* This helper routine to saveAllCursors does the actual work of saving
** the cursors if and when a cursor is found that actually requires saving.
** The common case is that no cursors need to be saved, so this routine is
** broken out from its caller to avoid unnecessary stack pointer movement.
*/
static int SQLITE_NOINLINE saveCursorsOnList(
BtCursor *p, /* The first cursor that needs saving */
Pgno iRoot, /* Only save cursor with this iRoot. Save all if zero */
BtCursor *pExcept /* Do not save this cursor */
){
do{
if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) ){
if( p->eState==CURSOR_VALID ){
int rc = saveCursorPosition(p);
@@ -650,7 +676,8 @@ static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){
btreeReleaseAllCursorPages(p);
}
}
}
p = p->pNext;
}while( p );
return SQLITE_OK;
}
@@ -735,37 +762,48 @@ static int btreeRestoreCursorPosition(BtCursor *pCur){
SQLITE_OK)
/*
** Determine whether or not a cursor has moved from the position it
** was last placed at. Cursors can move when the row they are pointing
** at is deleted out from under them.
** Determine whether or not a cursor has moved from the position where
** it was last placed, or has been invalidated for any other reason.
** Cursors can move when the row they are pointing at is deleted out
** from under them, for example. Cursor might also move if a btree
** is rebalanced.
**
** This routine returns an error code if something goes wrong. The
** integer *pHasMoved is set as follows:
** Calling this routine with a NULL cursor pointer returns false.
**
** 0: The cursor is unchanged
** 1: The cursor is still pointing at the same row, but the pointers
** returned by sqlite3BtreeKeyFetch() or sqlite3BtreeDataFetch()
** might now be invalid because of a balance() or other change to the
** b-tree.
** 2: The cursor is no longer pointing to the row. The row might have
** been deleted out from under the cursor.
** Use the separate sqlite3BtreeCursorRestore() routine to restore a cursor
** back to where it ought to be if this routine returns true.
*/
int sqlite3BtreeCursorHasMoved(BtCursor *pCur, int *pHasMoved){
int sqlite3BtreeCursorHasMoved(BtCursor *pCur){
return pCur && pCur->eState!=CURSOR_VALID;
}
/*
** This routine restores a cursor back to its original position after it
** has been moved by some outside activity (such as a btree rebalance or
** a row having been deleted out from under the cursor).
**
** On success, the *pDifferentRow parameter is false if the cursor is left
** pointing at exactly the same row. *pDifferntRow is the row the cursor
** was pointing to has been deleted, forcing the cursor to point to some
** nearby row.
**
** This routine should only be called for a cursor that just returned
** TRUE from sqlite3BtreeCursorHasMoved().
*/
int sqlite3BtreeCursorRestore(BtCursor *pCur, int *pDifferentRow){
int rc;
if( pCur->eState==CURSOR_VALID ){
*pHasMoved = 0;
return SQLITE_OK;
}
assert( pCur!=0 );
assert( pCur->eState!=CURSOR_VALID );
rc = restoreCursorPosition(pCur);
if( rc ){
*pHasMoved = 2;
*pDifferentRow = 1;
return rc;
}
if( pCur->eState!=CURSOR_VALID || NEVER(pCur->skipNext!=0) ){
*pHasMoved = 2;
*pDifferentRow = 1;
}else{
*pHasMoved = 1;
*pDifferentRow = 0;
}
return SQLITE_OK;
}

View File

@@ -169,7 +169,8 @@ int sqlite3BtreeMovetoUnpacked(
int bias,
int *pRes
);
int sqlite3BtreeCursorHasMoved(BtCursor*, int*);
int sqlite3BtreeCursorHasMoved(BtCursor*);
int sqlite3BtreeCursorRestore(BtCursor*, int*);
int sqlite3BtreeDelete(BtCursor*);
int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey,
const void *pData, int nData,

View File

@@ -286,16 +286,14 @@ void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){
Table *p = 0;
int i;
int nName;
assert( zName!=0 );
nName = sqlite3Strlen30(zName);
/* All mutexes are required for schema access. Make sure we hold them. */
assert( zDatabase!=0 || sqlite3BtreeHoldsAllMutexes(db) );
for(i=OMIT_TEMPDB; i<db->nDb; i++){
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
if( zDatabase!=0 && sqlite3StrICmp(zDatabase, db->aDb[j].zName) ) continue;
assert( sqlite3SchemaMutexHeld(db, j, 0) );
p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName, nName);
p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName);
if( p ) break;
}
return p;
@@ -378,7 +376,6 @@ Table *sqlite3LocateTableItem(
Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const char *zDb){
Index *p = 0;
int i;
int nName = sqlite3Strlen30(zName);
/* All mutexes are required for schema access. Make sure we hold them. */
assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) );
for(i=OMIT_TEMPDB; i<db->nDb; i++){
@@ -387,7 +384,7 @@ Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const char *zDb){
assert( pSchema );
if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zName) ) continue;
assert( sqlite3SchemaMutexHeld(db, j, 0) );
p = sqlite3HashFind(&pSchema->idxHash, zName, nName);
p = sqlite3HashFind(&pSchema->idxHash, zName);
if( p ) break;
}
return p;
@@ -415,13 +412,11 @@ static void freeIndex(sqlite3 *db, Index *p){
*/
void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){
Index *pIndex;
int len;
Hash *pHash;
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
pHash = &db->aDb[iDb].pSchema->idxHash;
len = sqlite3Strlen30(zIdxName);
pIndex = sqlite3HashInsert(pHash, zIdxName, len, 0);
pIndex = sqlite3HashInsert(pHash, zIdxName, 0);
if( ALWAYS(pIndex) ){
if( pIndex->pTable->pIndex==pIndex ){
pIndex->pTable->pIndex = pIndex->pNext;
@@ -581,7 +576,7 @@ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
if( !db || db->pnBytesFreed==0 ){
char *zName = pIndex->zName;
TESTONLY ( Index *pOld = ) sqlite3HashInsert(
&pIndex->pSchema->idxHash, zName, sqlite3Strlen30(zName), 0
&pIndex->pSchema->idxHash, zName, 0
);
assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) );
assert( pOld==pIndex || pOld==0 );
@@ -624,8 +619,7 @@ void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char *zTabName){
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
testcase( zTabName[0]==0 ); /* Zero-length table names are allowed */
pDb = &db->aDb[iDb];
p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName,
sqlite3Strlen30(zTabName),0);
p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName, 0);
sqlite3DeleteTable(db, p);
db->flags |= SQLITE_InternChanges;
}
@@ -1947,8 +1941,7 @@ void sqlite3EndTable(
Table *pOld;
Schema *pSchema = p->pSchema;
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName,
sqlite3Strlen30(p->zName),p);
pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName, p);
if( pOld ){
assert( p==pOld ); /* Malloc must have failed inside HashInsert() */
db->mallocFailed = 1;
@@ -2598,7 +2591,7 @@ void sqlite3CreateForeignKey(
assert( sqlite3SchemaMutexHeld(db, 0, p->pSchema) );
pNextTo = (FKey *)sqlite3HashInsert(&p->pSchema->fkeyHash,
pFKey->zTo, sqlite3Strlen30(pFKey->zTo), (void *)pFKey
pFKey->zTo, (void *)pFKey
);
if( pNextTo==pFKey ){
db->mallocFailed = 1;
@@ -3146,8 +3139,7 @@ Index *sqlite3CreateIndex(
Index *p;
assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) );
p = sqlite3HashInsert(&pIndex->pSchema->idxHash,
pIndex->zName, sqlite3Strlen30(pIndex->zName),
pIndex);
pIndex->zName, pIndex);
if( p ){
assert( p==pIndex ); /* Malloc must have failed */
db->mallocFailed = 1;

View File

@@ -154,11 +154,11 @@ static CollSeq *findCollSeqEntry(
int create /* Create a new entry if true */
){
CollSeq *pColl;
int nName = sqlite3Strlen30(zName);
pColl = sqlite3HashFind(&db->aCollSeq, zName, nName);
pColl = sqlite3HashFind(&db->aCollSeq, zName);
if( 0==pColl && create ){
pColl = sqlite3DbMallocZero(db, 3*sizeof(*pColl) + nName + 1 );
int nName = sqlite3Strlen30(zName);
pColl = sqlite3DbMallocZero(db, 3*sizeof(*pColl) + nName + 1);
if( pColl ){
CollSeq *pDel = 0;
pColl[0].zName = (char*)&pColl[3];
@@ -169,7 +169,7 @@ static CollSeq *findCollSeqEntry(
pColl[2].enc = SQLITE_UTF16BE;
memcpy(pColl[0].zName, zName, nName);
pColl[0].zName[nName] = 0;
pDel = sqlite3HashInsert(&db->aCollSeq, pColl[0].zName, nName, pColl);
pDel = sqlite3HashInsert(&db->aCollSeq, pColl[0].zName, pColl);
/* If a malloc() failure occurred in sqlite3HashInsert(), it will
** return the pColl pointer to be deleted (because it wasn't added

View File

@@ -2595,26 +2595,13 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
#ifndef SQLITE_OMIT_CAST
case TK_CAST: {
/* Expressions of the form: CAST(pLeft AS token) */
int aff, to_op;
inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
assert( !ExprHasProperty(pExpr, EP_IntValue) );
aff = sqlite3AffinityType(pExpr->u.zToken, 0);
to_op = aff - SQLITE_AFF_TEXT + OP_ToText;
assert( to_op==OP_ToText || aff!=SQLITE_AFF_TEXT );
assert( to_op==OP_ToBlob || aff!=SQLITE_AFF_NONE );
assert( to_op==OP_ToNumeric || aff!=SQLITE_AFF_NUMERIC );
assert( to_op==OP_ToInt || aff!=SQLITE_AFF_INTEGER );
assert( to_op==OP_ToReal || aff!=SQLITE_AFF_REAL );
testcase( to_op==OP_ToText );
testcase( to_op==OP_ToBlob );
testcase( to_op==OP_ToNumeric );
testcase( to_op==OP_ToInt );
testcase( to_op==OP_ToReal );
if( inReg!=target ){
sqlite3VdbeAddOp2(v, OP_SCopy, inReg, target);
inReg = target;
}
sqlite3VdbeAddOp1(v, to_op, inReg);
sqlite3VdbeAddOp2(v, OP_Cast, target,
sqlite3AffinityType(pExpr->u.zToken, 0));
testcase( usedAsColumnCache(pParse, inReg, inReg) );
sqlite3ExprCacheAffinityChange(pParse, inReg, 1);
break;

View File

@@ -659,8 +659,7 @@ static void fkScanChildren(
** table).
*/
FKey *sqlite3FkReferences(Table *pTab){
int nName = sqlite3Strlen30(pTab->zName);
return (FKey *)sqlite3HashFind(&pTab->pSchema->fkeyHash, pTab->zName, nName);
return (FKey *)sqlite3HashFind(&pTab->pSchema->fkeyHash, pTab->zName);
}
/*
@@ -1338,7 +1337,7 @@ void sqlite3FkDelete(sqlite3 *db, Table *pTab){
}else{
void *p = (void *)pFKey->pNextTo;
const char *z = (p ? pFKey->pNextTo->zTo : pFKey->zTo);
sqlite3HashInsert(&pTab->pSchema->fkeyHash, z, sqlite3Strlen30(z), p);
sqlite3HashInsert(&pTab->pSchema->fkeyHash, z, p);
}
if( pFKey->pNextTo ){
pFKey->pNextTo->pPrevTo = pFKey->pPrevTo;

View File

@@ -52,12 +52,11 @@ void sqlite3HashClear(Hash *pH){
/*
** The hashing function.
*/
static unsigned int strHash(const char *z, int nKey){
static unsigned int strHash(const char *z){
unsigned int h = 0;
assert( nKey>=0 );
while( nKey > 0 ){
h = (h<<3) ^ h ^ sqlite3UpperToLower[(unsigned char)*z++];
nKey--;
unsigned char c;
while( (c = (unsigned char)*z++)!=0 ){
h = (h<<3) ^ h ^ sqlite3UpperToLower[c];
}
return h;
}
@@ -129,7 +128,7 @@ static int rehash(Hash *pH, unsigned int new_size){
pH->htsize = new_size = sqlite3MallocSize(new_ht)/sizeof(struct _ht);
memset(new_ht, 0, new_size*sizeof(struct _ht));
for(elem=pH->first, pH->first=0; elem; elem = next_elem){
unsigned int h = strHash(elem->pKey, elem->nKey) % new_size;
unsigned int h = strHash(elem->pKey) % new_size;
next_elem = elem->next;
insertElement(pH, &new_ht[h], elem);
}
@@ -137,28 +136,33 @@ 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 has
** already been computed and is passed as the 4th parameter.
** hash table that matches the given key. The hash for this key is
** also computed and returned in the *pH parameter.
*/
static HashElem *findElementGivenHash(
static HashElem *findElementWithHash(
const Hash *pH, /* The pH to be searched */
const char *pKey, /* The key we are searching for */
int nKey, /* Bytes in key (not counting zero terminator) */
unsigned int h /* The hash for this key. */
unsigned int *pHash /* Write the hash value here */
){
HashElem *elem; /* Used to loop thru the element list */
int count; /* Number of elements left to test */
unsigned int h; /* The computed hash */
if( pH->ht ){
struct _ht *pEntry = &pH->ht[h];
struct _ht *pEntry;
h = strHash(pKey) % pH->htsize;
pEntry = &pH->ht[h];
elem = pEntry->chain;
count = pEntry->count;
}else{
h = 0;
elem = pH->first;
count = pH->count;
}
while( count-- && ALWAYS(elem) ){
if( elem->nKey==nKey && sqlite3StrNICmp(elem->pKey,pKey,nKey)==0 ){
*pHash = h;
while( count-- ){
assert( elem!=0 );
if( sqlite3StrICmp(elem->pKey,pKey)==0 ){
return elem;
}
elem = elem->next;
@@ -201,26 +205,20 @@ static void removeElementGivenHash(
}
/* Attempt to locate an element of the hash table pH with a key
** that matches pKey,nKey. Return the data for this element if it is
** that matches pKey. Return the data for this element if it is
** found, or NULL if there is no match.
*/
void *sqlite3HashFind(const Hash *pH, const char *pKey, int nKey){
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 );
assert( nKey>=0 );
if( pH->ht ){
h = strHash(pKey, nKey) % pH->htsize;
}else{
h = 0;
}
elem = findElementGivenHash(pH, pKey, nKey, h);
elem = findElementWithHash(pH, pKey, &h);
return elem ? elem->data : 0;
}
/* Insert an element into the hash table pH. The key is pKey,nKey
/* Insert an element into the hash table pH. The key is pKey
** and the data is "data".
**
** If no element exists with a matching key, then a new
@@ -234,20 +232,14 @@ void *sqlite3HashFind(const Hash *pH, const char *pKey, int nKey){
** If the "data" parameter to this function is NULL, then the
** element corresponding to "key" is removed from the hash table.
*/
void *sqlite3HashInsert(Hash *pH, const char *pKey, int nKey, void *data){
void *sqlite3HashInsert(Hash *pH, const char *pKey, void *data){
unsigned int h; /* the hash of the key modulo hash table size */
HashElem *elem; /* Used to loop thru the element list */
HashElem *new_elem; /* New element added to the pH */
assert( pH!=0 );
assert( pKey!=0 );
assert( nKey>=0 );
if( pH->htsize ){
h = strHash(pKey, nKey) % pH->htsize;
}else{
h = 0;
}
elem = findElementGivenHash(pH,pKey,nKey,h);
elem = findElementWithHash(pH,pKey,&h);
if( elem ){
void *old_data = elem->data;
if( data==0 ){
@@ -255,7 +247,6 @@ void *sqlite3HashInsert(Hash *pH, const char *pKey, int nKey, void *data){
}else{
elem->data = data;
elem->pKey = pKey;
assert(nKey==elem->nKey);
}
return old_data;
}
@@ -263,19 +254,14 @@ void *sqlite3HashInsert(Hash *pH, const char *pKey, int nKey, void *data){
new_elem = (HashElem*)sqlite3Malloc( sizeof(HashElem) );
if( new_elem==0 ) return data;
new_elem->pKey = pKey;
new_elem->nKey = nKey;
new_elem->data = data;
pH->count++;
if( pH->count>=10 && pH->count > 2*pH->htsize ){
if( rehash(pH, pH->count*2) ){
assert( pH->htsize>0 );
h = strHash(pKey, nKey) % pH->htsize;
h = strHash(pKey) % pH->htsize;
}
}
if( pH->ht ){
insertElement(pH, &pH->ht[h], new_elem);
}else{
insertElement(pH, 0, new_elem);
}
insertElement(pH, pH->ht ? &pH->ht[h] : 0, new_elem);
return 0;
}

View File

@@ -59,15 +59,15 @@ struct Hash {
struct HashElem {
HashElem *next, *prev; /* Next and previous elements in the table */
void *data; /* Data associated with this element */
const char *pKey; int nKey; /* Key associated with this element */
const char *pKey; /* Key associated with this element */
};
/*
** Access routines. To delete, insert a NULL pointer.
*/
void sqlite3HashInit(Hash*);
void *sqlite3HashInsert(Hash*, const char *pKey, int nKey, void *pData);
void *sqlite3HashFind(const Hash*, const char *pKey, int nKey);
void *sqlite3HashInsert(Hash*, const char *pKey, void *pData);
void *sqlite3HashFind(const Hash*, const char *pKey);
void sqlite3HashClear(Hash*);
/*

View File

@@ -44,7 +44,7 @@ int sqlite3_exec(
if( zSql==0 ) zSql = "";
sqlite3_mutex_enter(db->mutex);
sqlite3Error(db, SQLITE_OK, 0);
sqlite3Error(db, SQLITE_OK);
while( rc==SQLITE_OK && zSql[0] ){
int nCol;
char **azVals = 0;
@@ -102,7 +102,7 @@ int sqlite3_exec(
rc = SQLITE_ABORT;
sqlite3VdbeFinalize((Vdbe *)pStmt);
pStmt = 0;
sqlite3Error(db, SQLITE_ABORT, 0);
sqlite3Error(db, SQLITE_ABORT);
goto exec_out;
}
}
@@ -132,7 +132,7 @@ exec_out:
memcpy(*pzErrMsg, sqlite3_errmsg(db), nErrMsg);
}else{
rc = SQLITE_NOMEM;
sqlite3Error(db, SQLITE_NOMEM, 0);
sqlite3Error(db, SQLITE_NOMEM);
}
}else if( pzErrMsg ){
*pzErrMsg = 0;

View File

@@ -749,7 +749,7 @@ void sqlite3AutoLoadExtensions(sqlite3 *db){
sqlite3_mutex_leave(mutex);
zErrmsg = 0;
if( xInit && (rc = xInit(db, &zErrmsg, &sqlite3Apis))!=0 ){
sqlite3Error(db, rc,
sqlite3ErrorWithMsg(db, rc,
"automatic extension loading failed: %s", zErrmsg);
go = 0;
}

View File

@@ -852,7 +852,7 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){
** SQLITE_BUSY if the connection can not be closed immediately.
*/
if( !forceZombie && connectionIsBusy(db) ){
sqlite3Error(db, SQLITE_BUSY, "unable to close due to unfinalized "
sqlite3ErrorWithMsg(db, SQLITE_BUSY, "unable to close due to unfinalized "
"statements or unfinished backups");
sqlite3_mutex_leave(db->mutex);
return SQLITE_BUSY;
@@ -982,7 +982,7 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
sqlite3HashClear(&db->aModule);
#endif
sqlite3Error(db, SQLITE_OK, 0); /* Deallocates any cached error strings. */
sqlite3Error(db, SQLITE_OK); /* Deallocates any cached error strings. */
sqlite3ValueFree(db->pErr);
sqlite3CloseExtensions(db);
@@ -1415,7 +1415,7 @@ int sqlite3CreateFunc(
p = sqlite3FindFunction(db, zFunctionName, nName, nArg, (u8)enc, 0);
if( p && (p->funcFlags & SQLITE_FUNC_ENCMASK)==enc && p->nArg==nArg ){
if( db->nVdbeActive ){
sqlite3Error(db, SQLITE_BUSY,
sqlite3ErrorWithMsg(db, SQLITE_BUSY,
"unable to delete/modify user-function due to active statements");
assert( !db->mallocFailed );
return SQLITE_BUSY;
@@ -1774,10 +1774,10 @@ int sqlite3_wal_checkpoint_v2(
}
if( iDb<0 ){
rc = SQLITE_ERROR;
sqlite3Error(db, SQLITE_ERROR, "unknown database: %s", zDb);
sqlite3ErrorWithMsg(db, SQLITE_ERROR, "unknown database: %s", zDb);
}else{
rc = sqlite3Checkpoint(db, iDb, eMode, pnLog, pnCkpt);
sqlite3Error(db, rc, 0);
sqlite3Error(db, rc);
}
rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
@@ -1932,7 +1932,7 @@ const void *sqlite3_errmsg16(sqlite3 *db){
}else{
z = sqlite3_value_text16(db->pErr);
if( z==0 ){
sqlite3Error(db, db->errCode, sqlite3ErrStr(db->errCode));
sqlite3ErrorWithMsg(db, db->errCode, sqlite3ErrStr(db->errCode));
z = sqlite3_value_text16(db->pErr);
}
/* A malloc() may have failed within the call to sqlite3_value_text16()
@@ -2019,7 +2019,6 @@ static int createCollation(
){
CollSeq *pColl;
int enc2;
int nName = sqlite3Strlen30(zName);
assert( sqlite3_mutex_held(db->mutex) );
@@ -2044,7 +2043,7 @@ static int createCollation(
pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, 0);
if( pColl && pColl->xCmp ){
if( db->nVdbeActive ){
sqlite3Error(db, SQLITE_BUSY,
sqlite3ErrorWithMsg(db, SQLITE_BUSY,
"unable to delete/modify collation sequence due to active statements");
return SQLITE_BUSY;
}
@@ -2058,7 +2057,7 @@ static int createCollation(
** to be called.
*/
if( (pColl->enc & ~SQLITE_UTF16_ALIGNED)==enc2 ){
CollSeq *aColl = sqlite3HashFind(&db->aCollSeq, zName, nName);
CollSeq *aColl = sqlite3HashFind(&db->aCollSeq, zName);
int j;
for(j=0; j<3; j++){
CollSeq *p = &aColl[j];
@@ -2078,7 +2077,7 @@ static int createCollation(
pColl->pUser = pCtx;
pColl->xDel = xDel;
pColl->enc = (u8)(enc2 | (enc & SQLITE_UTF16_ALIGNED));
sqlite3Error(db, SQLITE_OK, 0);
sqlite3Error(db, SQLITE_OK);
return SQLITE_OK;
}
@@ -2563,7 +2562,7 @@ static int openDatabase(
rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
sqlite3Error(db, rc, zErrMsg ? "%s" : 0, zErrMsg);
sqlite3ErrorWithMsg(db, rc, zErrMsg ? "%s" : 0, zErrMsg);
sqlite3_free(zErrMsg);
goto opendb_out;
}
@@ -2575,7 +2574,7 @@ static int openDatabase(
if( rc==SQLITE_IOERR_NOMEM ){
rc = SQLITE_NOMEM;
}
sqlite3Error(db, rc, 0);
sqlite3Error(db, rc);
goto opendb_out;
}
db->aDb[0].pSchema = sqlite3SchemaGet(db, db->aDb[0].pBt);
@@ -2599,7 +2598,7 @@ static int openDatabase(
** database schema yet. This is delayed until the first time the database
** is accessed.
*/
sqlite3Error(db, SQLITE_OK, 0);
sqlite3Error(db, SQLITE_OK);
sqlite3RegisterBuiltinFunctions(db);
/* Load automatic extensions - extensions that have been registered
@@ -2656,7 +2655,7 @@ static int openDatabase(
SQLITE_DEFAULT_LOCKING_MODE);
#endif
if( rc ) sqlite3Error(db, rc, 0);
if( rc ) sqlite3Error(db, rc);
/* Enable the lookaside-malloc subsystem */
setupLookaside(db, 0, sqlite3GlobalConfig.szLookaside,
@@ -3018,7 +3017,7 @@ error_out:
zColumnName);
rc = SQLITE_ERROR;
}
sqlite3Error(db, rc, (zErrMsg?"%s":0), zErrMsg);
sqlite3ErrorWithMsg(db, rc, (zErrMsg?"%s":0), zErrMsg);
sqlite3DbFree(db, zErrMsg);
rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);

View File

@@ -352,22 +352,20 @@ void *sqlite3ScratchMalloc(int n){
assert( n>0 );
sqlite3_mutex_enter(mem0.mutex);
sqlite3StatusSet(SQLITE_STATUS_SCRATCH_SIZE, n);
if( mem0.nScratchFree && sqlite3GlobalConfig.szScratch>=n ){
p = mem0.pScratchFree;
mem0.pScratchFree = mem0.pScratchFree->pNext;
mem0.nScratchFree--;
sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_USED, 1);
sqlite3StatusSet(SQLITE_STATUS_SCRATCH_SIZE, n);
sqlite3_mutex_leave(mem0.mutex);
}else{
if( sqlite3GlobalConfig.bMemstat ){
sqlite3StatusSet(SQLITE_STATUS_SCRATCH_SIZE, n);
n = mallocWithAlarm(n, &p);
if( p ) sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_OVERFLOW, n);
sqlite3_mutex_leave(mem0.mutex);
p = sqlite3Malloc(n);
if( sqlite3GlobalConfig.bMemstat && p ){
sqlite3_mutex_enter(mem0.mutex);
sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_OVERFLOW, sqlite3MallocSize(p));
sqlite3_mutex_leave(mem0.mutex);
}else{
sqlite3_mutex_leave(mem0.mutex);
p = sqlite3GlobalConfig.m.xMalloc(n);
}
sqlite3MemdebugSetType(p, MEMTYPE_SCRATCH);
}
@@ -479,6 +477,14 @@ void sqlite3_free(void *p){
}
}
/*
** Add the size of memory allocation "p" to the count in
** *db->pnBytesFreed.
*/
static SQLITE_NOINLINE void measureAllocationSize(sqlite3 *db, void *p){
*db->pnBytesFreed += sqlite3DbMallocSize(db,p);
}
/*
** Free memory that might be associated with a particular database
** connection.
@@ -488,7 +494,7 @@ void sqlite3DbFree(sqlite3 *db, void *p){
if( p==0 ) return;
if( db ){
if( db->pnBytesFreed ){
*db->pnBytesFreed += sqlite3DbMallocSize(db, p);
measureAllocationSize(db, p);
return;
}
if( isLookaside(db, p) ){
@@ -755,6 +761,14 @@ void sqlite3SetString(char **pz, sqlite3 *db, const char *zFormat, ...){
*pz = z;
}
/*
** Take actions at the end of an API call to indicate an OOM error
*/
static SQLITE_NOINLINE int apiOomError(sqlite3 *db){
db->mallocFailed = 0;
sqlite3Error(db, SQLITE_NOMEM);
return SQLITE_NOMEM;
}
/*
** This function must be called before exiting any API function (i.e.
@@ -775,10 +789,9 @@ int sqlite3ApiExit(sqlite3* db, int rc){
** is unsafe, as is the call to sqlite3Error().
*/
assert( !db || sqlite3_mutex_held(db->mutex) );
if( db && (db->mallocFailed || rc==SQLITE_IOERR_NOMEM) ){
sqlite3Error(db, SQLITE_NOMEM, 0);
db->mallocFailed = 0;
rc = SQLITE_NOMEM;
if( db==0 ) return rc & 0xff;
if( db->mallocFailed || rc==SQLITE_IOERR_NOMEM ){
return apiOomError(db);
}
return rc & (db ? db->errMask : 0xff);
return rc & db->errMask;
}

View File

@@ -184,7 +184,7 @@ int sqlite3_unlock_notify(
leaveMutex();
assert( !db->mallocFailed );
sqlite3Error(db, rc, (rc?"database is deadlocked":0));
sqlite3ErrorWithMsg(db, rc, (rc?"database is deadlocked":0));
sqlite3_mutex_leave(db->mutex);
return rc;
}

View File

@@ -1677,21 +1677,6 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){
return rc;
}
/*
** Find a page in the hash table given its page number. Return
** a pointer to the page or NULL if the requested page is not
** already in memory.
*/
static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){
PgHdr *p = 0; /* Return value */
/* It is not possible for a call to PcacheFetch() with createFlag==0 to
** fail, since no attempt to allocate dynamic memory will be made.
*/
(void)sqlite3PcacheFetch(pPager->pPCache, pgno, 0, &p);
return p;
}
/*
** Discard the entire contents of the in-memory page-cache.
*/
@@ -1984,7 +1969,7 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
#ifdef SQLITE_CHECK_PAGES
sqlite3PcacheIterateDirty(pPager->pPCache, pager_set_pagehash);
if( pPager->dbSize==0 && sqlite3PcacheRefCount(pPager->pPCache)>0 ){
PgHdr *p = pager_lookup(pPager, 1);
PgHdr *p = sqlite3PagerLookup(pPager, 1);
if( p ){
p->pageHash = 0;
sqlite3PagerUnrefNotNull(p);
@@ -2263,7 +2248,7 @@ static int pager_playback_one_page(
if( pagerUseWal(pPager) ){
pPg = 0;
}else{
pPg = pager_lookup(pPager, pgno);
pPg = sqlite3PagerLookup(pPager, pgno);
}
assert( pPg || !MEMDB );
assert( pPager->eState!=PAGER_OPEN || pPg==0 );
@@ -5434,7 +5419,6 @@ DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
assert( pPager!=0 );
assert( pgno!=0 );
assert( pPager->pPCache!=0 );
assert( pPager->eState>=PAGER_READER && pPager->eState!=PAGER_ERROR );
sqlite3PcacheFetch(pPager->pPCache, pgno, 0, &pPg);
return pPg;
}
@@ -5772,6 +5756,97 @@ static int pager_write(PgHdr *pPg){
return rc;
}
/*
** This is a variant of sqlite3PagerWrite() that runs when the sector size
** is larger than the page size. SQLite makes the (reasonable) assumption that
** all bytes of a sector are written together by hardware. Hence, all bytes of
** a sector need to be journalled in case of a power loss in the middle of
** a write.
**
** Usually, the sector size is less than or equal to the page size, in which
** case pages can be individually written. This routine only runs in the exceptional
** case where the page size is smaller than the sector size.
*/
static SQLITE_NOINLINE int pagerWriteLargeSector(PgHdr *pPg){
int rc = SQLITE_OK; /* Return code */
Pgno nPageCount; /* Total number of pages in database file */
Pgno pg1; /* First page of the sector pPg is located on. */
int nPage = 0; /* Number of pages starting at pg1 to journal */
int ii; /* Loop counter */
int needSync = 0; /* True if any page has PGHDR_NEED_SYNC */
Pager *pPager = pPg->pPager; /* The pager that owns pPg */
Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize);
/* Set the doNotSpill NOSYNC bit to 1. This is because we cannot allow
** a journal header to be written between the pages journaled by
** this function.
*/
assert( !MEMDB );
assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)==0 );
pPager->doNotSpill |= SPILLFLAG_NOSYNC;
/* This trick assumes that both the page-size and sector-size are
** an integer power of 2. It sets variable pg1 to the identifier
** of the first page of the sector pPg is located on.
*/
pg1 = ((pPg->pgno-1) & ~(nPagePerSector-1)) + 1;
nPageCount = pPager->dbSize;
if( pPg->pgno>nPageCount ){
nPage = (pPg->pgno - pg1)+1;
}else if( (pg1+nPagePerSector-1)>nPageCount ){
nPage = nPageCount+1-pg1;
}else{
nPage = nPagePerSector;
}
assert(nPage>0);
assert(pg1<=pPg->pgno);
assert((pg1+nPage)>pPg->pgno);
for(ii=0; ii<nPage && rc==SQLITE_OK; ii++){
Pgno pg = pg1+ii;
PgHdr *pPage;
if( pg==pPg->pgno || !sqlite3BitvecTest(pPager->pInJournal, pg) ){
if( pg!=PAGER_MJ_PGNO(pPager) ){
rc = sqlite3PagerGet(pPager, pg, &pPage);
if( rc==SQLITE_OK ){
rc = pager_write(pPage);
if( pPage->flags&PGHDR_NEED_SYNC ){
needSync = 1;
}
sqlite3PagerUnrefNotNull(pPage);
}
}
}else if( (pPage = sqlite3PagerLookup(pPager, pg))!=0 ){
if( pPage->flags&PGHDR_NEED_SYNC ){
needSync = 1;
}
sqlite3PagerUnrefNotNull(pPage);
}
}
/* If the PGHDR_NEED_SYNC flag is set for any of the nPage pages
** starting at pg1, then it needs to be set for all of them. Because
** writing to any of these nPage pages may damage the others, the
** journal file must contain sync()ed copies of all of them
** before any of them can be written out to the database file.
*/
if( rc==SQLITE_OK && needSync ){
assert( !MEMDB );
for(ii=0; ii<nPage; ii++){
PgHdr *pPage = sqlite3PagerLookup(pPager, pg1+ii);
if( pPage ){
pPage->flags |= PGHDR_NEED_SYNC;
sqlite3PagerUnrefNotNull(pPage);
}
}
}
assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)!=0 );
pPager->doNotSpill &= ~SPILLFLAG_NOSYNC;
return rc;
}
/*
** Mark a data page as writeable. This routine must be called before
** making changes to a page. The caller must check the return value
@@ -5786,96 +5861,16 @@ static int pager_write(PgHdr *pPg){
** If an error occurs, SQLITE_NOMEM or an IO error code is returned
** as appropriate. Otherwise, SQLITE_OK.
*/
int sqlite3PagerWrite(DbPage *pDbPage){
int rc = SQLITE_OK;
PgHdr *pPg = pDbPage;
Pager *pPager = pPg->pPager;
int sqlite3PagerWrite(PgHdr *pPg){
assert( (pPg->flags & PGHDR_MMAP)==0 );
assert( pPager->eState>=PAGER_WRITER_LOCKED );
assert( pPager->eState!=PAGER_ERROR );
assert( assert_pager_state(pPager) );
if( pPager->sectorSize > (u32)pPager->pageSize ){
Pgno nPageCount; /* Total number of pages in database file */
Pgno pg1; /* First page of the sector pPg is located on. */
int nPage = 0; /* Number of pages starting at pg1 to journal */
int ii; /* Loop counter */
int needSync = 0; /* True if any page has PGHDR_NEED_SYNC */
Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize);
/* Set the doNotSpill NOSYNC bit to 1. This is because we cannot allow
** a journal header to be written between the pages journaled by
** this function.
*/
assert( !MEMDB );
assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)==0 );
pPager->doNotSpill |= SPILLFLAG_NOSYNC;
/* This trick assumes that both the page-size and sector-size are
** an integer power of 2. It sets variable pg1 to the identifier
** of the first page of the sector pPg is located on.
*/
pg1 = ((pPg->pgno-1) & ~(nPagePerSector-1)) + 1;
nPageCount = pPager->dbSize;
if( pPg->pgno>nPageCount ){
nPage = (pPg->pgno - pg1)+1;
}else if( (pg1+nPagePerSector-1)>nPageCount ){
nPage = nPageCount+1-pg1;
}else{
nPage = nPagePerSector;
}
assert(nPage>0);
assert(pg1<=pPg->pgno);
assert((pg1+nPage)>pPg->pgno);
for(ii=0; ii<nPage && rc==SQLITE_OK; ii++){
Pgno pg = pg1+ii;
PgHdr *pPage;
if( pg==pPg->pgno || !sqlite3BitvecTest(pPager->pInJournal, pg) ){
if( pg!=PAGER_MJ_PGNO(pPager) ){
rc = sqlite3PagerGet(pPager, pg, &pPage);
if( rc==SQLITE_OK ){
rc = pager_write(pPage);
if( pPage->flags&PGHDR_NEED_SYNC ){
needSync = 1;
}
sqlite3PagerUnrefNotNull(pPage);
}
}
}else if( (pPage = pager_lookup(pPager, pg))!=0 ){
if( pPage->flags&PGHDR_NEED_SYNC ){
needSync = 1;
}
sqlite3PagerUnrefNotNull(pPage);
}
}
/* If the PGHDR_NEED_SYNC flag is set for any of the nPage pages
** starting at pg1, then it needs to be set for all of them. Because
** writing to any of these nPage pages may damage the others, the
** journal file must contain sync()ed copies of all of them
** before any of them can be written out to the database file.
*/
if( rc==SQLITE_OK && needSync ){
assert( !MEMDB );
for(ii=0; ii<nPage; ii++){
PgHdr *pPage = pager_lookup(pPager, pg1+ii);
if( pPage ){
pPage->flags |= PGHDR_NEED_SYNC;
sqlite3PagerUnrefNotNull(pPage);
}
}
}
assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)!=0 );
pPager->doNotSpill &= ~SPILLFLAG_NOSYNC;
assert( pPg->pPager->eState>=PAGER_WRITER_LOCKED );
assert( pPg->pPager->eState!=PAGER_ERROR );
assert( assert_pager_state(pPg->pPager) );
if( pPg->pPager->sectorSize > (u32)pPg->pPager->pageSize ){
return pagerWriteLargeSector(pPg);
}else{
rc = pager_write(pDbPage);
return pager_write(pPg);
}
return rc;
}
/*
@@ -6771,7 +6766,7 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){
** for the page moved there.
*/
pPg->flags &= ~PGHDR_NEED_SYNC;
pPgOld = pager_lookup(pPager, pgno);
pPgOld = sqlite3PagerLookup(pPager, pgno);
assert( !pPgOld || pPgOld->nRef==1 );
if( pPgOld ){
pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC);

View File

@@ -62,71 +62,73 @@ static int pcacheCheckSynced(PCache *pCache){
}
#endif /* !NDEBUG && SQLITE_ENABLE_EXPENSIVE_ASSERT */
/*
** Remove page pPage from the list of dirty pages.
*/
static void pcacheRemoveFromDirtyList(PgHdr *pPage){
PCache *p = pPage->pCache;
assert( pPage->pDirtyNext || pPage==p->pDirtyTail );
assert( pPage->pDirtyPrev || pPage==p->pDirty );
/* Update the PCache1.pSynced variable if necessary. */
if( p->pSynced==pPage ){
PgHdr *pSynced = pPage->pDirtyPrev;
while( pSynced && (pSynced->flags&PGHDR_NEED_SYNC) ){
pSynced = pSynced->pDirtyPrev;
}
p->pSynced = pSynced;
}
if( pPage->pDirtyNext ){
pPage->pDirtyNext->pDirtyPrev = pPage->pDirtyPrev;
}else{
assert( pPage==p->pDirtyTail );
p->pDirtyTail = pPage->pDirtyPrev;
}
if( pPage->pDirtyPrev ){
pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext;
}else{
assert( pPage==p->pDirty );
p->pDirty = pPage->pDirtyNext;
if( p->pDirty==0 && p->bPurgeable ){
assert( p->eCreate==1 );
p->eCreate = 2;
}
}
pPage->pDirtyNext = 0;
pPage->pDirtyPrev = 0;
expensive_assert( pcacheCheckSynced(p) );
}
/* Allowed values for second argument to pcacheManageDirtyList() */
#define PCACHE_DIRTYLIST_REMOVE 1 /* Remove pPage from dirty list */
#define PCACHE_DIRTYLIST_ADD 2 /* Add pPage to the dirty list */
#define PCACHE_DIRTYLIST_FRONT 3 /* Move pPage to the front of the list */
/*
** Add page pPage to the head of the dirty list (PCache1.pDirty is set to
** pPage).
** Manage pPage's participation on the dirty list. Bits of the addRemove
** argument determines what operation to do. The 0x01 bit means first
** remove pPage from the dirty list. The 0x02 means add pPage back to
** the dirty list. Doing both moves pPage to the front of the dirty list.
*/
static void pcacheAddToDirtyList(PgHdr *pPage){
static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
PCache *p = pPage->pCache;
assert( pPage->pDirtyNext==0 && pPage->pDirtyPrev==0 && p->pDirty!=pPage );
if( addRemove & PCACHE_DIRTYLIST_REMOVE ){
assert( pPage->pDirtyNext || pPage==p->pDirtyTail );
assert( pPage->pDirtyPrev || pPage==p->pDirty );
pPage->pDirtyNext = p->pDirty;
if( pPage->pDirtyNext ){
assert( pPage->pDirtyNext->pDirtyPrev==0 );
pPage->pDirtyNext->pDirtyPrev = pPage;
}else if( p->bPurgeable ){
assert( p->eCreate==2 );
p->eCreate = 1;
/* Update the PCache1.pSynced variable if necessary. */
if( p->pSynced==pPage ){
PgHdr *pSynced = pPage->pDirtyPrev;
while( pSynced && (pSynced->flags&PGHDR_NEED_SYNC) ){
pSynced = pSynced->pDirtyPrev;
}
p->pSynced = pSynced;
}
if( pPage->pDirtyNext ){
pPage->pDirtyNext->pDirtyPrev = pPage->pDirtyPrev;
}else{
assert( pPage==p->pDirtyTail );
p->pDirtyTail = pPage->pDirtyPrev;
}
if( pPage->pDirtyPrev ){
pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext;
}else{
assert( pPage==p->pDirty );
p->pDirty = pPage->pDirtyNext;
if( p->pDirty==0 && p->bPurgeable ){
assert( p->eCreate==1 );
p->eCreate = 2;
}
}
pPage->pDirtyNext = 0;
pPage->pDirtyPrev = 0;
expensive_assert( pcacheCheckSynced(p) );
}
p->pDirty = pPage;
if( !p->pDirtyTail ){
p->pDirtyTail = pPage;
if( addRemove & PCACHE_DIRTYLIST_ADD ){
assert( pPage->pDirtyNext==0 && pPage->pDirtyPrev==0 && p->pDirty!=pPage );
pPage->pDirtyNext = p->pDirty;
if( pPage->pDirtyNext ){
assert( pPage->pDirtyNext->pDirtyPrev==0 );
pPage->pDirtyNext->pDirtyPrev = pPage;
}else if( p->bPurgeable ){
assert( p->eCreate==2 );
p->eCreate = 1;
}
p->pDirty = pPage;
if( !p->pDirtyTail ){
p->pDirtyTail = pPage;
}
if( !p->pSynced && 0==(pPage->flags&PGHDR_NEED_SYNC) ){
p->pSynced = pPage;
}
expensive_assert( pcacheCheckSynced(p) );
}
if( !p->pSynced && 0==(pPage->flags&PGHDR_NEED_SYNC) ){
p->pSynced = pPage;
}
expensive_assert( pcacheCheckSynced(p) );
}
/*
@@ -134,12 +136,11 @@ static void pcacheAddToDirtyList(PgHdr *pPage){
** being used for an in-memory database, this function is a no-op.
*/
static void pcacheUnpin(PgHdr *p){
PCache *pCache = p->pCache;
if( pCache->bPurgeable ){
if( p->pCache->bPurgeable ){
if( p->pgno==1 ){
pCache->pPage1 = 0;
p->pCache->pPage1 = 0;
}
sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, p->pPage, 0);
sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 0);
}
}
@@ -332,18 +333,16 @@ int sqlite3PcacheFetch(
** Decrement the reference count on a page. If the page is clean and the
** reference count drops to 0, then it is made elible for recycling.
*/
void sqlite3PcacheRelease(PgHdr *p){
void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){
assert( p->nRef>0 );
p->nRef--;
if( p->nRef==0 ){
PCache *pCache = p->pCache;
pCache->nRef--;
p->pCache->nRef--;
if( (p->flags&PGHDR_DIRTY)==0 ){
pcacheUnpin(p);
}else{
/* Move the page to the head of the dirty list. */
pcacheRemoveFromDirtyList(p);
pcacheAddToDirtyList(p);
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
}
}
}
@@ -362,17 +361,15 @@ void sqlite3PcacheRef(PgHdr *p){
** page pointed to by p is invalid.
*/
void sqlite3PcacheDrop(PgHdr *p){
PCache *pCache;
assert( p->nRef==1 );
if( p->flags&PGHDR_DIRTY ){
pcacheRemoveFromDirtyList(p);
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE);
}
pCache = p->pCache;
pCache->nRef--;
p->pCache->nRef--;
if( p->pgno==1 ){
pCache->pPage1 = 0;
p->pCache->pPage1 = 0;
}
sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, p->pPage, 1);
sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 1);
}
/*
@@ -384,7 +381,7 @@ void sqlite3PcacheMakeDirty(PgHdr *p){
assert( p->nRef>0 );
if( 0==(p->flags & PGHDR_DIRTY) ){
p->flags |= PGHDR_DIRTY;
pcacheAddToDirtyList( p);
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_ADD);
}
}
@@ -394,7 +391,7 @@ void sqlite3PcacheMakeDirty(PgHdr *p){
*/
void sqlite3PcacheMakeClean(PgHdr *p){
if( (p->flags & PGHDR_DIRTY) ){
pcacheRemoveFromDirtyList(p);
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE);
p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC);
if( p->nRef==0 ){
pcacheUnpin(p);
@@ -433,8 +430,7 @@ void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
sqlite3GlobalConfig.pcache2.xRekey(pCache->pCache, p->pPage, p->pgno,newPgno);
p->pgno = newPgno;
if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){
pcacheRemoveFromDirtyList(p);
pcacheAddToDirtyList(p);
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
}
}

View File

@@ -383,7 +383,7 @@ static int pcache1UnderMemoryPressure(PCache1 *pCache){
**
** The PCache mutex must be held when this function is called.
*/
static int pcache1ResizeHash(PCache1 *p){
static void pcache1ResizeHash(PCache1 *p){
PgHdr1 **apNew;
unsigned int nNew;
unsigned int i;
@@ -415,8 +415,6 @@ static int pcache1ResizeHash(PCache1 *p){
p->apHash = apNew;
p->nHash = nNew;
}
return (p->apHash ? SQLITE_OK : SQLITE_NOMEM);
}
/*
@@ -551,6 +549,9 @@ static void pcache1Shutdown(void *NotUsed){
memset(&pcache1, 0, sizeof(pcache1));
}
/* forward declaration */
static void pcache1Destroy(sqlite3_pcache *p);
/*
** Implementation of the sqlite3_pcache.xCreate method.
**
@@ -595,12 +596,17 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){
pCache->szPage = szPage;
pCache->szExtra = szExtra;
pCache->bPurgeable = (bPurgeable ? 1 : 0);
pcache1EnterMutex(pGroup);
pcache1ResizeHash(pCache);
if( bPurgeable ){
pCache->nMin = 10;
pcache1EnterMutex(pGroup);
pGroup->nMinPage += pCache->nMin;
pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
pcache1LeaveMutex(pGroup);
}
pcache1LeaveMutex(pGroup);
if( pCache->nHash==0 ){
pcache1Destroy((sqlite3_pcache*)pCache);
pCache = 0;
}
}
return (sqlite3_pcache *)pCache;
@@ -656,6 +662,95 @@ static int pcache1Pagecount(sqlite3_pcache *p){
return n;
}
/*
** Implement steps 3, 4, and 5 of the pcache1Fetch() algorithm described
** in the header of the pcache1Fetch() procedure.
**
** This steps are broken out into a separate procedure because they are
** usually not needed, and by avoiding the stack initialization required
** for these steps, the main pcache1Fetch() procedure can run faster.
*/
static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
PCache1 *pCache,
unsigned int iKey,
int createFlag
){
unsigned int nPinned;
PGroup *pGroup = pCache->pGroup;
PgHdr1 *pPage = 0;
/* Step 3: Abort if createFlag is 1 but the cache is nearly full */
assert( pCache->nPage >= pCache->nRecyclable );
nPinned = pCache->nPage - pCache->nRecyclable;
assert( pGroup->mxPinned == pGroup->nMaxPage + 10 - pGroup->nMinPage );
assert( pCache->n90pct == pCache->nMax*9/10 );
if( createFlag==1 && (
nPinned>=pGroup->mxPinned
|| nPinned>=pCache->n90pct
|| pcache1UnderMemoryPressure(pCache)
)){
return 0;
}
if( pCache->nPage>=pCache->nHash ) pcache1ResizeHash(pCache);
assert( pCache->nHash>0 && pCache->apHash );
/* Step 4. Try to recycle a page. */
if( pCache->bPurgeable && pGroup->pLruTail && (
(pCache->nPage+1>=pCache->nMax)
|| pGroup->nCurrentPage>=pGroup->nMaxPage
|| pcache1UnderMemoryPressure(pCache)
)){
PCache1 *pOther;
pPage = pGroup->pLruTail;
assert( pPage->isPinned==0 );
pcache1RemoveFromHash(pPage);
pcache1PinPage(pPage);
pOther = pPage->pCache;
/* We want to verify that szPage and szExtra are the same for pOther
** and pCache. Assert that we can verify this by comparing sums. */
assert( (pCache->szPage & (pCache->szPage-1))==0 && pCache->szPage>=512 );
assert( pCache->szExtra<512 );
assert( (pOther->szPage & (pOther->szPage-1))==0 && pOther->szPage>=512 );
assert( pOther->szExtra<512 );
if( pOther->szPage+pOther->szExtra != pCache->szPage+pCache->szExtra ){
pcache1FreePage(pPage);
pPage = 0;
}else{
pGroup->nCurrentPage -= (pOther->bPurgeable - pCache->bPurgeable);
}
}
/* Step 5. If a usable page buffer has still not been found,
** attempt to allocate a new one.
*/
if( !pPage ){
if( createFlag==1 ) sqlite3BeginBenignMalloc();
pPage = pcache1AllocPage(pCache);
if( createFlag==1 ) sqlite3EndBenignMalloc();
}
if( pPage ){
unsigned int h = iKey % pCache->nHash;
pCache->nPage++;
pPage->iKey = iKey;
pPage->pNext = pCache->apHash[h];
pPage->pCache = pCache;
pPage->pLruPrev = 0;
pPage->pLruNext = 0;
pPage->isPinned = 1;
*(void **)pPage->page.pExtra = 0;
pCache->apHash[h] = pPage;
if( iKey>pCache->iMaxKey ){
pCache->iMaxKey = iKey;
}
}
return pPage;
}
/*
** Implementation of the sqlite3_pcache.xFetch method.
**
@@ -715,9 +810,7 @@ static sqlite3_pcache_page *pcache1Fetch(
unsigned int iKey,
int createFlag
){
unsigned int nPinned;
PCache1 *pCache = (PCache1 *)p;
PGroup *pGroup;
PgHdr1 *pPage = 0;
assert( offsetof(PgHdr1,page)==0 );
@@ -725,107 +818,22 @@ static sqlite3_pcache_page *pcache1Fetch(
assert( pCache->bPurgeable || pCache->nMin==0 );
assert( pCache->bPurgeable==0 || pCache->nMin==10 );
assert( pCache->nMin==0 || pCache->bPurgeable );
pcache1EnterMutex(pGroup = pCache->pGroup);
assert( pCache->nHash>0 );
pcache1EnterMutex(pCache->pGroup);
/* Step 1: Search the hash table for an existing entry. */
if( pCache->nHash>0 ){
unsigned int h = iKey % pCache->nHash;
for(pPage=pCache->apHash[h]; pPage&&pPage->iKey!=iKey; pPage=pPage->pNext);
}
pPage = pCache->apHash[iKey % pCache->nHash];
while( pPage && pPage->iKey!=iKey ){ pPage = pPage->pNext; }
/* Step 2: Abort if no existing page is found and createFlag is 0 */
if( pPage ){
if( !pPage->isPinned ) pcache1PinPage(pPage);
goto fetch_out;
}else if( createFlag ){
/* Steps 3, 4, and 5 implemented by this subroutine */
pPage = pcache1FetchStage2(pCache, iKey, createFlag);
}
if( createFlag==0 ){
goto fetch_out;
}
/* The pGroup local variable will normally be initialized by the
** pcache1EnterMutex() macro above. But if SQLITE_MUTEX_OMIT is defined,
** then pcache1EnterMutex() is a no-op, so we have to initialize the
** local variable here. Delaying the initialization of pGroup is an
** optimization: The common case is to exit the module before reaching
** this point.
*/
#ifdef SQLITE_MUTEX_OMIT
pGroup = pCache->pGroup;
#endif
/* Step 3: Abort if createFlag is 1 but the cache is nearly full */
assert( pCache->nPage >= pCache->nRecyclable );
nPinned = pCache->nPage - pCache->nRecyclable;
assert( pGroup->mxPinned == pGroup->nMaxPage + 10 - pGroup->nMinPage );
assert( pCache->n90pct == pCache->nMax*9/10 );
if( createFlag==1 && (
nPinned>=pGroup->mxPinned
|| nPinned>=pCache->n90pct
|| pcache1UnderMemoryPressure(pCache)
)){
goto fetch_out;
}
if( pCache->nPage>=pCache->nHash && pcache1ResizeHash(pCache) ){
goto fetch_out;
}
assert( pCache->nHash>0 && pCache->apHash );
/* Step 4. Try to recycle a page. */
if( pCache->bPurgeable && pGroup->pLruTail && (
(pCache->nPage+1>=pCache->nMax)
|| pGroup->nCurrentPage>=pGroup->nMaxPage
|| pcache1UnderMemoryPressure(pCache)
)){
PCache1 *pOther;
pPage = pGroup->pLruTail;
assert( pPage->isPinned==0 );
pcache1RemoveFromHash(pPage);
pcache1PinPage(pPage);
pOther = pPage->pCache;
/* We want to verify that szPage and szExtra are the same for pOther
** and pCache. Assert that we can verify this by comparing sums. */
assert( (pCache->szPage & (pCache->szPage-1))==0 && pCache->szPage>=512 );
assert( pCache->szExtra<512 );
assert( (pOther->szPage & (pOther->szPage-1))==0 && pOther->szPage>=512 );
assert( pOther->szExtra<512 );
if( pOther->szPage+pOther->szExtra != pCache->szPage+pCache->szExtra ){
pcache1FreePage(pPage);
pPage = 0;
}else{
pGroup->nCurrentPage -= (pOther->bPurgeable - pCache->bPurgeable);
}
}
/* Step 5. If a usable page buffer has still not been found,
** attempt to allocate a new one.
*/
if( !pPage ){
if( createFlag==1 ) sqlite3BeginBenignMalloc();
pPage = pcache1AllocPage(pCache);
if( createFlag==1 ) sqlite3EndBenignMalloc();
}
if( pPage ){
unsigned int h = iKey % pCache->nHash;
pCache->nPage++;
pPage->iKey = iKey;
pPage->pNext = pCache->apHash[h];
pPage->pCache = pCache;
pPage->pLruPrev = 0;
pPage->pLruNext = 0;
pPage->isPinned = 1;
*(void **)pPage->page.pExtra = 0;
pCache->apHash[h] = pPage;
}
fetch_out:
if( pPage && iKey>pCache->iMaxKey ){
pCache->iMaxKey = iKey;
}
pcache1LeaveMutex(pGroup);
assert( pPage==0 || pCache->iMaxKey>=iKey );
pcache1LeaveMutex(pCache->pGroup);
return (sqlite3_pcache_page*)pPage;
}

View File

@@ -593,7 +593,7 @@ static int sqlite3Prepare(
rc = sqlite3BtreeSchemaLocked(pBt);
if( rc ){
const char *zDb = db->aDb[i].zName;
sqlite3Error(db, rc, "database schema is locked: %s", zDb);
sqlite3ErrorWithMsg(db, rc, "database schema is locked: %s", zDb);
testcase( db->flags & SQLITE_ReadUncommitted );
goto end_prepare;
}
@@ -610,7 +610,7 @@ static int sqlite3Prepare(
testcase( nBytes==mxLen );
testcase( nBytes==mxLen+1 );
if( nBytes>mxLen ){
sqlite3Error(db, SQLITE_TOOBIG, "statement too long");
sqlite3ErrorWithMsg(db, SQLITE_TOOBIG, "statement too long");
rc = sqlite3ApiExit(db, SQLITE_TOOBIG);
goto end_prepare;
}
@@ -677,10 +677,10 @@ static int sqlite3Prepare(
}
if( zErrMsg ){
sqlite3Error(db, rc, "%s", zErrMsg);
sqlite3ErrorWithMsg(db, rc, "%s", zErrMsg);
sqlite3DbFree(db, zErrMsg);
}else{
sqlite3Error(db, rc, 0);
sqlite3Error(db, rc);
}
/* Delete any TriggerPrg structures allocated while parsing this statement. */

View File

@@ -784,7 +784,7 @@ void sqlite3AppendSpace(StrAccum *p, int N){
** work (enlarging the buffer) using tail recursion, so that the
** sqlite3StrAccumAppend() routine can use fast calling semantics.
*/
static void enlargeAndAppend(StrAccum *p, const char *z, int N){
static void SQLITE_NOINLINE enlargeAndAppend(StrAccum *p, const char *z, int N){
N = sqlite3StrAccumEnlarge(p, N);
if( N>0 ){
memcpy(&p->zText[p->nChar], z, N);
@@ -803,11 +803,11 @@ void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
assert( p->accError==0 || p->nAlloc==0 );
if( p->nChar+N >= p->nAlloc ){
enlargeAndAppend(p,z,N);
return;
}else{
assert( p->zText );
p->nChar += N;
memcpy(&p->zText[p->nChar-N], z, N);
}
assert( p->zText );
memcpy(&p->zText[p->nChar], z, N);
p->nChar += N;
}
/*

View File

@@ -153,6 +153,18 @@
# define SQLITE_PTR_TO_INT(X) ((int)(X))
#endif
/*
** A macro to hint to the compiler that a function should not be
** inlined.
*/
#if defined(__GNUC__)
# define SQLITE_NOINLINE __attribute__((noinline))
#elif defined(_MSC_VER)
# define SQLITE_NOINLINE __declspec(noinline)
#else
# define SQLITE_NOINLINE
#endif
/*
** The SQLITE_THREADSAFE macro must be defined as 0, 1, or 2.
** 0 means mutexes are permanently disable and the library is never
@@ -3307,38 +3319,23 @@ u64 sqlite3LogEstToInt(LogEst);
/*
** Routines to read and write variable-length integers. These used to
** be defined locally, but now we use the varint routines in the util.c
** file. Code should use the MACRO forms below, as the Varint32 versions
** are coded to assume the single byte case is already handled (which
** the MACRO form does).
** file.
*/
int sqlite3PutVarint(unsigned char*, u64);
int sqlite3PutVarint32(unsigned char*, u32);
u8 sqlite3GetVarint(const unsigned char *, u64 *);
u8 sqlite3GetVarint32(const unsigned char *, u32 *);
int sqlite3VarintLen(u64 v);
/*
** The header of a record consists of a sequence variable-length integers.
** These integers are almost always small and are encoded as a single byte.
** The following macros take advantage this fact to provide a fast encode
** and decode of the integers in a record header. It is faster for the common
** case where the integer is a single byte. It is a little slower when the
** integer is two or more bytes. But overall it is faster.
**
** The following expressions are equivalent:
**
** x = sqlite3GetVarint32( A, &B );
** x = sqlite3PutVarint32( A, B );
**
** x = getVarint32( A, B );
** x = putVarint32( A, B );
**
** The common case is for a varint to be a single byte. They following
** macros handle the common case without a procedure call, but then call
** the procedure for larger varints.
*/
#define getVarint32(A,B) \
(u8)((*(A)<(u8)0x80)?((B)=(u32)*(A)),1:sqlite3GetVarint32((A),(u32 *)&(B)))
#define putVarint32(A,B) \
(u8)(((u32)(B)<(u32)0x80)?(*(A)=(unsigned char)(B)),1:\
sqlite3PutVarint32((A),(B)))
sqlite3PutVarint((A),(B)))
#define getVarint sqlite3GetVarint
#define putVarint sqlite3PutVarint
@@ -3350,7 +3347,8 @@ int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity);
char sqlite3ExprAffinity(Expr *pExpr);
int sqlite3Atoi64(const char*, i64*, int, u8);
int sqlite3DecOrHexToI64(const char*, i64*);
void sqlite3Error(sqlite3*, int, const char*,...);
void sqlite3ErrorWithMsg(sqlite3*, int, const char*,...);
void sqlite3Error(sqlite3*,int);
void *sqlite3HexToBlob(sqlite3*, const char *z, int n);
u8 sqlite3HexToInt(int h);
int sqlite3TwoPartName(Parse *, Token *, Token *, Token **);

View File

@@ -180,8 +180,7 @@ void sqlite3BeginTrigger(
goto trigger_cleanup;
}
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash),
zName, sqlite3Strlen30(zName)) ){
if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash),zName) ){
if( !noErr ){
sqlite3ErrorMsg(pParse, "trigger %T already exists", pName);
}else{
@@ -324,13 +323,12 @@ void sqlite3FinishTrigger(
Trigger *pLink = pTrig;
Hash *pHash = &db->aDb[iDb].pSchema->trigHash;
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
pTrig = sqlite3HashInsert(pHash, zName, sqlite3Strlen30(zName), pTrig);
pTrig = sqlite3HashInsert(pHash, zName, pTrig);
if( pTrig ){
db->mallocFailed = 1;
}else if( pLink->pSchema==pLink->pTabSchema ){
Table *pTab;
int n = sqlite3Strlen30(pLink->table);
pTab = sqlite3HashFind(&pLink->pTabSchema->tblHash, pLink->table, n);
pTab = sqlite3HashFind(&pLink->pTabSchema->tblHash, pLink->table);
assert( pTab!=0 );
pLink->pNext = pTab->pTrigger;
pTab->pTrigger = pLink;
@@ -489,7 +487,6 @@ void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr){
int i;
const char *zDb;
const char *zName;
int nName;
sqlite3 *db = pParse->db;
if( db->mallocFailed ) goto drop_trigger_cleanup;
@@ -500,13 +497,12 @@ void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr){
assert( pName->nSrc==1 );
zDb = pName->a[0].zDatabase;
zName = pName->a[0].zName;
nName = sqlite3Strlen30(zName);
assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) );
for(i=OMIT_TEMPDB; i<db->nDb; i++){
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
if( zDb && sqlite3StrICmp(db->aDb[j].zName, zDb) ) continue;
assert( sqlite3SchemaMutexHeld(db, j, 0) );
pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName, nName);
pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName);
if( pTrigger ) break;
}
if( !pTrigger ){
@@ -529,8 +525,7 @@ drop_trigger_cleanup:
** is set on.
*/
static Table *tableOfTrigger(Trigger *pTrigger){
int n = sqlite3Strlen30(pTrigger->table);
return sqlite3HashFind(&pTrigger->pTabSchema->tblHash, pTrigger->table, n);
return sqlite3HashFind(&pTrigger->pTabSchema->tblHash, pTrigger->table);
}
@@ -602,7 +597,7 @@ void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
pHash = &(db->aDb[iDb].pSchema->trigHash);
pTrigger = sqlite3HashInsert(pHash, zName, sqlite3Strlen30(zName), 0);
pTrigger = sqlite3HashInsert(pHash, zName, 0);
if( ALWAYS(pTrigger) ){
if( pTrigger->pSchema==pTrigger->pTabSchema ){
Table *pTab = tableOfTrigger(pTrigger);

View File

@@ -199,7 +199,7 @@ u32 sqlite3Utf8Read(
** desiredEnc. It is an error if the string is already of the desired
** encoding, or if *pMem does not contain a string value.
*/
int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
int len; /* Maximum length of output string in bytes */
unsigned char *zOut; /* Output buffer */
unsigned char *zIn; /* Input iterator */

View File

@@ -111,6 +111,15 @@ int sqlite3Strlen30(const char *z){
return 0x3fffffff & (int)(z2 - z);
}
/*
** Set the current error code to err_code and clear any prior error message.
*/
void sqlite3Error(sqlite3 *db, int err_code){
assert( db!=0 );
db->errCode = err_code;
if( db->pErr ) sqlite3ValueSetNull(db->pErr);
}
/*
** Set the most recent error code and error string for the sqlite
** handle "db". The error code is set to "err_code".
@@ -132,18 +141,18 @@ int sqlite3Strlen30(const char *z){
** should be called with err_code set to SQLITE_OK and zFormat set
** to NULL.
*/
void sqlite3Error(sqlite3 *db, int err_code, const char *zFormat, ...){
void sqlite3ErrorWithMsg(sqlite3 *db, int err_code, const char *zFormat, ...){
assert( db!=0 );
db->errCode = err_code;
if( zFormat && (db->pErr || (db->pErr = sqlite3ValueNew(db))!=0) ){
if( zFormat==0 ){
sqlite3Error(db, err_code);
}else if( db->pErr || (db->pErr = sqlite3ValueNew(db))!=0 ){
char *z;
va_list ap;
va_start(ap, zFormat);
z = sqlite3VMPrintf(db, zFormat, ap);
va_end(ap);
sqlite3ValueSetStr(db->pErr, -1, z, SQLITE_UTF8, SQLITE_DYNAMIC);
}else if( db->pErr ){
sqlite3ValueSetNull(db->pErr);
}
}
@@ -157,12 +166,12 @@ void sqlite3Error(sqlite3 *db, int err_code, const char *zFormat, ...){
** %T Insert a token
** %S Insert the first element of a SrcList
**
** This function should be used to report any error that occurs whilst
** This function should be used to report any error that occurs while
** compiling an SQL statement (i.e. within sqlite3_prepare()). The
** last thing the sqlite3_prepare() function does is copy the error
** stored by this function into the database handle using sqlite3Error().
** Function sqlite3Error() should be used during statement execution
** (sqlite3_step() etc.).
** Functions sqlite3Error() or sqlite3ErrorWithMsg() should be used
** during statement execution (sqlite3_step() etc.).
*/
void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
char *zMsg;
@@ -699,7 +708,7 @@ int sqlite3Atoi(const char *z){
** bit clear. Except, if we get to the 9th byte, it stores the full
** 8 bits and is the last byte.
*/
int sqlite3PutVarint(unsigned char *p, u64 v){
static int SQLITE_NOINLINE putVarint64(unsigned char *p, u64 v){
int i, j, n;
u8 buf[10];
if( v & (((u64)0xff000000)<<32) ){
@@ -723,28 +732,17 @@ int sqlite3PutVarint(unsigned char *p, u64 v){
}
return n;
}
/*
** This routine is a faster version of sqlite3PutVarint() that only
** works for 32-bit positive integers and which is optimized for
** the common case of small integers. A MACRO version, putVarint32,
** is provided which inlines the single-byte case. All code should use
** the MACRO version as this function assumes the single-byte case has
** already been handled.
*/
int sqlite3PutVarint32(unsigned char *p, u32 v){
#ifndef putVarint32
if( (v & ~0x7f)==0 ){
p[0] = v;
int sqlite3PutVarint(unsigned char *p, u64 v){
if( v<=0x7f ){
p[0] = v&0x7f;
return 1;
}
#endif
if( (v & ~0x3fff)==0 ){
p[0] = (u8)((v>>7) | 0x80);
p[1] = (u8)(v & 0x7f);
if( v<=0x3fff ){
p[0] = ((v>>7)&0x7f)|0x80;
p[1] = v&0x7f;
return 2;
}
return sqlite3PutVarint(p, v);
return putVarint64(p,v);
}
/*

View File

@@ -156,7 +156,7 @@ int sqlite3_found_count = 0;
** already. Return non-zero if a malloc() fails.
*/
#define Stringify(P, enc) \
if(((P)->flags&(MEM_Str|MEM_Blob))==0 && sqlite3VdbeMemStringify(P,enc)) \
if(((P)->flags&(MEM_Str|MEM_Blob))==0 && sqlite3VdbeMemStringify(P,enc,0)) \
{ goto no_mem; }
/*
@@ -238,8 +238,17 @@ static VdbeCursor *allocateCursor(
** do so without loss of information. In other words, if the string
** looks like a number, convert it into a number. If it does not
** look like a number, leave it alone.
**
** If the bTryForInt flag is true, then extra effort is made to give
** an integer representation. Strings that look like floating point
** values but which have no fractional component (example: '48.00')
** will have a MEM_Int representation when bTryForInt is true.
**
** If bTryForInt is false, then if the input string contains a decimal
** point or exponential notation, the result is only MEM_Real, even
** if there is an exact integer representation of the quantity.
*/
static void applyNumericAffinity(Mem *pRec){
static void applyNumericAffinity(Mem *pRec, int bTryForInt){
double rValue;
i64 iValue;
u8 enc = pRec->enc;
@@ -251,10 +260,9 @@ static void applyNumericAffinity(Mem *pRec){
}else{
pRec->r = rValue;
pRec->flags |= MEM_Real;
if( bTryForInt ) sqlite3VdbeIntegerAffinity(pRec);
}
}
#define ApplyNumericAffinity(X) \
if(((X)->flags&(MEM_Real|MEM_Int))==0){applyNumericAffinity(X);}
/*
** Processing is determine by the affinity parameter:
@@ -285,15 +293,17 @@ static void applyAffinity(
** representation.
*/
if( 0==(pRec->flags&MEM_Str) && (pRec->flags&(MEM_Real|MEM_Int)) ){
sqlite3VdbeMemStringify(pRec, enc);
sqlite3VdbeMemStringify(pRec, enc, 1);
}
pRec->flags &= ~(MEM_Real|MEM_Int);
}else if( affinity!=SQLITE_AFF_NONE ){
assert( affinity==SQLITE_AFF_INTEGER || affinity==SQLITE_AFF_REAL
|| affinity==SQLITE_AFF_NUMERIC );
ApplyNumericAffinity(pRec);
if( pRec->flags & MEM_Real ){
sqlite3VdbeIntegerAffinity(pRec);
if( (pRec->flags & MEM_Int)==0 ){
if( (pRec->flags & MEM_Real)==0 ){
applyNumericAffinity(pRec,1);
}else{
sqlite3VdbeIntegerAffinity(pRec);
}
}
}
}
@@ -308,7 +318,7 @@ int sqlite3_value_numeric_type(sqlite3_value *pVal){
int eType = sqlite3_value_type(pVal);
if( eType==SQLITE_TEXT ){
Mem *pMem = (Mem*)pVal;
applyNumericAffinity(pMem);
applyNumericAffinity(pMem, 0);
eType = sqlite3_value_type(pVal);
}
return eType;
@@ -326,6 +336,24 @@ void sqlite3ValueApplyAffinity(
applyAffinity((Mem *)pVal, affinity, enc);
}
/*
** pMem currently only holds a string type (or maybe a BLOB that we can
** interpret as a string if we want to). Compute its corresponding
** numeric type, if has one. Set the pMem->r and pMem->u.i fields
** accordingly.
*/
static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){
assert( (pMem->flags & (MEM_Int|MEM_Real))==0 );
assert( (pMem->flags & (MEM_Str|MEM_Blob))!=0 );
if( sqlite3AtoF(pMem->z, &pMem->r, pMem->n, pMem->enc)==0 ){
return 0;
}
if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==SQLITE_OK ){
return MEM_Int;
}
return MEM_Real;
}
/*
** Return the numeric type for pMem, either MEM_Int or MEM_Real or both or
** none.
@@ -338,13 +366,7 @@ static u16 numericType(Mem *pMem){
return pMem->flags & (MEM_Int|MEM_Real);
}
if( pMem->flags & (MEM_Str|MEM_Blob) ){
if( sqlite3AtoF(pMem->z, &pMem->r, pMem->n, pMem->enc)==0 ){
return 0;
}
if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==SQLITE_OK ){
return MEM_Int;
}
return MEM_Real;
return computeNumericType(pMem);
}
return 0;
}
@@ -628,7 +650,7 @@ int sqlite3VdbeExec(
assert( pOp->p2<=(p->nMem-p->nCursor) );
pOut = &aMem[pOp->p2];
memAboutToChange(p, pOut);
VdbeMemRelease(pOut);
VdbeMemReleaseExtern(pOut);
pOut->flags = MEM_Int;
}
@@ -1067,7 +1089,7 @@ case OP_Null: { /* out2-prerelease */
while( cnt>0 ){
pOut++;
memAboutToChange(p, pOut);
VdbeMemRelease(pOut);
VdbeMemReleaseExtern(pOut);
pOut->flags = nullFlag;
cnt--;
}
@@ -1153,7 +1175,7 @@ case OP_Move: {
assert( pIn1<=&aMem[(p->nMem-p->nCursor)] );
assert( memIsValid(pIn1) );
memAboutToChange(p, pOut);
VdbeMemRelease(pOut);
VdbeMemReleaseExtern(pOut);
zMalloc = pOut->zMalloc;
memcpy(pOut, pIn1, sizeof(Mem));
#ifdef SQLITE_DEBUG
@@ -1756,106 +1778,36 @@ case OP_RealAffinity: { /* in1 */
#endif
#ifndef SQLITE_OMIT_CAST
/* Opcode: ToText P1 * * * *
/* Opcode: Cast P1 P2 * * *
**
** Force the value in register P1 to be text.
** If the value is numeric, convert it to a string using the
** equivalent of sprintf(). Blob values are unchanged and
** are afterwards simply interpreted as text.
** Force the value in register P1 to be the type defined by P2.
**
** <ul>
** <li value="97"> TEXT
** <li value="98"> BLOB
** <li value="99"> NUMERIC
** <li value="100"> INTEGER
** <li value="101"> REAL
** </ul>
**
** A NULL value is not changed by this routine. It remains NULL.
*/
case OP_ToText: { /* same as TK_TO_TEXT, in1 */
case OP_Cast: { /* in1 */
assert( pOp->p2>=SQLITE_AFF_TEXT && pOp->p2<=SQLITE_AFF_REAL );
testcase( pOp->p2==SQLITE_AFF_TEXT );
testcase( pOp->p2==SQLITE_AFF_NONE );
testcase( pOp->p2==SQLITE_AFF_NUMERIC );
testcase( pOp->p2==SQLITE_AFF_INTEGER );
testcase( pOp->p2==SQLITE_AFF_REAL );
pIn1 = &aMem[pOp->p1];
memAboutToChange(p, pIn1);
if( pIn1->flags & MEM_Null ) break;
assert( MEM_Str==(MEM_Blob>>3) );
pIn1->flags |= (pIn1->flags&MEM_Blob)>>3;
applyAffinity(pIn1, SQLITE_AFF_TEXT, encoding);
rc = ExpandBlob(pIn1);
assert( pIn1->flags & MEM_Str || db->mallocFailed );
pIn1->flags &= ~(MEM_Int|MEM_Real|MEM_Blob|MEM_Zero);
sqlite3VdbeMemCast(pIn1, pOp->p2, encoding);
UPDATE_MAX_BLOBSIZE(pIn1);
break;
}
/* Opcode: ToBlob P1 * * * *
**
** Force the value in register P1 to be a BLOB.
** If the value is numeric, convert it to a string first.
** Strings are simply reinterpreted as blobs with no change
** to the underlying data.
**
** A NULL value is not changed by this routine. It remains NULL.
*/
case OP_ToBlob: { /* same as TK_TO_BLOB, in1 */
pIn1 = &aMem[pOp->p1];
if( pIn1->flags & MEM_Null ) break;
if( (pIn1->flags & MEM_Blob)==0 ){
applyAffinity(pIn1, SQLITE_AFF_TEXT, encoding);
assert( pIn1->flags & MEM_Str || db->mallocFailed );
MemSetTypeFlag(pIn1, MEM_Blob);
}else{
pIn1->flags &= ~(MEM_TypeMask&~MEM_Blob);
}
UPDATE_MAX_BLOBSIZE(pIn1);
break;
}
/* Opcode: ToNumeric P1 * * * *
**
** Force the value in register P1 to be numeric (either an
** integer or a floating-point number.)
** If the value is text or blob, try to convert it to an using the
** equivalent of atoi() or atof() and store 0 if no such conversion
** is possible.
**
** A NULL value is not changed by this routine. It remains NULL.
*/
case OP_ToNumeric: { /* same as TK_TO_NUMERIC, in1 */
pIn1 = &aMem[pOp->p1];
sqlite3VdbeMemNumerify(pIn1);
break;
}
#endif /* SQLITE_OMIT_CAST */
/* Opcode: ToInt P1 * * * *
**
** Force the value in register P1 to be an integer. If
** The value is currently a real number, drop its fractional part.
** If the value is text or blob, try to convert it to an integer using the
** equivalent of atoi() and store 0 if no such conversion is possible.
**
** A NULL value is not changed by this routine. It remains NULL.
*/
case OP_ToInt: { /* same as TK_TO_INT, in1 */
pIn1 = &aMem[pOp->p1];
if( (pIn1->flags & MEM_Null)==0 ){
sqlite3VdbeMemIntegerify(pIn1);
}
break;
}
#if !defined(SQLITE_OMIT_CAST) && !defined(SQLITE_OMIT_FLOATING_POINT)
/* Opcode: ToReal P1 * * * *
**
** Force the value in register P1 to be a floating point number.
** If The value is currently an integer, convert it.
** If the value is text or blob, try to convert it to an integer using the
** equivalent of atoi() and store 0.0 if no such conversion is possible.
**
** A NULL value is not changed by this routine. It remains NULL.
*/
case OP_ToReal: { /* same as TK_TO_REAL, in1 */
pIn1 = &aMem[pOp->p1];
memAboutToChange(p, pIn1);
if( (pIn1->flags & MEM_Null)==0 ){
sqlite3VdbeMemRealify(pIn1);
}
break;
}
#endif /* !defined(SQLITE_OMIT_CAST) && !defined(SQLITE_OMIT_FLOATING_POINT) */
/* Opcode: Lt P1 P2 P3 P4 P5
** Synopsis: if r[P1]<r[P3] goto P2
**
@@ -2526,7 +2478,7 @@ case OP_Column: {
if( pC->szRow>=aOffset[p2+1] ){
/* This is the common case where the desired content fits on the original
** page - where the content is not on an overflow page */
VdbeMemRelease(pDest);
VdbeMemReleaseExtern(pDest);
sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], aType[p2], pDest);
}else{
/* This branch happens only when content is on overflow pages */
@@ -3613,7 +3565,9 @@ case OP_SeekGT: { /* jump, in3 */
** blob, or NULL. But it needs to be an integer before we can do
** the seek, so covert it. */
pIn3 = &aMem[pOp->p3];
ApplyNumericAffinity(pIn3);
if( (pIn3->flags & (MEM_Int|MEM_Real))==0 ){
applyNumericAffinity(pIn3, 0);
}
iKey = sqlite3VdbeIntValue(pIn3);
pC->rowidIsValid = 0;

View File

@@ -437,19 +437,20 @@ void sqlite3VdbeMemSetNull(Mem*);
void sqlite3VdbeMemSetZeroBlob(Mem*,int);
void sqlite3VdbeMemSetRowSet(Mem*);
int sqlite3VdbeMemMakeWriteable(Mem*);
int sqlite3VdbeMemStringify(Mem*, int);
int sqlite3VdbeMemStringify(Mem*, u8, u8);
i64 sqlite3VdbeIntValue(Mem*);
int sqlite3VdbeMemIntegerify(Mem*);
double sqlite3VdbeRealValue(Mem*);
void sqlite3VdbeIntegerAffinity(Mem*);
int sqlite3VdbeMemRealify(Mem*);
int sqlite3VdbeMemNumerify(Mem*);
void sqlite3VdbeMemCast(Mem*,u8,u8);
int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,int,Mem*);
void sqlite3VdbeMemRelease(Mem *p);
void sqlite3VdbeMemReleaseExternal(Mem *p);
#define VdbeMemDynamic(X) \
(((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))!=0)
#define VdbeMemRelease(X) \
#define VdbeMemReleaseExtern(X) \
if( VdbeMemDynamic(X) ) sqlite3VdbeMemReleaseExternal(X);
int sqlite3VdbeMemFinalize(Mem*, FuncDef*);
const char *sqlite3OpcodeName(int);

View File

@@ -606,32 +606,42 @@ void sqlite3InvalidFunction(
sqlite3_free(zErr);
}
/*
** Create a new aggregate context for p and return a pointer to
** its pMem->z element.
*/
static SQLITE_NOINLINE void *createAggContext(sqlite3_context *p, int nByte){
Mem *pMem = p->pMem;
assert( (pMem->flags & MEM_Agg)==0 );
if( nByte<=0 ){
sqlite3VdbeMemReleaseExternal(pMem);
pMem->flags = MEM_Null;
pMem->z = 0;
}else{
sqlite3VdbeMemGrow(pMem, nByte, 0);
pMem->flags = MEM_Agg;
pMem->u.pDef = p->pFunc;
if( pMem->z ){
memset(pMem->z, 0, nByte);
}
}
return (void*)pMem->z;
}
/*
** Allocate or return the aggregate context for a user function. A new
** context is allocated on the first call. Subsequent calls return the
** same context that was returned on prior calls.
*/
void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){
Mem *pMem;
assert( p && p->pFunc && p->pFunc->xStep );
assert( sqlite3_mutex_held(p->s.db->mutex) );
pMem = p->pMem;
testcase( nByte<0 );
if( (pMem->flags & MEM_Agg)==0 ){
if( nByte<=0 ){
sqlite3VdbeMemReleaseExternal(pMem);
pMem->flags = MEM_Null;
pMem->z = 0;
}else{
sqlite3VdbeMemGrow(pMem, nByte, 0);
pMem->flags = MEM_Agg;
pMem->u.pDef = p->pFunc;
if( pMem->z ){
memset(pMem->z, 0, nByte);
}
}
if( (p->pMem->flags & MEM_Agg)==0 ){
return createAggContext(p, nByte);
}else{
return (void*)p->pMem->z;
}
return (void*)pMem->z;
}
/*
@@ -770,7 +780,7 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
}else{
if( pVm && ALWAYS(pVm->db) ){
sqlite3_mutex_enter(pVm->db->mutex);
sqlite3Error(pVm->db, SQLITE_RANGE, 0);
sqlite3Error(pVm->db, SQLITE_RANGE);
}
pOut = (Mem*)columnNullValue();
}
@@ -1035,14 +1045,14 @@ static int vdbeUnbind(Vdbe *p, int i){
}
sqlite3_mutex_enter(p->db->mutex);
if( p->magic!=VDBE_MAGIC_RUN || p->pc>=0 ){
sqlite3Error(p->db, SQLITE_MISUSE, 0);
sqlite3Error(p->db, SQLITE_MISUSE);
sqlite3_mutex_leave(p->db->mutex);
sqlite3_log(SQLITE_MISUSE,
"bind on a busy prepared statement: [%s]", p->zSql);
return SQLITE_MISUSE_BKPT;
}
if( i<1 || i>p->nVar ){
sqlite3Error(p->db, SQLITE_RANGE, 0);
sqlite3Error(p->db, SQLITE_RANGE);
sqlite3_mutex_leave(p->db->mutex);
return SQLITE_RANGE;
}
@@ -1050,7 +1060,7 @@ static int vdbeUnbind(Vdbe *p, int i){
pVar = &p->aVar[i];
sqlite3VdbeMemRelease(pVar);
pVar->flags = MEM_Null;
sqlite3Error(p->db, SQLITE_OK, 0);
sqlite3Error(p->db, SQLITE_OK);
/* If the bit corresponding to this variable in Vdbe.expmask is set, then
** binding a new value to this variable invalidates the current query plan.
@@ -1092,7 +1102,7 @@ static int bindText(
if( rc==SQLITE_OK && encoding!=0 ){
rc = sqlite3VdbeChangeEncoding(pVar, ENC(p->db));
}
sqlite3Error(p->db, rc, 0);
sqlite3Error(p->db, rc);
rc = sqlite3ApiExit(p->db, rc);
}
sqlite3_mutex_leave(p->db->mutex);
@@ -1428,7 +1438,7 @@ int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
}
preupdate_old_out:
sqlite3Error(db, rc, 0);
sqlite3Error(db, rc);
return sqlite3ApiExit(db, rc);
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
@@ -1532,7 +1542,7 @@ int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
*ppValue = pMem;
preupdate_new_out:
sqlite3Error(db, rc, 0);
sqlite3Error(db, rc);
return sqlite3ApiExit(db, rc);
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */

View File

@@ -2498,7 +2498,7 @@ int sqlite3VdbeTransferError(Vdbe *p){
db->mallocFailed = mallocFailed;
db->errCode = rc;
}else{
sqlite3Error(db, rc, 0);
sqlite3Error(db, rc);
}
return rc;
}
@@ -2561,7 +2561,7 @@ int sqlite3VdbeReset(Vdbe *p){
** to sqlite3_step(). For consistency (since sqlite3_step() was
** called), set the database error in this case as well.
*/
sqlite3Error(db, p->rc, p->zErrMsg ? "%s" : 0, p->zErrMsg);
sqlite3ErrorWithMsg(db, p->rc, p->zErrMsg ? "%s" : 0, p->zErrMsg);
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = 0;
}
@@ -2714,6 +2714,48 @@ void sqlite3VdbeDelete(Vdbe *p){
sqlite3DbFree(db, p);
}
/*
** The cursor "p" has a pending seek operation that has not yet been
** carried out. Seek the cursor now. If an error occurs, return
** the appropriate error code.
*/
static int SQLITE_NOINLINE handleDeferredMoveto(VdbeCursor *p){
int res, rc;
#ifdef SQLITE_TEST
extern int sqlite3_search_count;
#endif
assert( p->deferredMoveto );
assert( p->isTable );
rc = sqlite3BtreeMovetoUnpacked(p->pCursor, 0, p->movetoTarget, 0, &res);
if( rc ) return rc;
p->lastRowid = p->movetoTarget;
if( res!=0 ) return SQLITE_CORRUPT_BKPT;
p->rowidIsValid = 1;
#ifdef SQLITE_TEST
sqlite3_search_count++;
#endif
p->deferredMoveto = 0;
p->cacheStatus = CACHE_STALE;
return SQLITE_OK;
}
/*
** Something has moved cursor "p" out of place. Maybe the row it was
** pointed to was deleted out from under it. Or maybe the btree was
** rebalanced. Whatever the cause, try to restore "p" to the place it
** is suppose to be pointing. If the row was deleted out from under the
** cursor, set the cursor to point to a NULL row.
*/
static int SQLITE_NOINLINE handleMovedCursor(VdbeCursor *p){
int isDifferentRow, rc;
assert( p->pCursor!=0 );
assert( sqlite3BtreeCursorHasMoved(p->pCursor) );
rc = sqlite3BtreeCursorRestore(p->pCursor, &isDifferentRow);
p->cacheStatus = CACHE_STALE;
if( isDifferentRow ) p->nullRow = 1;
return rc;
}
/*
** Make sure the cursor p is ready to read or write the row to which it
** was last positioned. Return an error code if an OOM fault or I/O error
@@ -2729,29 +2771,10 @@ void sqlite3VdbeDelete(Vdbe *p){
*/
int sqlite3VdbeCursorMoveto(VdbeCursor *p){
if( p->deferredMoveto ){
int res, rc;
#ifdef SQLITE_TEST
extern int sqlite3_search_count;
#endif
assert( p->isTable );
rc = sqlite3BtreeMovetoUnpacked(p->pCursor, 0, p->movetoTarget, 0, &res);
if( rc ) return rc;
p->lastRowid = p->movetoTarget;
if( res!=0 ) return SQLITE_CORRUPT_BKPT;
p->rowidIsValid = 1;
#ifdef SQLITE_TEST
sqlite3_search_count++;
#endif
p->deferredMoveto = 0;
p->cacheStatus = CACHE_STALE;
}else if( p->pCursor ){
int hasMoved;
int rc = sqlite3BtreeCursorHasMoved(p->pCursor, &hasMoved);
if( rc ) return rc;
if( hasMoved ){
p->cacheStatus = CACHE_STALE;
if( hasMoved==2 ) p->nullRow = 1;
}
return handleDeferredMoveto(p);
}
if( sqlite3BtreeCursorHasMoved(p->pCursor) ){
return handleMovedCursor(p);
}
return SQLITE_OK;
}
@@ -2934,10 +2957,11 @@ u32 sqlite3VdbeSerialPut(u8 *buf, Mem *pMem, u32 serial_type){
v = pMem->u.i;
}
len = i = sqlite3VdbeSerialTypeLen(serial_type);
while( i-- ){
buf[i] = (u8)(v&0xFF);
assert( i>0 );
do{
buf[--i] = (u8)(v&0xFF);
v >>= 8;
}
}while( i );
return len;
}
@@ -2961,18 +2985,54 @@ u32 sqlite3VdbeSerialPut(u8 *buf, Mem *pMem, u32 serial_type){
#define TWO_BYTE_INT(x) (256*(i8)((x)[0])|(x)[1])
#define THREE_BYTE_INT(x) (65536*(i8)((x)[0])|((x)[1]<<8)|(x)[2])
#define FOUR_BYTE_UINT(x) (((u32)(x)[0]<<24)|((x)[1]<<16)|((x)[2]<<8)|(x)[3])
#define FOUR_BYTE_INT(x) (16777216*(i8)((x)[0])|((x)[1]<<16)|((x)[2]<<8)|(x)[3])
/*
** Deserialize the data blob pointed to by buf as serial type serial_type
** and store the result in pMem. Return the number of bytes read.
**
** This function is implemented as two separate routines for performance.
** The few cases that require local variables are broken out into a separate
** routine so that in most cases the overhead of moving the stack pointer
** is avoided.
*/
static u32 SQLITE_NOINLINE serialGet(
const unsigned char *buf, /* Buffer to deserialize from */
u32 serial_type, /* Serial type to deserialize */
Mem *pMem /* Memory cell to write value into */
){
u64 x = FOUR_BYTE_UINT(buf);
u32 y = FOUR_BYTE_UINT(buf+4);
x = (x<<32) + y;
if( serial_type==6 ){
pMem->u.i = *(i64*)&x;
pMem->flags = MEM_Int;
testcase( pMem->u.i<0 );
}else{
#if !defined(NDEBUG) && !defined(SQLITE_OMIT_FLOATING_POINT)
/* Verify that integers and floating point values use the same
** byte order. Or, that if SQLITE_MIXED_ENDIAN_64BIT_FLOAT is
** defined that 64-bit floating point values really are mixed
** endian.
*/
static const u64 t1 = ((u64)0x3ff00000)<<32;
static const double r1 = 1.0;
u64 t2 = t1;
swapMixedEndianFloat(t2);
assert( sizeof(r1)==sizeof(t2) && memcmp(&r1, &t2, sizeof(r1))==0 );
#endif
assert( sizeof(x)==8 && sizeof(pMem->r)==8 );
swapMixedEndianFloat(x);
memcpy(&pMem->r, &x, sizeof(x));
pMem->flags = sqlite3IsNaN(pMem->r) ? MEM_Null : MEM_Real;
}
return 8;
}
u32 sqlite3VdbeSerialGet(
const unsigned char *buf, /* Buffer to deserialize from */
u32 serial_type, /* Serial type to deserialize */
Mem *pMem /* Memory cell to write value into */
){
u64 x;
u32 y;
switch( serial_type ){
case 10: /* Reserved for future use */
case 11: /* Reserved for future use */
@@ -2999,8 +3059,7 @@ u32 sqlite3VdbeSerialGet(
return 3;
}
case 4: { /* 4-byte signed integer */
y = FOUR_BYTE_UINT(buf);
pMem->u.i = (i64)*(int*)&y;
pMem->u.i = FOUR_BYTE_INT(buf);
pMem->flags = MEM_Int;
testcase( pMem->u.i<0 );
return 4;
@@ -3013,32 +3072,9 @@ u32 sqlite3VdbeSerialGet(
}
case 6: /* 8-byte signed integer */
case 7: { /* IEEE floating point */
#if !defined(NDEBUG) && !defined(SQLITE_OMIT_FLOATING_POINT)
/* Verify that integers and floating point values use the same
** byte order. Or, that if SQLITE_MIXED_ENDIAN_64BIT_FLOAT is
** defined that 64-bit floating point values really are mixed
** endian.
*/
static const u64 t1 = ((u64)0x3ff00000)<<32;
static const double r1 = 1.0;
u64 t2 = t1;
swapMixedEndianFloat(t2);
assert( sizeof(r1)==sizeof(t2) && memcmp(&r1, &t2, sizeof(r1))==0 );
#endif
x = FOUR_BYTE_UINT(buf);
y = FOUR_BYTE_UINT(buf+4);
x = (x<<32) | y;
if( serial_type==6 ){
pMem->u.i = *(i64*)&x;
pMem->flags = MEM_Int;
testcase( pMem->u.i<0 );
}else{
assert( sizeof(x)==8 && sizeof(pMem->r)==8 );
swapMixedEndianFloat(x);
memcpy(&pMem->r, &x, sizeof(x));
pMem->flags = sqlite3IsNaN(pMem->r) ? MEM_Null : MEM_Real;
}
return 8;
/* These use local variables, so do them in a separate routine
** to avoid having to move the frame pointer in the common case */
return serialGet(buf,serial_type,pMem);
}
case 8: /* Integer 0 */
case 9: { /* Integer 1 */
@@ -3048,17 +3084,15 @@ u32 sqlite3VdbeSerialGet(
}
default: {
static const u16 aFlag[] = { MEM_Blob|MEM_Ephem, MEM_Str|MEM_Ephem };
u32 len = (serial_type-12)/2;
pMem->z = (char *)buf;
pMem->n = len;
pMem->n = (serial_type-12)/2;
pMem->xDel = 0;
pMem->flags = aFlag[serial_type&1];
return len;
return pMem->n;
}
}
return 0;
}
/*
** This routine is used to allocate sufficient space for an UnpackedRecord
** structure large enough to be used with sqlite3VdbeRecordUnpack() if

View File

@@ -322,7 +322,7 @@ blob_open_out:
if( pBlob && pBlob->pStmt ) sqlite3VdbeFinalize((Vdbe *)pBlob->pStmt);
sqlite3DbFree(db, pBlob);
}
sqlite3Error(db, rc, (zErr ? "%s" : 0), zErr);
sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr);
sqlite3DbFree(db, zErr);
sqlite3ParserReset(pParse);
sqlite3StackFree(db, pParse);
@@ -375,7 +375,7 @@ static int blobReadWrite(
if( n<0 || iOffset<0 || (iOffset+n)>p->nByte ){
/* Request is out of range. Return a transient error. */
rc = SQLITE_ERROR;
sqlite3Error(db, SQLITE_ERROR, 0);
sqlite3Error(db, SQLITE_ERROR);
}else if( v==0 ){
/* If there is no statement handle, then the blob-handle has
** already been invalidated. Return SQLITE_ABORT in this case.
@@ -479,7 +479,7 @@ int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
char *zErr;
rc = blobSeekToRow(p, iRow, &zErr);
if( rc!=SQLITE_OK ){
sqlite3Error(db, rc, (zErr ? "%s" : 0), zErr);
sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr);
sqlite3DbFree(db, zErr);
}
assert( rc!=SQLITE_SCHEMA );

View File

@@ -121,7 +121,7 @@ int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, n);
}
if( pMem->zMalloc==0 ){
VdbeMemRelease(pMem);
VdbeMemReleaseExtern(pMem);
pMem->z = 0;
pMem->flags = MEM_Null;
return SQLITE_NOMEM;
@@ -223,7 +223,8 @@ int sqlite3VdbeMemNulTerminate(Mem *pMem){
** are converted using sqlite3_snprintf(). Converting a BLOB to a string
** is a no-op.
**
** Existing representations MEM_Int and MEM_Real are *not* invalidated.
** Existing representations MEM_Int and MEM_Real are invalidated if
** bForce is true but are retained if bForce is false.
**
** A MEM_Null value will never be passed to this function. This function is
** used for converting values to text for returning to the user (i.e. via
@@ -231,8 +232,7 @@ int sqlite3VdbeMemNulTerminate(Mem *pMem){
** keys are strings. In the former case a NULL pointer is returned the
** user and the later is an internal programming error.
*/
int sqlite3VdbeMemStringify(Mem *pMem, int enc){
int rc = SQLITE_OK;
int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){
int fg = pMem->flags;
const int nByte = 32;
@@ -248,7 +248,7 @@ int sqlite3VdbeMemStringify(Mem *pMem, int enc){
return SQLITE_NOMEM;
}
/* For a Real or Integer, use sqlite3_mprintf() to produce the UTF-8
/* For a Real or Integer, use sqlite3_snprintf() to produce the UTF-8
** string representation of the value. Then, if the required encoding
** is UTF-16le or UTF-16be do a translation.
**
@@ -263,8 +263,9 @@ int sqlite3VdbeMemStringify(Mem *pMem, int enc){
pMem->n = sqlite3Strlen30(pMem->z);
pMem->enc = SQLITE_UTF8;
pMem->flags |= MEM_Str|MEM_Term;
if( bForce ) pMem->flags &= ~(MEM_Int|MEM_Real);
sqlite3VdbeChangeEncoding(pMem, enc);
return rc;
return SQLITE_OK;
}
/*
@@ -299,6 +300,9 @@ int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
** If the memory cell contains a string value that must be freed by
** invoking an external callback, free it now. Calling this function
** does not free any Mem.zMalloc buffer.
**
** The VdbeMemReleaseExtern() macro invokes this routine if only if there
** is work for this routine to do.
*/
void sqlite3VdbeMemReleaseExternal(Mem *p){
assert( p->db==0 || sqlite3_mutex_held(p->db->mutex) );
@@ -318,6 +322,25 @@ void sqlite3VdbeMemReleaseExternal(Mem *p){
}
}
/*
** Release memory held by the Mem p, both external memory cleared
** by p->xDel and memory in p->zMalloc.
**
** This is a helper routine invoked by sqlite3VdbeMemRelease() in
** the uncommon case when there really is memory in p that is
** need of freeing.
*/
static SQLITE_NOINLINE void vdbeMemRelease(Mem *p){
if( VdbeMemDynamic(p) ){
sqlite3VdbeMemReleaseExternal(p);
}
if( p->zMalloc ){
sqlite3DbFree(p->db, p->zMalloc);
p->zMalloc = 0;
}
p->z = 0;
}
/*
** Release any memory held by the Mem. This may leave the Mem in an
** inconsistent state, for example with (Mem.z==0) and
@@ -325,13 +348,12 @@ void sqlite3VdbeMemReleaseExternal(Mem *p){
*/
void sqlite3VdbeMemRelease(Mem *p){
assert( sqlite3VdbeCheckMemInvariants(p) );
VdbeMemRelease(p);
if( p->zMalloc ){
sqlite3DbFree(p->db, p->zMalloc);
p->zMalloc = 0;
if( VdbeMemDynamic(p) || p->zMalloc ){
vdbeMemRelease(p);
}else{
p->z = 0;
}
p->z = 0;
assert( p->xDel==0 ); /* Zeroed by VdbeMemRelease() above */
assert( p->xDel==0 );
}
/*
@@ -387,7 +409,6 @@ i64 sqlite3VdbeIntValue(Mem *pMem){
}else if( flags & (MEM_Str|MEM_Blob) ){
i64 value = 0;
assert( pMem->z || pMem->n==0 );
testcase( pMem->z==0 );
sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc);
return value;
}else{
@@ -500,6 +521,51 @@ int sqlite3VdbeMemNumerify(Mem *pMem){
return SQLITE_OK;
}
/*
** Cast the datatype of the value in pMem according to the affinity
** "aff". Casting is different from applying affinity in that a cast
** is forced. In other words, the value is converted into the desired
** affinity even if that results in loss of data. This routine is
** used (for example) to implement the SQL "cast()" operator.
*/
void sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){
if( pMem->flags & MEM_Null ) return;
switch( aff ){
case SQLITE_AFF_NONE: { /* Really a cast to BLOB */
if( (pMem->flags & MEM_Blob)==0 ){
sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT, encoding);
assert( pMem->flags & MEM_Str || pMem->db->mallocFailed );
MemSetTypeFlag(pMem, MEM_Blob);
}else{
pMem->flags &= ~(MEM_TypeMask&~MEM_Blob);
}
break;
}
case SQLITE_AFF_NUMERIC: {
sqlite3VdbeMemNumerify(pMem);
break;
}
case SQLITE_AFF_INTEGER: {
sqlite3VdbeMemIntegerify(pMem);
break;
}
case SQLITE_AFF_REAL: {
sqlite3VdbeMemRealify(pMem);
break;
}
default: {
assert( aff==SQLITE_AFF_TEXT );
assert( MEM_Str==(MEM_Blob>>3) );
pMem->flags |= (pMem->flags&MEM_Blob)>>3;
sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT, encoding);
assert( pMem->flags & MEM_Str || pMem->db->mallocFailed );
pMem->flags &= ~(MEM_Int|MEM_Real|MEM_Blob|MEM_Zero);
break;
}
}
}
/*
** Delete any previous value and set the value stored in *pMem to NULL.
*/
@@ -637,7 +703,7 @@ void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){
*/
void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){
assert( (pFrom->flags & MEM_RowSet)==0 );
VdbeMemRelease(pTo);
VdbeMemReleaseExtern(pTo);
memcpy(pTo, pFrom, MEMCELLSIZE);
pTo->xDel = 0;
if( (pFrom->flags&MEM_Static)==0 ){
@@ -655,7 +721,7 @@ int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){
int rc = SQLITE_OK;
assert( (pFrom->flags & MEM_RowSet)==0 );
VdbeMemRelease(pTo);
VdbeMemReleaseExtern(pTo);
memcpy(pTo, pFrom, MEMCELLSIZE);
pTo->flags &= ~MEM_Dyn;
pTo->xDel = 0;
@@ -877,7 +943,7 @@ const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){
sqlite3VdbeMemNulTerminate(pVal); /* IMP: R-31275-44060 */
}else{
assert( (pVal->flags&MEM_Blob)==0 );
sqlite3VdbeMemStringify(pVal, enc);
sqlite3VdbeMemStringify(pVal, enc, 0);
assert( 0==(1&SQLITE_PTR_TO_INT(pVal->z)) );
}
assert(pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) || pVal->db==0
@@ -993,9 +1059,20 @@ static int valueFromExpr(
*ppVal = 0;
return SQLITE_OK;
}
op = pExpr->op;
while( (op = pExpr->op)==TK_UPLUS ) pExpr = pExpr->pLeft;
if( NEVER(op==TK_REGISTER) ) op = pExpr->op2;
if( op==TK_CAST ){
u8 aff = sqlite3AffinityType(pExpr->u.zToken,0);
rc = valueFromExpr(db, pExpr->pLeft, enc, aff, ppVal, pCtx);
testcase( rc!=SQLITE_OK );
if( *ppVal ){
sqlite3VdbeMemCast(*ppVal, aff, SQLITE_UTF8);
sqlite3ValueApplyAffinity(*ppVal, affinity, SQLITE_UTF8);
}
return rc;
}
/* Handle negative integers in a single step. This is needed in the
** case when the value is -9223372036854775808.
*/
@@ -1130,7 +1207,7 @@ static void recordFunc(
sqlite3_result_error_nomem(context);
}else{
aRet[0] = nSerial+1;
sqlite3PutVarint(&aRet[1], iSerial);
putVarint32(&aRet[1], iSerial);
sqlite3VdbeSerialPut(&aRet[1+nSerial], argv[0], iSerial);
sqlite3_result_blob(context, aRet, nRet, SQLITE_TRANSIENT);
sqlite3DbFree(db, aRet);

View File

@@ -43,7 +43,7 @@ static int createModule(
sqlite3_mutex_enter(db->mutex);
nName = sqlite3Strlen30(zName);
if( sqlite3HashFind(&db->aModule, zName, nName) ){
if( sqlite3HashFind(&db->aModule, zName) ){
rc = SQLITE_MISUSE_BKPT;
}else{
Module *pMod;
@@ -56,7 +56,7 @@ static int createModule(
pMod->pModule = pModule;
pMod->pAux = pAux;
pMod->xDestroy = xDestroy;
pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,nName,(void*)pMod);
pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,(void*)pMod);
assert( pDel==0 || pDel==pMod );
if( pDel ){
db->mallocFailed = 1;
@@ -425,9 +425,8 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
Table *pOld;
Schema *pSchema = pTab->pSchema;
const char *zName = pTab->zName;
int nName = sqlite3Strlen30(zName);
assert( sqlite3SchemaMutexHeld(db, 0, pSchema) );
pOld = sqlite3HashInsert(&pSchema->tblHash, zName, nName, pTab);
pOld = sqlite3HashInsert(&pSchema->tblHash, zName, pTab);
if( pOld ){
db->mallocFailed = 1;
assert( pTab==pOld ); /* Malloc must have failed inside HashInsert() */
@@ -593,7 +592,7 @@ int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
/* Locate the required virtual table module */
zMod = pTab->azModuleArg[0];
pMod = (Module*)sqlite3HashFind(&db->aModule, zMod, sqlite3Strlen30(zMod));
pMod = (Module*)sqlite3HashFind(&db->aModule, zMod);
if( !pMod ){
const char *zModule = pTab->azModuleArg[0];
@@ -661,7 +660,7 @@ int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){
/* Locate the required virtual table module */
zMod = pTab->azModuleArg[0];
pMod = (Module*)sqlite3HashFind(&db->aModule, zMod, sqlite3Strlen30(zMod));
pMod = (Module*)sqlite3HashFind(&db->aModule, zMod);
/* If the module has been registered and includes a Create method,
** invoke it now. If the module has not been registered, return an
@@ -700,7 +699,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
sqlite3_mutex_enter(db->mutex);
if( !db->pVtabCtx || !(pTab = db->pVtabCtx->pTab) ){
sqlite3Error(db, SQLITE_MISUSE, 0);
sqlite3Error(db, SQLITE_MISUSE);
sqlite3_mutex_leave(db->mutex);
return SQLITE_MISUSE_BKPT;
}
@@ -728,7 +727,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
}
db->pVtabCtx->pTab = 0;
}else{
sqlite3Error(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr);
sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr);
sqlite3DbFree(db, zErr);
rc = SQLITE_ERROR;
}
@@ -1089,7 +1088,7 @@ int sqlite3_vtab_config(sqlite3 *db, int op, ...){
}
va_end(ap);
if( rc!=SQLITE_OK ) sqlite3Error(db, rc, 0);
if( rc!=SQLITE_OK ) sqlite3Error(db, rc);
sqlite3_mutex_leave(db->mutex);
return rc;
}

View File

@@ -2220,6 +2220,7 @@ static int whereRangeScanEst(
iNew = a[0] + ((pLower->eOperator & WO_GT) ? a[1] : 0);
if( iNew>iLower ) iLower = iNew;
nOut--;
pLower = 0;
}
}
@@ -2235,6 +2236,7 @@ static int whereRangeScanEst(
iNew = a[0] + ((pUpper->eOperator & WO_LE) ? a[1] : 0);
if( iNew<iUpper ) iUpper = iNew;
nOut--;
pUpper = 0;
}
}
@@ -2248,10 +2250,8 @@ static int whereRangeScanEst(
if( nNew<nOut ){
nOut = nNew;
}
pLoop->nOut = (LogEst)nOut;
WHERETRACE(0x10, ("range scan regions: %u..%u est=%d\n",
(u32)iLower, (u32)iUpper, nOut));
return SQLITE_OK;
}
}else{
int bDone = 0;
@@ -2262,8 +2262,8 @@ static int whereRangeScanEst(
#else
UNUSED_PARAMETER(pParse);
UNUSED_PARAMETER(pBuilder);
#endif
assert( pLower || pUpper );
#endif
assert( pUpper==0 || (pUpper->wtFlags & TERM_VNULL)==0 );
nNew = whereRangeAdjust(pLower, nOut);
nNew = whereRangeAdjust(pUpper, nNew);

View File

@@ -145,7 +145,7 @@ do_test alter4-2.6 {
} {1 {Cannot add a column with non-constant default}}
do_test alter4-2.7 {
catchsql {
alter table t1 add column d default (-+1);
alter table t1 add column d default (-5+1);
}
} {1 {Cannot add a column with non-constant default}}
do_test alter4-2.99 {

View File

@@ -1088,4 +1088,50 @@ foreach {tn where eqp} {
do_eqp_test 24.$tn "SeLeCt * FROM t5 WHERE $where" $eqp
}
#-------------------------------------------------------------------------
# Test that if stat4 data is available but cannot be used because the
# rhs of a range constraint is a complex expression, the default estimates
# are used instead.
ifcapable stat4&&cte {
do_execsql_test 25.1 {
CREATE TABLE t6(a, b);
WITH ints(i,j) AS (
SELECT 1,1 UNION ALL SELECT i+1,j+1 FROM ints WHERE i<100
) INSERT INTO t6 SELECT * FROM ints;
CREATE INDEX aa ON t6(a);
CREATE INDEX bb ON t6(b);
ANALYZE;
}
# Term (b<?) is estimated at 25%. Better than (a<30) but not as
# good as (a<20).
do_eqp_test 25.2.1 { SELECT * FROM t6 WHERE a<30 AND b<? } {
0 0 0 {SEARCH TABLE t6 USING INDEX bb (b<?)}
}
do_eqp_test 25.2.2 { SELECT * FROM t6 WHERE a<20 AND b<? } {
0 0 0 {SEARCH TABLE t6 USING INDEX aa (a<?)}
}
# Term (b BETWEEN ? AND ?) is estimated at 1/64.
do_eqp_test 25.3.1 {
SELECT * FROM t6 WHERE a BETWEEN 5 AND 10 AND b BETWEEN ? AND ?
} {
0 0 0 {SEARCH TABLE t6 USING INDEX bb (b>? AND b<?)}
}
# Term (b BETWEEN ? AND 60) is estimated to return roughly 15 rows -
# 60 from (b<=60) multiplied by 0.25 for the b>=? term. Better than
# (a<20) but not as good as (a<10).
do_eqp_test 25.4.1 {
SELECT * FROM t6 WHERE a < 10 AND (b BETWEEN ? AND 60)
} {
0 0 0 {SEARCH TABLE t6 USING INDEX aa (a<?)}
}
do_eqp_test 25.4.2 {
SELECT * FROM t6 WHERE a < 20 AND (b BETWEEN ? AND 60)
} {
0 0 0 {SEARCH TABLE t6 USING INDEX bb (b>? AND b<?)}
}
}
finish_test

View File

@@ -117,7 +117,7 @@ foreach {tn analyze_cmd} {
} {
reset_db
do_test 1.$tn.1 {
execsql { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c) }
execsql { CREATE TABLE t1(a INTEGER PRIMARY KEY, b INT, c INT) }
for {set i 0} {$i < 100} {incr i} {
set c [expr int(pow(1.1,$i)/100)]
set b [expr 125 - int(pow(1.1,99-$i))/100]
@@ -161,7 +161,26 @@ foreach {tn analyze_cmd} {
do_eqp_test 1.$tn.3.6 {
SELECT * FROM t1 WHERE b BETWEEN 75 AND 125 AND c BETWEEN 75 AND 125
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)}}
do_eqp_test 1.$tn.3.7 {
SELECT * FROM t1 WHERE b BETWEEN +0 AND +50 AND c BETWEEN +0 AND +50
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)}}
do_eqp_test 1.$tn.3.8 {
SELECT * FROM t1
WHERE b BETWEEN cast('0' AS int) AND cast('50.0' AS real)
AND c BETWEEN cast('0' AS numeric) AND cast('50.0' AS real)
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)}}
do_eqp_test 1.$tn.3.9 {
SELECT * FROM t1 WHERE b BETWEEN +75 AND +125 AND c BETWEEN +75 AND +125
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)}}
do_eqp_test 1.$tn.3.10 {
SELECT * FROM t1
WHERE b BETWEEN cast('75' AS int) AND cast('125.0' AS real)
AND c BETWEEN cast('75' AS numeric) AND cast('125.0' AS real)
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)}}
}
finish_test

View File

@@ -124,6 +124,22 @@ do_execsql_test 1.23 {
SELECT next_char('ab','vocab2','w',null,'binary');
} {c}
do_execsql_test 1.30 {
SELECT rowid FROM t1 WHERE word='rabbit';
} {2}
do_execsql_test 1.31 {
UPDATE t1 SET rowid=2000 WHERE word='rabbit';
SELECT rowid FROM t1 WHERE word='rabbit';
} {2000}
do_execsql_test 1.32 {
INSERT INTO t1(rowid, word) VALUES(3000,'melody');
SELECT rowid, word, matchlen FROM t1 WHERE word MATCH 'melotti'
ORDER BY score LIMIT 3;
} {3000 melody 6}
do_test 1.33 {
catchsql {INSERT INTO t1(rowid, word) VALUES(3000,'garden');}
} {1 {constraint failed}}
do_execsql_test 2.1 {
CREATE VIRTUAL TABLE t2 USING spellfix1;
INSERT INTO t2 (word, soundslike) VALUES('school', 'skuul');