mirror of https://github.com/sqlite/sqlite
Update the sessions branch with the latest trunk changes.
FossilOrigin-Name: d09355050a74344c1cb6d303af9f601cd41e2368
This commit is contained in:
commit
ad1818d9ed
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
** 2013-05-15
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
******************************************************************************
|
||||
**
|
||||
** This SQLite extension implements a rot13() function and a rot13
|
||||
** collating sequence.
|
||||
*/
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
** Perform rot13 encoding on a single ASCII character.
|
||||
*/
|
||||
static unsigned char rot13(unsigned char c){
|
||||
if( c>='a' && c<='z' ){
|
||||
c += 13;
|
||||
if( c>'z' ) c -= 26;
|
||||
}else if( c>='A' && c<='Z' ){
|
||||
c += 13;
|
||||
if( c>'Z' ) c -= 26;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the rot13() function.
|
||||
**
|
||||
** Rotate ASCII alphabetic characters by 13 character positions.
|
||||
** Non-ASCII characters are unchanged. rot13(rot13(X)) should always
|
||||
** equal X.
|
||||
*/
|
||||
static void rot13func(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
const unsigned char *zIn;
|
||||
int nIn;
|
||||
unsigned char *zOut;
|
||||
char *zToFree = 0;
|
||||
int i;
|
||||
char zTemp[100];
|
||||
assert( argc==1 );
|
||||
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
|
||||
zIn = (const unsigned char*)sqlite3_value_text(argv[0]);
|
||||
nIn = sqlite3_value_bytes(argv[0]);
|
||||
if( nIn<sizeof(zTemp)-1 ){
|
||||
zOut = zTemp;
|
||||
}else{
|
||||
zOut = zToFree = sqlite3_malloc( nIn+1 );
|
||||
if( zOut==0 ){
|
||||
sqlite3_result_error_nomem(context);
|
||||
return;
|
||||
}
|
||||
}
|
||||
for(i=0; i<nIn; i++) zOut[i] = rot13(zIn[i]);
|
||||
zOut[i] = 0;
|
||||
sqlite3_result_text(context, (char*)zOut, i, SQLITE_TRANSIENT);
|
||||
sqlite3_free(zToFree);
|
||||
}
|
||||
|
||||
/*
|
||||
** Implement the rot13 collating sequence so that if
|
||||
**
|
||||
** x=y COLLATE rot13
|
||||
**
|
||||
** Then
|
||||
**
|
||||
** rot13(x)=rot13(y) COLLATE binary
|
||||
*/
|
||||
static int rot13CollFunc(
|
||||
void *notUsed,
|
||||
int nKey1, const void *pKey1,
|
||||
int nKey2, const void *pKey2
|
||||
){
|
||||
const char *zA = (const char*)pKey1;
|
||||
const char *zB = (const char*)pKey2;
|
||||
int i, x;
|
||||
for(i=0; i<nKey1 && i<nKey2; i++){
|
||||
x = (int)rot13(zA[i]) - (int)rot13(zB[i]);
|
||||
if( x!=0 ) return x;
|
||||
}
|
||||
return nKey1 - nKey2;
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_rot_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
rc = sqlite3_create_function(db, "rot13", 1, SQLITE_UTF8, 0,
|
||||
rot13func, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_collation(db, "rot13", SQLITE_UTF8, 0, rot13CollFunc);
|
||||
}
|
||||
return rc;
|
||||
}
|
1
main.mk
1
main.mk
|
@ -297,6 +297,7 @@ TESTSRC2 = \
|
|||
$(TOP)/src/func.c \
|
||||
$(TOP)/src/insert.c \
|
||||
$(TOP)/src/wal.c \
|
||||
$(TOP)/src/main.c \
|
||||
$(TOP)/src/mem5.c \
|
||||
$(TOP)/src/os.c \
|
||||
$(TOP)/src/os_unix.c \
|
||||
|
|
24
manifest
24
manifest
|
@ -1,5 +1,5 @@
|
|||
C Merge\strunk\schanges\sinto\sthe\ssessions\sbranch.
|
||||
D 2013-05-09T23:40:59.000
|
||||
C Update\sthe\ssessions\sbranch\swith\sthe\slatest\strunk\schanges.
|
||||
D 2013-05-15T18:45:14.080
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in e2acdd75b30e5f2fd8739c923c746d9d2228fe9a
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
|
@ -89,6 +89,7 @@ F ext/misc/fuzzer.c fb64a15af978ae73fa9075b9b1dfbe82b8defc6f
|
|||
F ext/misc/ieee754.c 2565ce373d842977efe0922dc50b8a41b3289556
|
||||
F ext/misc/nextchar.c 1131e2b36116ffc6fe6b2e3464bfdace27978b1e
|
||||
F ext/misc/regexp.c c25c65fe775f5d9801fb8573e36ebe73f2c0c2e0
|
||||
F ext/misc/rot13.c 1ac6f95f99b575907b9b09c81a349114cf9be45a
|
||||
F ext/misc/spellfix.c f9d24a2b2617cee143b7841b453e4e1fd8f189cc
|
||||
F ext/misc/wholenumber.c 784b12543d60702ebdd47da936e278aa03076212
|
||||
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
|
||||
|
@ -125,7 +126,7 @@ F ext/session/test_session.c 23eddaf713708ae063d278ec6297652e3672dc38
|
|||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt 3f820e18c43504b25da40ff4b4cdb66dc4c4907e
|
||||
F main.mk 06e980ed70c3fa4c27c35ff38735af6e05a64304
|
||||
F main.mk e1aa28b8104784696a7ca9c15d0b6c4bf156ae02
|
||||
F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a
|
||||
F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
|
||||
F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac
|
||||
|
@ -149,16 +150,16 @@ F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
|||
F src/backup.c b266767351ae2d847716c56fcb2a1fea7c761c03
|
||||
F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
|
||||
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
|
||||
F src/btree.c 480a6d255cc4f066029daf23dd54acf152cd0e13
|
||||
F src/btree.c fcfbe61a311e54224b23527bbf7586ce320e7b40
|
||||
F src/btree.h 6fa8a3ff2483d0bb64a9f0105a8cedeac9e00cca
|
||||
F src/btreeInt.h eecc84f02375b2bb7a44abbcbbe3747dde73edb2
|
||||
F src/build.c 083da8466fd7e481cb8bd5264398f537507f6176
|
||||
F src/build.c 92ef9483189389828966153c5950f2e5a49c1182
|
||||
F src/callback.c d7e46f40c3cf53c43550b7da7a1d0479910b62cc
|
||||
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
||||
F src/ctime.c 4262c227bc91cecc61ae37ed3a40f08069cfa267
|
||||
F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4
|
||||
F src/delete.c 39a770e9729b1acd2de347f8f614584841d0083e
|
||||
F src/expr.c 437c03d5bb4fe3a53ecab3ad0286d6c5260da7ed
|
||||
F src/expr.c e40d198a719aba1d2514f6e1541f9154f976ceb6
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c e16942bd5c8a868ac53287886464a5ed0e72b179
|
||||
F src/func.c d3fdcff9274bc161152e67ed3f626841c247f4b9
|
||||
|
@ -171,7 +172,7 @@ F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
|
|||
F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12
|
||||
F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
|
||||
F src/loadext.c c48f7f3f170e502fe0cc20748e03c6e0b5a016c2
|
||||
F src/main.c dca921cb27c2221fe726a962b74aad19255a5bf4
|
||||
F src/main.c 393460eeb03d98f52863c1def596f988b33fe2a1
|
||||
F src/malloc.c fe085aa851b666b7c375c1ff957643dc20a04bf6
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c 437c7c4af964895d4650f29881df63535caaa1fa
|
||||
|
@ -353,7 +354,7 @@ F test/closure01.test 6194a899cdbba561d0439c0d6cc7bcdf4fc413e7
|
|||
F test/coalesce.test cee0dccb9fbd2d494b77234bccf9dc6c6786eb91
|
||||
F test/collate1.test fd02c4d8afc71879c4bb952586389961a21fb0ce
|
||||
F test/collate2.test 04cebe4a033be319d6ddbb3bbc69464e01700b49
|
||||
F test/collate3.test d28d2cfab2c3a3d4628ae4b2b7afc9965daa3b4c
|
||||
F test/collate3.test 79558a286362cb9ed603c6fa543f1cda7f563f0f
|
||||
F test/collate4.test 031f7265c13308b724ba3c49f41cc04612bd92b1
|
||||
F test/collate5.test 65d928034d30d2d263a80f6359f7549ee1598ec6
|
||||
F test/collate6.test 8be65a182abaac8011a622131486dafb8076e907
|
||||
|
@ -750,6 +751,7 @@ F test/shared6.test 866bb4982c45ce216c61ded5e8fde4e7e2f3ffa9
|
|||
F test/shared7.test 960760bc8d03e1419e70dea69cf41db62853616e
|
||||
F test/shared8.test b27befbefbe7f4517f1d6b7ff8f64a41ec74165d
|
||||
F test/shared9.test 5f2a8f79b4d6c7d107a01ffa1ed05ae7e6333e21
|
||||
F test/sharedA.test 0cdf1a76dfa00e6beee66af5b534b1e8df2720f5
|
||||
F test/shared_err.test 0079c05c97d88cfa03989b7c20a8b266983087aa
|
||||
F test/sharedlock.test ffa0a3c4ac192145b310f1254f8afca4d553eabf
|
||||
F test/shell1.test 4a2f57952719972c6f862134463f8712e953c038
|
||||
|
@ -1075,7 +1077,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
|
|||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
|
||||
F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac
|
||||
P ae6c4a0906ad8caabd8c605bb39c5fb979ab39a2 cf5c3642247fdd34d87f0368594cd7b8f081636a
|
||||
R aa02d52ce458f281b5bc9615e6d33430
|
||||
P 512f8a1ef8c4cf50723cfc4a78b7370dc37358d9 867b3e3b29a357f68e48f0898bf323c5dd0575a4
|
||||
R ffa29f370c90d286799404471155a28b
|
||||
U drh
|
||||
Z 94e59add3d7670652b5bb83515516e8f
|
||||
Z 1d96d56a3ef3c0775b8112327033ec85
|
||||
|
|
|
@ -1 +1 @@
|
|||
512f8a1ef8c4cf50723cfc4a78b7370dc37358d9
|
||||
d09355050a74344c1cb6d303af9f601cd41e2368
|
51
src/btree.c
51
src/btree.c
|
@ -2517,6 +2517,29 @@ page1_init_failed:
|
|||
return rc;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
/*
|
||||
** Return the number of cursors open on pBt. This is for use
|
||||
** in assert() expressions, so it is only compiled if NDEBUG is not
|
||||
** defined.
|
||||
**
|
||||
** Only write cursors are counted if wrOnly is true. If wrOnly is
|
||||
** false then all cursors are counted.
|
||||
**
|
||||
** For the purposes of this routine, a cursor is any cursor that
|
||||
** is capable of reading or writing to the databse. Cursors that
|
||||
** have been tripped into the CURSOR_FAULT state are not counted.
|
||||
*/
|
||||
static int countValidCursors(BtShared *pBt, int wrOnly){
|
||||
BtCursor *pCur;
|
||||
int r = 0;
|
||||
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
|
||||
if( (wrOnly==0 || pCur->wrFlag) && pCur->eState!=CURSOR_FAULT ) r++;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** If there are no outstanding cursors and we are not in the middle
|
||||
** of a transaction but there is a read lock on the database, then
|
||||
|
@ -2527,7 +2550,7 @@ page1_init_failed:
|
|||
*/
|
||||
static void unlockBtreeIfUnused(BtShared *pBt){
|
||||
assert( sqlite3_mutex_held(pBt->mutex) );
|
||||
assert( pBt->pCursor==0 || pBt->inTransaction>TRANS_NONE );
|
||||
assert( countValidCursors(pBt,0)==0 || pBt->inTransaction>TRANS_NONE );
|
||||
if( pBt->inTransaction==TRANS_NONE && pBt->pPage1!=0 ){
|
||||
assert( pBt->pPage1->aData );
|
||||
assert( sqlite3PagerRefcount(pBt->pPager)==1 );
|
||||
|
@ -3255,7 +3278,6 @@ static void btreeEndTransaction(Btree *p){
|
|||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
pBt->bDoTruncate = 0;
|
||||
#endif
|
||||
btreeClearHasContent(pBt);
|
||||
if( p->inTrans>TRANS_NONE && p->db->activeVdbeCnt>1 ){
|
||||
/* If there are other active statements that belong to this database
|
||||
** handle, downgrade to a read-only transaction. The other statements
|
||||
|
@ -3330,6 +3352,7 @@ int sqlite3BtreeCommitPhaseTwo(Btree *p, int bCleanup){
|
|||
return rc;
|
||||
}
|
||||
pBt->inTransaction = TRANS_READ;
|
||||
btreeClearHasContent(pBt);
|
||||
}
|
||||
|
||||
btreeEndTransaction(p);
|
||||
|
@ -3351,27 +3374,6 @@ int sqlite3BtreeCommit(Btree *p){
|
|||
return rc;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
/*
|
||||
** Return the number of write-cursors open on this handle. This is for use
|
||||
** in assert() expressions, so it is only compiled if NDEBUG is not
|
||||
** defined.
|
||||
**
|
||||
** For the purposes of this routine, a write-cursor is any cursor that
|
||||
** is capable of writing to the databse. That means the cursor was
|
||||
** originally opened for writing and the cursor has not be disabled
|
||||
** by having its state changed to CURSOR_FAULT.
|
||||
*/
|
||||
static int countWriteCursors(BtShared *pBt){
|
||||
BtCursor *pCur;
|
||||
int r = 0;
|
||||
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
|
||||
if( pCur->wrFlag && pCur->eState!=CURSOR_FAULT ) r++;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This routine sets the state to CURSOR_FAULT and the error
|
||||
** code to errCode for every cursor on BtShared that pBtree
|
||||
|
@ -3451,8 +3453,9 @@ int sqlite3BtreeRollback(Btree *p, int tripCode){
|
|||
pBt->nPage = nPage;
|
||||
releasePage(pPage1);
|
||||
}
|
||||
assert( countWriteCursors(pBt)==0 );
|
||||
assert( countValidCursors(pBt, 1)==0 );
|
||||
pBt->inTransaction = TRANS_READ;
|
||||
btreeClearHasContent(pBt);
|
||||
}
|
||||
|
||||
btreeEndTransaction(p);
|
||||
|
|
18
src/build.c
18
src/build.c
|
@ -2659,10 +2659,8 @@ Index *sqlite3CreateIndex(
|
|||
for(i=0; i<pList->nExpr; i++){
|
||||
Expr *pExpr = pList->a[i].pExpr;
|
||||
if( pExpr ){
|
||||
CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr);
|
||||
if( pColl ){
|
||||
nExtra += (1 + sqlite3Strlen30(pColl->zName));
|
||||
}
|
||||
assert( pExpr->op==TK_COLLATE );
|
||||
nExtra += (1 + sqlite3Strlen30(pExpr->u.zToken));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2723,7 +2721,6 @@ Index *sqlite3CreateIndex(
|
|||
const char *zColName = pListItem->zName;
|
||||
Column *pTabCol;
|
||||
int requestedSortOrder;
|
||||
CollSeq *pColl; /* Collating sequence */
|
||||
char *zColl; /* Collation sequence name */
|
||||
|
||||
for(j=0, pTabCol=pTab->aCol; j<pTab->nCol; j++, pTabCol++){
|
||||
|
@ -2736,11 +2733,10 @@ Index *sqlite3CreateIndex(
|
|||
goto exit_create_index;
|
||||
}
|
||||
pIndex->aiColumn[i] = j;
|
||||
if( pListItem->pExpr
|
||||
&& (pColl = sqlite3ExprCollSeq(pParse, pListItem->pExpr))!=0
|
||||
){
|
||||
if( pListItem->pExpr ){
|
||||
int nColl;
|
||||
zColl = pColl->zName;
|
||||
assert( pListItem->pExpr->op==TK_COLLATE );
|
||||
zColl = pListItem->pExpr->u.zToken;
|
||||
nColl = sqlite3Strlen30(zColl) + 1;
|
||||
assert( nExtra>=nColl );
|
||||
memcpy(zExtra, zColl, nColl);
|
||||
|
@ -2749,9 +2745,7 @@ Index *sqlite3CreateIndex(
|
|||
nExtra -= nColl;
|
||||
}else{
|
||||
zColl = pTab->aCol[j].zColl;
|
||||
if( !zColl ){
|
||||
zColl = "BINARY";
|
||||
}
|
||||
if( !zColl ) zColl = "BINARY";
|
||||
}
|
||||
if( !db->init.busy && !sqlite3LocateCollSeq(pParse, zColl) ){
|
||||
goto exit_create_index;
|
||||
|
|
|
@ -116,12 +116,7 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
|
|||
}
|
||||
assert( op!=TK_REGISTER || p->op2!=TK_COLLATE );
|
||||
if( op==TK_COLLATE ){
|
||||
if( db->init.busy ){
|
||||
/* Do not report errors when parsing while the schema */
|
||||
pColl = sqlite3FindCollSeq(db, ENC(db), p->u.zToken, 0);
|
||||
}else{
|
||||
pColl = sqlite3GetCollSeq(pParse, ENC(db), 0, p->u.zToken);
|
||||
}
|
||||
pColl = sqlite3GetCollSeq(pParse, ENC(db), 0, p->u.zToken);
|
||||
break;
|
||||
}
|
||||
if( p->pTab!=0
|
||||
|
|
|
@ -848,6 +848,12 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){
|
|||
return SQLITE_BUSY;
|
||||
}
|
||||
|
||||
/* If a transaction is open, roll it back. This also ensures that if
|
||||
** any database schemas have been modified by the current transaction
|
||||
** they are reset. And that the required b-tree mutex is held to make
|
||||
** the the pager rollback and schema reset an atomic operation. */
|
||||
sqlite3RollbackAll(db, SQLITE_OK);
|
||||
|
||||
#ifdef SQLITE_ENABLE_SQLLOG
|
||||
if( sqlite3GlobalConfig.xSqllog ){
|
||||
/* Closing the handle. Fourth parameter is passed the value 2. */
|
||||
|
@ -1002,6 +1008,7 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){
|
|||
int inTrans = 0;
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
sqlite3BeginBenignMalloc();
|
||||
sqlite3BtreeEnterAll(db);
|
||||
for(i=0; i<db->nDb; i++){
|
||||
Btree *p = db->aDb[i].pBt;
|
||||
if( p ){
|
||||
|
@ -1019,6 +1026,7 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){
|
|||
sqlite3ExpirePreparedStatements(db);
|
||||
sqlite3ResetAllSchemasOfConnection(db);
|
||||
}
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
|
||||
/* Any deferred constraint violations have now been resolved. */
|
||||
db->nDeferredCons = 0;
|
||||
|
|
|
@ -55,6 +55,104 @@ execsql {
|
|||
DROP TABLE collate3t1;
|
||||
}
|
||||
|
||||
proc caseless {a b} { string compare -nocase $a $b }
|
||||
do_test collate3-1.4 {
|
||||
db collate caseless caseless
|
||||
execsql {
|
||||
CREATE TABLE t1(a COLLATE caseless);
|
||||
INSERT INTO t1 VALUES('Abc2');
|
||||
INSERT INTO t1 VALUES('abc1');
|
||||
INSERT INTO t1 VALUES('aBc3');
|
||||
}
|
||||
execsql { SELECT * FROM t1 ORDER BY a }
|
||||
} {abc1 Abc2 aBc3}
|
||||
|
||||
do_test collate3-1.5 {
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
catchsql { SELECT * FROM t1 ORDER BY a }
|
||||
} {1 {no such collation sequence: caseless}}
|
||||
|
||||
do_test collate3-1.6.1 {
|
||||
db collate caseless caseless
|
||||
execsql { CREATE INDEX i1 ON t1(a) }
|
||||
execsql { SELECT * FROM t1 ORDER BY a }
|
||||
} {abc1 Abc2 aBc3}
|
||||
|
||||
do_test collate3-1.6.2 {
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
catchsql { SELECT * FROM t1 ORDER BY a }
|
||||
} {1 {no such collation sequence: caseless}}
|
||||
|
||||
do_test collate3-1.6.3 {
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
catchsql { PRAGMA integrity_check }
|
||||
} {1 {no such collation sequence: caseless}}
|
||||
|
||||
do_test collate3-1.6.4 {
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
catchsql { REINDEX }
|
||||
} {1 {no such collation sequence: caseless}}
|
||||
|
||||
do_test collate3-1.7.1 {
|
||||
db collate caseless caseless
|
||||
execsql {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(a);
|
||||
CREATE INDEX i1 ON t1(a COLLATE caseless);
|
||||
INSERT INTO t1 VALUES('Abc2');
|
||||
INSERT INTO t1 VALUES('abc1');
|
||||
INSERT INTO t1 VALUES('aBc3');
|
||||
SELECT * FROM t1 ORDER BY a COLLATE caseless;
|
||||
}
|
||||
} {abc1 Abc2 aBc3}
|
||||
|
||||
do_test collate3-1.7.2 {
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
catchsql { SELECT * FROM t1 ORDER BY a COLLATE caseless}
|
||||
} {1 {no such collation sequence: caseless}}
|
||||
|
||||
do_test collate3-1.7.4 {
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
catchsql { REINDEX }
|
||||
} {1 {no such collation sequence: caseless}}
|
||||
|
||||
do_test collate3-1.7.3 {
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
catchsql { PRAGMA integrity_check }
|
||||
} {1 {no such collation sequence: caseless}}
|
||||
|
||||
do_test collate3-1.7.4 {
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
catchsql { REINDEX }
|
||||
} {1 {no such collation sequence: caseless}}
|
||||
|
||||
do_test collate3-1.7.5 {
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
db collate caseless caseless
|
||||
catchsql { PRAGMA integrity_check }
|
||||
} {0 ok}
|
||||
|
||||
proc needed {nm} { db collate caseless caseless }
|
||||
do_test collate3-1.7.6 {
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
db collation_needed needed
|
||||
catchsql { PRAGMA integrity_check }
|
||||
} {0 ok}
|
||||
|
||||
do_test collate3-1.8 {
|
||||
execsql { DROP TABLE t1 }
|
||||
} {}
|
||||
|
||||
#
|
||||
# Create a table with a default collation sequence, then close
|
||||
# and re-open the database without re-registering the collation
|
||||
|
|
|
@ -0,0 +1,188 @@
|
|||
# 2013 May 14
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Test some specific circumstances to do with shared cache mode.
|
||||
#
|
||||
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
if {[run_thread_tests]==0} { finish_test ; return }
|
||||
db close
|
||||
set ::testprefix sharedA
|
||||
|
||||
set ::enable_shared_cache [sqlite3_enable_shared_cache 1]
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_test 0.1 {
|
||||
sqlite3 db1 test.db
|
||||
sqlite3 db2 test.db
|
||||
|
||||
db1 eval {
|
||||
CREATE TABLE t1(x);
|
||||
INSERT INTO t1 VALUES(randomblob(100));
|
||||
INSERT INTO t1 SELECT randomblob(100) FROM t1;
|
||||
INSERT INTO t1 SELECT randomblob(100) FROM t1;
|
||||
INSERT INTO t1 SELECT randomblob(100) FROM t1;
|
||||
INSERT INTO t1 SELECT randomblob(100) FROM t1;
|
||||
INSERT INTO t1 SELECT randomblob(100) FROM t1;
|
||||
INSERT INTO t1 SELECT randomblob(100) FROM t1;
|
||||
CREATE INDEX i1 ON t1(x);
|
||||
}
|
||||
|
||||
db1 eval {
|
||||
BEGIN;
|
||||
DROP INDEX i1;
|
||||
}
|
||||
|
||||
db2 close
|
||||
|
||||
db1 eval {
|
||||
INSERT INTO t1 SELECT randomblob(100) FROM t1;
|
||||
ROLLBACK;
|
||||
PRAGMA integrity_check;
|
||||
}
|
||||
} {ok}
|
||||
|
||||
db1 close
|
||||
forcedelete test.db
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_test 1.1 {
|
||||
sqlite3 db1 test.db
|
||||
sqlite3 db2 test.db
|
||||
db2 eval {
|
||||
CREATE TABLE t1(x);
|
||||
INSERT INTO t1 VALUES(123);
|
||||
}
|
||||
db1 eval {
|
||||
SELECT * FROM t1;
|
||||
CREATE INDEX i1 ON t1(x);
|
||||
}
|
||||
} {123}
|
||||
|
||||
do_test 1.2 {
|
||||
db2 eval { SELECT * FROM t1 ORDER BY x; }
|
||||
|
||||
db1 eval {
|
||||
BEGIN; DROP INDEX i1;
|
||||
}
|
||||
db1 close
|
||||
|
||||
db2 eval { SELECT * FROM t1 ORDER BY x; }
|
||||
} {123}
|
||||
|
||||
do_test 1.3 {
|
||||
db2 close
|
||||
} {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# sqlite3RollbackAll() loops through all attached b-trees and rolls
|
||||
# back each one separately. Then if the SQLITE_InternChanges flag is
|
||||
# set, it resets the schema. Both of the above steps must be done
|
||||
# while holding a mutex, otherwise another thread might slip in and
|
||||
# try to use the new schema with the old data.
|
||||
#
|
||||
# The following sequence of tests attempt to verify that the actions
|
||||
# taken by sqlite3RollbackAll() are thread-atomic (that they cannot be
|
||||
# interrupted by a separate thread.)
|
||||
#
|
||||
# Note that a TCL interpreter can only be used within the thread in which
|
||||
# it was originally created (because it uses thread-local-storage).
|
||||
# The tvfs callbacks must therefore only run on the main thread.
|
||||
# There is some trickery in the read_callback procedure to ensure that
|
||||
# this is the case.
|
||||
#
|
||||
testvfs tvfs
|
||||
|
||||
# Set up two databases and two database connections.
|
||||
#
|
||||
# db1: main(test.db), two(test2.db)
|
||||
# db2: main(test.db)
|
||||
#
|
||||
# The cache for test.db is shared between db1 and db2.
|
||||
#
|
||||
do_test 2.1 {
|
||||
forcedelete test.db test.db2
|
||||
sqlite3 db1 test.db -vfs tvfs
|
||||
db1 eval { ATTACH 'test.db2' AS two }
|
||||
|
||||
db1 eval {
|
||||
CREATE TABLE t1(x);
|
||||
INSERT INTO t1 VALUES(1);
|
||||
INSERT INTO t1 VALUES(2);
|
||||
INSERT INTO t1 VALUES(3);
|
||||
CREATE TABLE two.t2(x);
|
||||
INSERT INTO t2 SELECT * FROM t1;
|
||||
}
|
||||
|
||||
sqlite3 db2 test.db -vfs tvfs
|
||||
db2 eval { SELECT * FROM t1 }
|
||||
} {1 2 3}
|
||||
|
||||
# Create a prepared statement on db2 that will attempt a schema change
|
||||
# in test.db. Meanwhile, start a transaction on db1 that changes
|
||||
# the schema of test.db and that creates a rollback journal on test2.db
|
||||
#
|
||||
do_test 2.2 {
|
||||
set ::STMT [sqlite3_prepare db2 "CREATE INDEX i1 ON t1(x)" -1 tail]
|
||||
db1 eval {
|
||||
BEGIN;
|
||||
CREATE INDEX i1 ON t1(x);
|
||||
INSERT INTO t2 VALUES('value!');
|
||||
}
|
||||
} {}
|
||||
|
||||
# Set up a callback that will cause db2 to try to execute its
|
||||
# schema change when db1 accesses the journal file of test2.db.
|
||||
#
|
||||
# This callback will be invoked after the content of test.db has
|
||||
# be rolled back but before the schema has been reset. If the
|
||||
# sqlite3RollbackAll() operation is not thread-atomic, then the
|
||||
# db2 statement in the callback will see old content with the newer
|
||||
# schema, which is wrong.
|
||||
#
|
||||
tvfs filter xRead
|
||||
tvfs script read_callback
|
||||
unset -nocomplain ::some_time_laster
|
||||
unset -nocomplain ::thread_result
|
||||
proc read_callback {call file args} {
|
||||
if {[string match *test.db2-journal $file]} {
|
||||
tvfs filter {} ;# Ensure that tvfs callbacks to do run on the
|
||||
# child thread
|
||||
sqlthread spawn ::thread_result [subst -nocommands {
|
||||
sqlite3_step $::STMT
|
||||
set rc [sqlite3_finalize $::STMT]
|
||||
}]
|
||||
after 1000 { set ::some_time_later 1 }
|
||||
vwait ::some_time_later
|
||||
}
|
||||
}
|
||||
do_test 2.3 { db1 eval ROLLBACK } {}
|
||||
|
||||
# Verify that the db2 statement invoked by the callback detected the
|
||||
# schema change.
|
||||
#
|
||||
if {[info exists ::thread_result]==0} { vwait ::thread_result }
|
||||
do_test 2.4 {
|
||||
list $::thread_result [sqlite3_errmsg db2]
|
||||
} {SQLITE_SCHEMA {database schema has changed}}
|
||||
|
||||
db1 close
|
||||
db2 close
|
||||
tvfs delete
|
||||
|
||||
sqlite3_enable_shared_cache $::enable_shared_cache
|
||||
finish_test
|
Loading…
Reference in New Issue