Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Merge recent trunk changes into fts3-prefix-search branch. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | fts3-prefix-search |
Files: | files | file ages | folders |
SHA1: |
135ce30f62ebd6a1b239c18dbbd9c926 |
User & Date: | dan 2011-06-14 07:22:30.078 |
Context
2011-06-14
| ||
09:00 | Fix another bug caused by NEAR/matchinfo/order=DESC interaction. (check-in: 04907fbade user: dan tags: fts3-prefix-search) | |
07:22 | Merge recent trunk changes into fts3-prefix-search branch. (check-in: 135ce30f62 user: dan tags: fts3-prefix-search) | |
07:14 | Remove unused parameters from internal fts3 function. (check-in: 06de3f2cbc user: dan tags: fts3-prefix-search) | |
2011-06-13
| ||
12:19 | Use only unsigned values in the implementatin of LIKE and GLOB so that values won't overflow to negative when dealing with malformed UTF8. (check-in: 77f01578bb user: drh tags: trunk) | |
Changes
Changes to ext/fts3/fts3.c.
︙ | ︙ | |||
4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 | pCsr->isMatchinfoNeeded = 1; pCsr->iPrevId = pExpr->iDocid; }while( pCsr->isEof==0 && fts3EvalLoadDeferred(pCsr, &rc) ); } return rc; } static void fts3EvalRestart( Fts3Cursor *pCsr, Fts3Expr *pExpr, int *pRc ){ if( pExpr && *pRc==SQLITE_OK ){ Fts3Phrase *pPhrase = pExpr->pPhrase; | > > > > > > > > > | 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 | pCsr->isMatchinfoNeeded = 1; pCsr->iPrevId = pExpr->iDocid; }while( pCsr->isEof==0 && fts3EvalLoadDeferred(pCsr, &rc) ); } return rc; } /* ** Restart interation for expression pExpr so that the next call to ** sqlite3Fts3EvalNext() visits the first row. Do not allow incremental ** loading or merging of phrase doclists for this iteration. ** ** If *pRc is other than SQLITE_OK when this function is called, it is ** a no-op. If an error occurs within this function, *pRc is set to an ** SQLite error code before returning. */ static void fts3EvalRestart( Fts3Cursor *pCsr, Fts3Expr *pExpr, int *pRc ){ if( pExpr && *pRc==SQLITE_OK ){ Fts3Phrase *pPhrase = pExpr->pPhrase; |
︙ | ︙ |
Changes to src/fkey.c.
︙ | ︙ | |||
382 383 384 385 386 387 388 | for(i=0; i<nCol; i++){ sqlite3VdbeAddOp2(v, OP_Copy, aiCol[i]+1+regData, regTemp+i); } /* If the parent table is the same as the child table, and we are about ** to increment the constraint-counter (i.e. this is an INSERT operation), ** then check if the row being inserted matches itself. If so, do not | | > > > > > > > > > > > > | 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 | for(i=0; i<nCol; i++){ sqlite3VdbeAddOp2(v, OP_Copy, aiCol[i]+1+regData, regTemp+i); } /* If the parent table is the same as the child table, and we are about ** to increment the constraint-counter (i.e. this is an INSERT operation), ** then check if the row being inserted matches itself. If so, do not ** increment the constraint-counter. ** ** If any of the parent-key values are NULL, then the row cannot match ** itself. So set JUMPIFNULL to make sure we do the OP_Found if any ** of the parent-key values are NULL (at this point it is known that ** none of the child key values are). */ if( pTab==pFKey->pFrom && nIncr==1 ){ int iJump = sqlite3VdbeCurrentAddr(v) + nCol + 1; for(i=0; i<nCol; i++){ int iChild = aiCol[i]+1+regData; int iParent = pIdx->aiColumn[i]+1+regData; assert( aiCol[i]!=pTab->iPKey ); if( pIdx->aiColumn[i]==pTab->iPKey ){ /* The parent key is a composite key that includes the IPK column */ iParent = regData; } sqlite3VdbeAddOp3(v, OP_Ne, iChild, iJump, iParent); sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL); } sqlite3VdbeAddOp2(v, OP_Goto, 0, iOk); } sqlite3VdbeAddOp3(v, OP_MakeRecord, regTemp, nCol, regRec); sqlite3VdbeChangeP4(v, -1, sqlite3IndexAffinityStr(v,pIdx), P4_TRANSIENT); sqlite3VdbeAddOp4Int(v, OP_Found, iCur, iOk, regRec, 0); |
︙ | ︙ |
Changes to src/func.c.
︙ | ︙ | |||
502 503 504 505 506 507 508 | /* ** For LIKE and GLOB matching on EBCDIC machines, assume that every ** character is exactly one byte in size. Also, all characters are ** able to participate in upper-case-to-lower-case mappings in EBCDIC ** whereas only characters less than 0x80 do in ASCII. */ #if defined(SQLITE_EBCDIC) | | | | | 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 | /* ** For LIKE and GLOB matching on EBCDIC machines, assume that every ** character is exactly one byte in size. Also, all characters are ** able to participate in upper-case-to-lower-case mappings in EBCDIC ** whereas only characters less than 0x80 do in ASCII. */ #if defined(SQLITE_EBCDIC) # define sqlite3Utf8Read(A,C) (*(A++)) # define GlogUpperToLower(A) A = sqlite3UpperToLower[A] #else # define GlogUpperToLower(A) if( !((A)&~0x7f) ){ A = sqlite3UpperToLower[A]; } #endif static const struct compareInfo globInfo = { '*', '?', '[', 0 }; /* The correct SQL-92 behavior is for the LIKE operator to ignore ** case. Thus 'a' LIKE 'A' would be true. */ static const struct compareInfo likeInfoNorm = { '%', '_', 0, 1 }; /* If SQLITE_CASE_SENSITIVE_LIKE is defined, then the LIKE operator |
︙ | ︙ | |||
548 549 550 551 552 553 554 | ** ** abc[*]xyz Matches "abc*xyz" only */ static int patternCompare( const u8 *zPattern, /* The glob pattern */ const u8 *zString, /* The string to compare against the glob */ const struct compareInfo *pInfo, /* Information about how to do the compare */ | | | | 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 | ** ** abc[*]xyz Matches "abc*xyz" only */ static int patternCompare( const u8 *zPattern, /* The glob pattern */ const u8 *zString, /* The string to compare against the glob */ const struct compareInfo *pInfo, /* Information about how to do the compare */ u32 esc /* The escape character */ ){ u32 c, c2; int invert; int seen; u8 matchOne = pInfo->matchOne; u8 matchAll = pInfo->matchAll; u8 matchSet = pInfo->matchSet; u8 noCase = pInfo->noCase; int prevEscape = 0; /* True if the previous character was 'escape' */ |
︙ | ︙ | |||
680 681 682 683 684 685 686 | */ static void likeFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ const unsigned char *zA, *zB; | | | 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 | */ static void likeFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ const unsigned char *zA, *zB; u32 escape = 0; int nPat; sqlite3 *db = sqlite3_context_db_handle(context); zB = sqlite3_value_text(argv[0]); zA = sqlite3_value_text(argv[1]); /* Limit the length of the LIKE or GLOB pattern to avoid problems |
︙ | ︙ |
Changes to src/pcache1.c.
︙ | ︙ | |||
570 571 572 573 574 575 576 | pCache = (PCache1 *)sqlite3_malloc(sz); if( pCache ){ memset(pCache, 0, sz); if( separateCache ){ pGroup = (PGroup*)&pCache[1]; pGroup->mxPinned = 10; }else{ | | | 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 | pCache = (PCache1 *)sqlite3_malloc(sz); if( pCache ){ memset(pCache, 0, sz); if( separateCache ){ pGroup = (PGroup*)&pCache[1]; pGroup->mxPinned = 10; }else{ pGroup = &pcache1.grp; } pCache->pGroup = pGroup; pCache->szPage = szPage; pCache->bPurgeable = (bPurgeable ? 1 : 0); if( bPurgeable ){ pCache->nMin = 10; pcache1EnterMutex(pGroup); |
︙ | ︙ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
678 679 680 681 682 683 684 | ** Schema objects are automatically deallocated when the last Btree that ** references them is destroyed. The TEMP Schema is manually freed by ** sqlite3_close(). * ** A thread must be holding a mutex on the corresponding Btree in order ** to access Schema content. This implies that the thread must also be ** holding a mutex on the sqlite3 connection pointer that owns the Btree. | | | 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 | ** Schema objects are automatically deallocated when the last Btree that ** references them is destroyed. The TEMP Schema is manually freed by ** sqlite3_close(). * ** A thread must be holding a mutex on the corresponding Btree in order ** to access Schema content. This implies that the thread must also be ** holding a mutex on the sqlite3 connection pointer that owns the Btree. ** For a TEMP Schema, only the connection mutex is required. */ struct Schema { int schema_cookie; /* Database schema version number for this file */ int iGeneration; /* Generation counter. Incremented with each change */ Hash tblHash; /* All tables indexed by name */ Hash idxHash; /* All (named) indices indexed by name */ Hash trigHash; /* All triggers indexed by name */ |
︙ | ︙ | |||
2875 2876 2877 2878 2879 2880 2881 | int sqlite3FixExprList(DbFixer*, ExprList*); int sqlite3FixTriggerStep(DbFixer*, TriggerStep*); int sqlite3AtoF(const char *z, double*, int, u8); int sqlite3GetInt32(const char *, int*); int sqlite3Atoi(const char*); int sqlite3Utf16ByteLen(const void *pData, int nChar); int sqlite3Utf8CharLen(const char *pData, int nByte); | | | 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 | int sqlite3FixExprList(DbFixer*, ExprList*); int sqlite3FixTriggerStep(DbFixer*, TriggerStep*); int sqlite3AtoF(const char *z, double*, int, u8); int sqlite3GetInt32(const char *, int*); int sqlite3Atoi(const char*); int sqlite3Utf16ByteLen(const void *pData, int nChar); int sqlite3Utf8CharLen(const char *pData, int nByte); u32 sqlite3Utf8Read(const u8*, const u8**); /* ** 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). |
︙ | ︙ |
Changes to src/update.c.
︙ | ︙ | |||
240 241 242 243 244 245 246 | for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){} if( nIdx>0 ){ aRegIdx = sqlite3DbMallocRaw(db, sizeof(Index*) * nIdx ); if( aRegIdx==0 ) goto update_cleanup; } for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ int reg; | | | 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 | for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){} if( nIdx>0 ){ aRegIdx = sqlite3DbMallocRaw(db, sizeof(Index*) * nIdx ); if( aRegIdx==0 ) goto update_cleanup; } for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ int reg; if( hasFK || chngRowid ){ reg = ++pParse->nMem; }else{ reg = 0; for(i=0; i<pIdx->nColumn; i++){ if( aXRef[pIdx->aiColumn[i]]>=0 ){ reg = ++pParse->nMem; break; |
︙ | ︙ |
Changes to src/utf.c.
︙ | ︙ | |||
159 160 161 162 163 164 165 | while( zIn!=zTerm && (*zIn & 0xc0)==0x80 ){ \ c = (c<<6) + (0x3f & *(zIn++)); \ } \ if( c<0x80 \ || (c&0xFFFFF800)==0xD800 \ || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \ } | | | 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 | while( zIn!=zTerm && (*zIn & 0xc0)==0x80 ){ \ c = (c<<6) + (0x3f & *(zIn++)); \ } \ if( c<0x80 \ || (c&0xFFFFF800)==0xD800 \ || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \ } u32 sqlite3Utf8Read( const unsigned char *zIn, /* First byte of UTF-8 character */ const unsigned char **pzNext /* Write first byte past UTF-8 char here */ ){ unsigned int c; /* Same as READ_UTF8() above but without the zTerm parameter. ** For this routine, we assume the UTF8 string is always zero-terminated. |
︙ | ︙ |
Changes to test/fkey3.test.
︙ | ︙ | |||
16 17 18 19 20 21 22 23 24 25 26 27 28 29 | set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable {!foreignkey||!trigger} { finish_test return } # Create a table and some data to work with. # do_test fkey3-1.1 { execsql { PRAGMA foreign_keys=ON; CREATE TABLE t1(x INTEGER PRIMARY KEY); | > > | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable {!foreignkey||!trigger} { finish_test return } set testprefix fkey3 # Create a table and some data to work with. # do_test fkey3-1.1 { execsql { PRAGMA foreign_keys=ON; CREATE TABLE t1(x INTEGER PRIMARY KEY); |
︙ | ︙ | |||
73 74 75 76 77 78 79 80 | INSERT INTO t2 VALUES(100); INSERT INTO t2 VALUES(101); SELECT 1, x FROM t1; SELECT 2, y FROM t2; } } {1 100 1 101 2 100 2 101} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | INSERT INTO t2 VALUES(100); INSERT INTO t2 VALUES(101); SELECT 1, x FROM t1; SELECT 2, y FROM t2; } } {1 100 1 101 2 100 2 101} #------------------------------------------------------------------------- # The following tests - fkey-3.* - test some edge cases to do with # inserting rows into tables that have foreign keys where the parent # table is the same as the child table. Especially cases where the # new row being inserted matches itself. # do_execsql_test 3.1.1 { CREATE TABLE t3(a, b, c, d, UNIQUE(a, b), FOREIGN KEY(c, d) REFERENCES t3(a, b) ); INSERT INTO t3 VALUES(1, 2, 1, 2); } {} do_catchsql_test 3.1.2 { INSERT INTO t3 VALUES(NULL, 2, 5, 2); } {1 {foreign key constraint failed}} do_catchsql_test 3.1.3 { INSERT INTO t3 VALUES(NULL, 3, 5, 2); } {1 {foreign key constraint failed}} do_execsql_test 3.2.1 { CREATE TABLE t4(a UNIQUE, b REFERENCES t4(a)); } do_catchsql_test 3.2.2 { INSERT INTO t4 VALUES(NULL, 1); } {1 {foreign key constraint failed}} do_execsql_test 3.3.1 { CREATE TABLE t5(a INTEGER PRIMARY KEY, b REFERENCES t5(a)); INSERT INTO t5 VALUES(NULL, 1); } {} do_catchsql_test 3.3.2 { INSERT INTO t5 VALUES(NULL, 3); } {1 {foreign key constraint failed}} do_execsql_test 3.4.1 { CREATE TABLE t6(a INTEGER PRIMARY KEY, b, c, d, FOREIGN KEY(c, d) REFERENCES t6(a, b) ); CREATE UNIQUE INDEX t6i ON t6(b, a); } do_execsql_test 3.4.2 { INSERT INTO t6 VALUES(NULL, 'a', 1, 'a'); } {} do_execsql_test 3.4.3 { INSERT INTO t6 VALUES(2, 'a', 2, 'a'); } {} do_execsql_test 3.4.4 { INSERT INTO t6 VALUES(NULL, 'a', 1, 'a'); } {} do_execsql_test 3.4.5 { INSERT INTO t6 VALUES(5, 'a', 2, 'a'); } {} do_catchsql_test 3.4.6 { INSERT INTO t6 VALUES(NULL, 'a', 65, 'a'); } {1 {foreign key constraint failed}} do_execsql_test 3.4.7 { INSERT INTO t6 VALUES(100, 'one', 100, 'one'); DELETE FROM t6 WHERE a = 100; } do_execsql_test 3.4.8 { INSERT INTO t6 VALUES(100, 'one', 100, 'one'); UPDATE t6 SET c = 1, d = 'a' WHERE a = 100; DELETE FROM t6 WHERE a = 100; } do_execsql_test 3.5.1 { CREATE TABLE t7(a, b, c, d INTEGER PRIMARY KEY, FOREIGN KEY(c, d) REFERENCES t7(a, b) ); CREATE UNIQUE INDEX t7i ON t7(a, b); } do_execsql_test 3.5.2 { INSERT INTO t7 VALUES('x', 1, 'x', NULL) } {} do_execsql_test 3.5.3 { INSERT INTO t7 VALUES('x', 2, 'x', 2) } {} do_catchsql_test 3.5.4 { INSERT INTO t7 VALUES('x', 450, 'x', NULL); } {1 {foreign key constraint failed}} do_catchsql_test 3.5.5 { INSERT INTO t7 VALUES('x', 450, 'x', 451); } {1 {foreign key constraint failed}} do_execsql_test 3.6.1 { CREATE TABLE t8(a, b, c, d, e, FOREIGN KEY(c, d) REFERENCES t8(a, b)); CREATE UNIQUE INDEX t8i1 ON t8(a, b); CREATE UNIQUE INDEX t8i2 ON t8(c); INSERT INTO t8 VALUES(1, 1, 1, 1, 1); } do_catchsql_test 3.6.2 { UPDATE t8 SET d = 2; } {1 {foreign key constraint failed}} do_execsql_test 3.6.3 { UPDATE t8 SET d = 1; } do_execsql_test 3.6.4 { UPDATE t8 SET e = 2; } do_catchsql_test 3.6.5 { CREATE TABLE TestTable ( id INTEGER PRIMARY KEY, name text, source_id integer not null, parent_id integer, foreign key(source_id, parent_id) references TestTable(source_id, id) ); CREATE UNIQUE INDEX testindex on TestTable(source_id, id); PRAGMA foreign_keys=1; INSERT INTO TestTable VALUES (1, 'parent', 1, null); INSERT INTO TestTable VALUES (2, 'child', 1, 1); UPDATE TestTable SET parent_id=1000 where id=2; } {1 {foreign key constraint failed}} finish_test |