mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
Merge all recent trunk changes.
FossilOrigin-Name: 3a2a1bd47875e114d8e6f31c1768908f401d2861
This commit is contained in:
38
manifest
38
manifest
@@ -1,5 +1,5 @@
|
||||
C Merge\sin\sperformance\senhancements\sfrom\strunk.
|
||||
D 2013-11-26T18:00:29.602
|
||||
C Merge\sall\srecent\strunk\schanges.
|
||||
D 2013-11-27T21:53:51.759
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 06b851f767034811d4f6e159367c453dc28d3925
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@@ -220,7 +220,7 @@ F src/os.c b4ad71336fd96f97776f75587cd9e8218288f5be
|
||||
F src/os.h 4a46270a64e9193af4a0aaa3bc2c66dc07c29b3f
|
||||
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
|
||||
F src/os_unix.c 143624d9eabb3b997c59cf594e0d06c56edd43e9
|
||||
F src/os_win.c cb3f26205ea785a63ea5bdc21a9c9f9ae3972d0f
|
||||
F src/os_win.c 4323dd0bac4f7a7037fc4cf87fb4692d17f0b108
|
||||
F src/pager.c 2aa4444ffe86e9282d03bc349a4a5e49bd77c0e8
|
||||
F src/pager.h f094af9f6ececfaa8a1e93876905a4f34233fb0c
|
||||
F src/parse.y acee1a9958539e21263362b194594c5255ad2fca
|
||||
@@ -231,11 +231,11 @@ F src/pragma.c 5ab7279d132143feb77f773688a24ab05da75fd7
|
||||
F src/prepare.c 359d1a1e9c9bd4488e4dd3a1aaaf2d2ebb9bb768
|
||||
F src/printf.c da9119eb31a187a4b99f60aa4a225141c0ebb74b
|
||||
F src/random.c 0b2dbc37fdfbfa6bd455b091dfcef5bdb32dba68
|
||||
F src/resolve.c a70e32ae6ccb7b780f2b6d3e9e21837affc25ee5
|
||||
F src/resolve.c 7eda9097b29fcf3d2b42fdc17d1de672134e09b6
|
||||
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
|
||||
F src/select.c d41381d80a22d3a83352aeca274cccf264ac277a
|
||||
F src/shell.c c4d06a9238a515ff4bc86b8626139633c09a00a2
|
||||
F src/sqlite.h.in c84ef520934601e4d1a95c6858fef71dc369e940
|
||||
F src/shell.c 936a72ff784efff3832cce274a96ed0b036e6758
|
||||
F src/sqlite.h.in e7a96fad3f5a2e96f5b69cf395d3dfa657f4ab59
|
||||
F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
|
||||
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
|
||||
F src/sqliteInt.h dad3dff932c055304fc75b339f2cf68aab9cf19e
|
||||
@@ -294,10 +294,10 @@ F src/update.c 046d7df2a4b3d85442a758f484eb2d40a48b5465
|
||||
F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269
|
||||
F src/util.c cbe054290f780fcd472b89d701c7404c51ec9684
|
||||
F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
|
||||
F src/vdbe.c 520dcda659ff32e3da7d141e9ac083d3599a2079
|
||||
F src/vdbe.c 9c6fb9ed1b9165427b0fdc812bc9c48c031f77da
|
||||
F src/vdbe.h b7bfa7b468fcad2cf1890969fe7459325da00385
|
||||
F src/vdbeInt.h 1a5c604f33a5d46c839fee0cab16743aa3e1bc2e
|
||||
F src/vdbeapi.c 8ade912f7023a3b35ee64497a94718ddbd7269c3
|
||||
F src/vdbeapi.c e80d6d9dea792bd823cb64ae05cba446a7b3556a
|
||||
F src/vdbeaux.c 9270db4725c0143e572a2df660fabac7104a9db3
|
||||
F src/vdbeblob.c a2809461743e0b9dd9be871149ac65e8d2c80c08
|
||||
F src/vdbemem.c af650c2019dc197f062440cdb4650b7204e648bf
|
||||
@@ -307,7 +307,7 @@ F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd
|
||||
F src/wal.c 7dc3966ef98b74422267e7e6e46e07ff6c6eb1b4
|
||||
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
|
||||
F src/walker.c e9e593d5bb798c3e67fc3893dfe7055c9e7d8d74
|
||||
F src/where.c e558bfa67009ab7de08a7a1960ae0dd443241cdd
|
||||
F src/where.c e0a9909a58eee7dcde1d1bd5cf6381b0dbc83389
|
||||
F src/whereInt.h 96a75c61f1d2b9d4a8e4bb17d89deb0cf7cba358
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
@@ -447,11 +447,11 @@ F test/descidx3.test 09ddbe3f5295f482d2f8b687cf6db8bad7acd9a2
|
||||
F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e
|
||||
F test/distinct.test 44028aaf161a5e80a2f229622b3a174d3b352810
|
||||
F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376
|
||||
F test/e_createtable.test 3b453432cd14a12732ee9467597d2274ca37ce36
|
||||
F test/e_createtable.test ee95d48664503d40f6cc9ef4a7d03216188e2ada
|
||||
F test/e_delete.test d5186e2f5478b659f16a2c8b66c09892823e542a
|
||||
F test/e_droptrigger.test 3cd080807622c13e5bbb61fc9a57bd7754da2412
|
||||
F test/e_dropview.test 0c9f7f60989164a70a67a9d9c26d1083bc808306
|
||||
F test/e_expr.test 0808bc72c7b2a2fab4291418ecd73f4d09d7d671
|
||||
F test/e_expr.test 5c71d183fbf519a4769fd2e2124afdc70b5b1f42
|
||||
F test/e_fkey.test d83a04478bb9c02d2c513518548a69f818869f41
|
||||
F test/e_fts3.test 5c02288842e4f941896fd44afdef564dd5fc1459
|
||||
F test/e_insert.test 1e44f84d2abe44d66e4fbf198be4b20e3cc724a0
|
||||
@@ -601,7 +601,7 @@ F test/fuzz_malloc.test 328f70aaca63adf29b4c6f06505ed0cf57ca7c26
|
||||
F test/fuzzer1.test d4c52aaf3ef923da293a2653cfab33d02f718a36
|
||||
F test/fuzzerfault.test 8792cd77fd5bce765b05d0c8e01b9edcf8af8536
|
||||
F test/genesis.tcl 1e2e2e8e5cc4058549a154ff1892fe5c9de19f98
|
||||
F test/hook.test 777b2541f6dd4f4ca5e8d6b66c1df1b3717aeab6
|
||||
F test/hook.test 5429d34d6e59086175d8efbcd7e14d891375bdfb
|
||||
F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4
|
||||
F test/in.test 047c4671328e9032ab95666a67021adbbd36e98e
|
||||
F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
|
||||
@@ -657,7 +657,7 @@ F test/jrnlmode.test 9ee3a78f53d52cca737db69293d15dc41c0cbd36
|
||||
F test/jrnlmode2.test 81610545a4e6ed239ea8fa661891893385e23a1d
|
||||
F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa
|
||||
F test/keyword1.test a2400977a2e4fde43bf33754c2929fda34dbca05
|
||||
F test/lastinsert.test 474d519c68cb79d07ecae56a763aa7f322c72f51
|
||||
F test/lastinsert.test 42e948fd6442f07d60acbd15d33fb86473e0ef63
|
||||
F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200
|
||||
F test/like.test 935fb4f608e3ea126891496a6e99b9468372bf5c
|
||||
F test/like2.test 3b2ee13149ba4a8a60b59756f4e5d345573852da
|
||||
@@ -770,7 +770,7 @@ F test/releasetest.tcl 06d289d8255794073a58d2850742f627924545ce
|
||||
F test/resolver01.test 33abf37ff8335e6bf98f2b45a0af3e06996ccd9a
|
||||
F test/rollback.test e9504a009a202c3ed711da2e6879ff60c5a4669c
|
||||
F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81
|
||||
F test/rowid.test f777404492adb0e00868fd706a3721328fd3af48
|
||||
F test/rowid.test b78b30afb9537a73788ca1233a23a32190a3bb1f
|
||||
F test/rtree.test 0c8d9dd458d6824e59683c19ab2ffa9ef946f798
|
||||
F test/run-wordcount.sh 891e89c4c2d16e629cd45951d4ed899ad12afc09
|
||||
F test/savepoint.test 6c53f76dffe5df0dd87646efe3e7aa159c36e07b
|
||||
@@ -823,6 +823,7 @@ F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
|
||||
F test/shrink.test 8c70f62b6e8eb4d54533de6d65bd06b1b9a17868
|
||||
F test/sidedelete.test f0ad71abe6233e3b153100f3b8d679b19a488329
|
||||
F test/skipscan1.test 6bb4891c2cc5efd5690a9da9e7508e53d4a68e10
|
||||
F test/skipscan2.test 5a4db0799c338ddbacb154aaa5589c0254b36a8d
|
||||
F test/soak.test 0b5b6375c9f4110c828070b826b3b4b0bb65cd5f
|
||||
F test/softheap1.test 40562fe6cac6d9827b7b42b86d45aedf12c15e24
|
||||
F test/sort.test 0e4456e729e5a92a625907c63dcdedfbe72c5dc5
|
||||
@@ -834,7 +835,7 @@ F test/speed3.test d32043614c08c53eafdc80f33191d5bd9b920523
|
||||
F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
|
||||
F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
|
||||
F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b
|
||||
F test/speedtest1.c aa08ae8e3591bf5c028be9396a84237640761d8c
|
||||
F test/speedtest1.c 184ded13ffe61df44d6e2ac9985b61a6417d5311
|
||||
F test/spellfix.test 8c40b169b104086d8795781f670ba3c786d6d8be
|
||||
F test/sqllimits1.test b1aae27cc98eceb845e7f7adf918561256e31298
|
||||
F test/stat.test c8eccfe8fcd3f3cfc864ce22d5b9e803a3c69940
|
||||
@@ -1106,6 +1107,7 @@ F test/without_rowid1.test aaa26da19d543cd8d3d2d0e686dfa255556c15c8
|
||||
F test/without_rowid2.test af260339f79d13cb220288b67cd287fbcf81ad99
|
||||
F test/without_rowid3.test eac3d5c8a1924725b58503a368f2cbd24fd6c8a0
|
||||
F test/without_rowid4.test 4e08bcbaee0399f35d58b5581881e7a6243d458a
|
||||
F test/without_rowid5.test b4a639a367f04d382d20e8f44fc1be4f2d57d107
|
||||
F test/wordcount.c 9915e06cb33d8ca8109b8700791afe80d305afda
|
||||
F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688
|
||||
F test/zerodamage.test 209d7ed441f44cc5299e4ebffbef06fd5aabfefd
|
||||
@@ -1158,7 +1160,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
|
||||
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
|
||||
P 7596d1bf8040f7cefc7b22c5e609acc5d66820bf 6f91dca0de908dc2b15130a6593a61c3147a409f
|
||||
R 4bfa42555a9c1bb80b9d6441159a988c
|
||||
P fc9ae839569eb28eb734c52d95676c59b2e27494 81891288d9f281cf2ceb4cd701c0c3231b1bab19
|
||||
R 82cfa20fdf0a662273b8437808c19755
|
||||
U drh
|
||||
Z ab8c142eff787cc8d595e6a709628910
|
||||
Z 5ce6e39b92ce4cf1a9fbbd5b784d1d3b
|
||||
|
@@ -1 +1 @@
|
||||
fc9ae839569eb28eb734c52d95676c59b2e27494
|
||||
3a2a1bd47875e114d8e6f31c1768908f401d2861
|
41
src/os_win.c
41
src/os_win.c
@@ -59,6 +59,34 @@
|
||||
must be defined."
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Define the required Windows SDK version constants if they are not
|
||||
** already available.
|
||||
*/
|
||||
#ifndef NTDDI_WIN8
|
||||
# define NTDDI_WIN8 0x06020000
|
||||
#endif
|
||||
|
||||
#ifndef NTDDI_WINBLUE
|
||||
# define NTDDI_WINBLUE 0x06030000
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Check if the GetVersionEx[AW] functions should be considered deprecated
|
||||
** and avoid using them in that case. It should be noted here that if the
|
||||
** value of the SQLITE_WIN32_GETVERSIONEX pre-processor macro is zero
|
||||
** (whether via this block or via being manually specified), that implies
|
||||
** the underlying operating system will always be based on the Windows NT
|
||||
** Kernel.
|
||||
*/
|
||||
#ifndef SQLITE_WIN32_GETVERSIONEX
|
||||
# if defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WINBLUE
|
||||
# define SQLITE_WIN32_GETVERSIONEX 0
|
||||
# else
|
||||
# define SQLITE_WIN32_GETVERSIONEX 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This constant should already be defined (in the "WinDef.h" SDK file).
|
||||
*/
|
||||
@@ -694,7 +722,8 @@ static struct win_syscall {
|
||||
|
||||
#define osGetTickCount ((DWORD(WINAPI*)(VOID))aSyscall[33].pCurrent)
|
||||
|
||||
#if defined(SQLITE_WIN32_HAS_ANSI)
|
||||
#if defined(SQLITE_WIN32_HAS_ANSI) && defined(SQLITE_WIN32_GETVERSIONEX) && \
|
||||
SQLITE_WIN32_GETVERSIONEX
|
||||
{ "GetVersionExA", (SYSCALL)GetVersionExA, 0 },
|
||||
#else
|
||||
{ "GetVersionExA", (SYSCALL)0, 0 },
|
||||
@@ -703,7 +732,8 @@ static struct win_syscall {
|
||||
#define osGetVersionExA ((BOOL(WINAPI*)( \
|
||||
LPOSVERSIONINFOA))aSyscall[34].pCurrent)
|
||||
|
||||
#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
|
||||
#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \
|
||||
defined(SQLITE_WIN32_GETVERSIONEX) && SQLITE_WIN32_GETVERSIONEX
|
||||
{ "GetVersionExW", (SYSCALL)GetVersionExW, 0 },
|
||||
#else
|
||||
{ "GetVersionExW", (SYSCALL)0, 0 },
|
||||
@@ -1260,11 +1290,10 @@ void sqlite3_win32_sleep(DWORD milliseconds){
|
||||
** WinNT/2K/XP so that we will know whether or not we can safely call
|
||||
** the LockFileEx() API.
|
||||
*/
|
||||
#ifndef NTDDI_WIN8
|
||||
# define NTDDI_WIN8 0x06020000
|
||||
#endif
|
||||
|
||||
#if SQLITE_OS_WINCE || SQLITE_OS_WINRT || !defined(SQLITE_WIN32_HAS_ANSI)
|
||||
#if !defined(SQLITE_WIN32_GETVERSIONEX) || !SQLITE_WIN32_GETVERSIONEX
|
||||
# define osIsNT() (1)
|
||||
#elif SQLITE_OS_WINCE || SQLITE_OS_WINRT || !defined(SQLITE_WIN32_HAS_ANSI)
|
||||
# define osIsNT() (1)
|
||||
#elif !defined(SQLITE_WIN32_HAS_WIDE)
|
||||
# define osIsNT() (0)
|
||||
|
@@ -352,7 +352,9 @@ static int lookupName(
|
||||
}
|
||||
}
|
||||
if( iCol>=pTab->nCol && sqlite3IsRowid(zCol) && HasRowid(pTab) ){
|
||||
iCol = -1; /* IMP: R-44911-55124 */
|
||||
/* IMP: R-24309-18625 */
|
||||
/* IMP: R-44911-55124 */
|
||||
iCol = -1;
|
||||
}
|
||||
if( iCol<pTab->nCol ){
|
||||
cnt++;
|
||||
|
@@ -2096,7 +2096,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
*/
|
||||
p->mode = MODE_Explain;
|
||||
p->showHeader = 1;
|
||||
memset(p->colWidth,0,ArraySize(p->colWidth));
|
||||
memset(p->colWidth,0,sizeof(p->colWidth));
|
||||
p->colWidth[0] = 4; /* addr */
|
||||
p->colWidth[1] = 13; /* opcode */
|
||||
p->colWidth[2] = 4; /* P1 */
|
||||
|
@@ -3775,19 +3775,19 @@ int sqlite3_data_count(sqlite3_stmt *pStmt);
|
||||
**
|
||||
** <tr><td> NULL <td> INTEGER <td> Result is 0
|
||||
** <tr><td> NULL <td> FLOAT <td> Result is 0.0
|
||||
** <tr><td> NULL <td> TEXT <td> Result is NULL pointer
|
||||
** <tr><td> NULL <td> BLOB <td> Result is NULL pointer
|
||||
** <tr><td> NULL <td> TEXT <td> Result is a NULL pointer
|
||||
** <tr><td> NULL <td> BLOB <td> Result is a NULL pointer
|
||||
** <tr><td> INTEGER <td> FLOAT <td> Convert from integer to float
|
||||
** <tr><td> INTEGER <td> TEXT <td> ASCII rendering of the integer
|
||||
** <tr><td> INTEGER <td> BLOB <td> Same as INTEGER->TEXT
|
||||
** <tr><td> FLOAT <td> INTEGER <td> Convert from float to integer
|
||||
** <tr><td> FLOAT <td> INTEGER <td> [CAST] to INTEGER
|
||||
** <tr><td> FLOAT <td> TEXT <td> ASCII rendering of the float
|
||||
** <tr><td> FLOAT <td> BLOB <td> Same as FLOAT->TEXT
|
||||
** <tr><td> TEXT <td> INTEGER <td> Use atoi()
|
||||
** <tr><td> TEXT <td> FLOAT <td> Use atof()
|
||||
** <tr><td> FLOAT <td> BLOB <td> [CAST] to BLOB
|
||||
** <tr><td> TEXT <td> INTEGER <td> [CAST] to INTEGER
|
||||
** <tr><td> TEXT <td> FLOAT <td> [CAST] to REAL
|
||||
** <tr><td> TEXT <td> BLOB <td> No change
|
||||
** <tr><td> BLOB <td> INTEGER <td> Convert to TEXT then use atoi()
|
||||
** <tr><td> BLOB <td> FLOAT <td> Convert to TEXT then use atof()
|
||||
** <tr><td> BLOB <td> INTEGER <td> [CAST] to INTEGER
|
||||
** <tr><td> BLOB <td> FLOAT <td> [CAST] to REAL
|
||||
** <tr><td> BLOB <td> TEXT <td> Add a zero terminator if needed
|
||||
** </table>
|
||||
** </blockquote>)^
|
||||
|
63
src/vdbe.c
63
src/vdbe.c
@@ -3520,38 +3520,28 @@ case OP_SeekGt: { /* jump, in3 */
|
||||
pc = pOp->p2 - 1;
|
||||
break;
|
||||
}
|
||||
/* If we reach this point, then the P3 value must be a floating
|
||||
** point number. */
|
||||
assert( (pIn3->flags & MEM_Real)!=0 );
|
||||
|
||||
if( (iKey==SMALLEST_INT64 && pIn3->r<(double)iKey)
|
||||
|| (iKey==LARGEST_INT64 && pIn3->r>(double)iKey)
|
||||
){
|
||||
/* The P3 value is too large in magnitude to be expressed as an
|
||||
** integer. */
|
||||
res = 1;
|
||||
if( pIn3->r<0 ){
|
||||
if( oc>=OP_SeekGe ){ assert( oc==OP_SeekGe || oc==OP_SeekGt );
|
||||
rc = sqlite3BtreeFirst(pC->pCursor, &res);
|
||||
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
||||
/* If the approximation iKey is larger than the actual real search
|
||||
** term, substitute >= for > and < for <=. e.g. if the search term
|
||||
** is 4.9 and the integer approximation 5:
|
||||
**
|
||||
** (x > 4.9) -> (x >= 5)
|
||||
** (x <= 4.9) -> (x < 5)
|
||||
*/
|
||||
if( pIn3->r<(double)iKey ){
|
||||
assert( OP_SeekGe==(OP_SeekGt-1) );
|
||||
assert( OP_SeekLt==(OP_SeekLe-1) );
|
||||
assert( (OP_SeekLe & 0x0001)==(OP_SeekGt & 0x0001) );
|
||||
if( (oc & 0x0001)==(OP_SeekGt & 0x0001) ) oc--;
|
||||
}
|
||||
}else{
|
||||
if( oc<=OP_SeekLe ){ assert( oc==OP_SeekLt || oc==OP_SeekLe );
|
||||
rc = sqlite3BtreeLast(pC->pCursor, &res);
|
||||
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
||||
}
|
||||
}
|
||||
if( res ){
|
||||
pc = pOp->p2 - 1;
|
||||
}
|
||||
break;
|
||||
}else if( oc==OP_SeekLt || oc==OP_SeekGe ){
|
||||
/* Use the ceiling() function to convert real->int */
|
||||
if( pIn3->r > (double)iKey ) iKey++;
|
||||
}else{
|
||||
/* Use the floor() function to convert real->int */
|
||||
assert( oc==OP_SeekLe || oc==OP_SeekGt );
|
||||
if( pIn3->r < (double)iKey ) iKey--;
|
||||
|
||||
/* If the approximation iKey is smaller than the actual real search
|
||||
** term, substitute <= for < and > for >=. */
|
||||
else if( pIn3->r>(double)iKey ){
|
||||
assert( OP_SeekLe==(OP_SeekLt+1) );
|
||||
assert( OP_SeekGt==(OP_SeekGe+1) );
|
||||
assert( (OP_SeekLt & 0x0001)==(OP_SeekGe & 0x0001) );
|
||||
if( (oc & 0x0001)==(OP_SeekLt & 0x0001) ) oc++;
|
||||
}
|
||||
}
|
||||
rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, 0, (u64)iKey, 0, &res);
|
||||
@@ -4084,6 +4074,7 @@ case OP_InsertInt: {
|
||||
if( db->xPreUpdateCallback
|
||||
&& pOp->p4type==P4_TABLE
|
||||
&& (!(pOp->p5 & OPFLAG_ISUPDATE) || pC->rowidIsValid==0)
|
||||
&& HasRowid(pTab)
|
||||
){
|
||||
sqlite3VdbePreUpdateHook(p, pC, SQLITE_INSERT, zDb, pTab, iKey, pOp->p2);
|
||||
}
|
||||
@@ -4113,7 +4104,7 @@ case OP_InsertInt: {
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
|
||||
/* Invoke the update-hook if required. */
|
||||
if( rc==SQLITE_OK && db->xUpdateCallback && op ){
|
||||
if( rc==SQLITE_OK && db->xUpdateCallback && op && HasRowid(pTab) ){
|
||||
db->xUpdateCallback(db->pUpdateArg, op, zDb, pTab->zName, iKey);
|
||||
}
|
||||
break;
|
||||
@@ -4153,12 +4144,11 @@ case OP_Delete: {
|
||||
int opflags;
|
||||
|
||||
opflags = pOp->p2;
|
||||
iKey = 0;
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
assert( pC->pCursor!=0 ); /* Only valid for real tables, no pseudotables */
|
||||
assert( pOp->p4type==P4_TABLE || pOp->p4type==P4_NOTUSED );
|
||||
iKey = pC->lastRowid; /* Only used for the update hook */
|
||||
|
||||
/* The OP_Delete opcode always follows an OP_NotExists or OP_Last or
|
||||
** OP_Column on the same table without any intervening operations that
|
||||
@@ -4176,8 +4166,7 @@ case OP_Delete: {
|
||||
*/
|
||||
if( pOp->p4.z && HAS_UPDATE_HOOK(db) ){
|
||||
assert( pC->iDb>=0 );
|
||||
assert( pC->isTable );
|
||||
assert( pC->rowidIsValid ); /* lastRowid set by previous OP_NotFound */
|
||||
assert( pC->rowidIsValid || !HasRowid(pOp->p4.pTab) );
|
||||
iKey = pC->lastRowid;
|
||||
zDb = db->aDb[pC->iDb].zName;
|
||||
pTab = pOp->p4.pTab;
|
||||
@@ -4185,7 +4174,7 @@ case OP_Delete: {
|
||||
|
||||
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
||||
/* Invoke the pre-update-hook if required. */
|
||||
if( db->xPreUpdateCallback && pOp->p4.z ){
|
||||
if( db->xPreUpdateCallback && pOp->p4.z && HasRowid(pTab) ){
|
||||
assert( !(opflags & OPFLAG_ISUPDATE) || (aMem[pOp->p3].flags & MEM_Int) );
|
||||
sqlite3VdbePreUpdateHook(p, pC,
|
||||
(opflags & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_DELETE,
|
||||
@@ -4205,7 +4194,7 @@ case OP_Delete: {
|
||||
if( opflags & OPFLAG_NCHANGE ){
|
||||
p->nChange++;
|
||||
assert( pOp->p4.z );
|
||||
if( rc==SQLITE_OK && db->xUpdateCallback ){
|
||||
if( rc==SQLITE_OK && db->xUpdateCallback && HasRowid(pTab) ){
|
||||
db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, pTab->zName,iKey);
|
||||
}
|
||||
}
|
||||
|
@@ -728,27 +728,6 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
|
||||
sqlite3_mutex_enter(pVm->db->mutex);
|
||||
pOut = &pVm->pResultSet[i];
|
||||
}else{
|
||||
/* If the value passed as the second argument is out of range, return
|
||||
** a pointer to the following static Mem object which contains the
|
||||
** value SQL NULL. Even though the Mem structure contains an element
|
||||
** of type i64, on certain architectures (x86) with certain compiler
|
||||
** switches (-Os), gcc may align this Mem object on a 4-byte boundary
|
||||
** instead of an 8-byte one. This all works fine, except that when
|
||||
** running with SQLITE_DEBUG defined the SQLite code sometimes assert()s
|
||||
** that a Mem structure is located on an 8-byte boundary. To prevent
|
||||
** these assert()s from failing, when building with SQLITE_DEBUG defined
|
||||
** using gcc, we force nullMem to be 8-byte aligned using the magical
|
||||
** __attribute__((aligned(8))) macro. */
|
||||
static const Mem nullMem
|
||||
#if defined(SQLITE_DEBUG) && defined(__GNUC__)
|
||||
__attribute__((aligned(8)))
|
||||
#endif
|
||||
= {0, "", (double)0, {0}, 0, MEM_Null, SQLITE_NULL, 0,
|
||||
#ifdef SQLITE_DEBUG
|
||||
0, 0, /* pScopyFrom, pFiller */
|
||||
#endif
|
||||
0, 0 };
|
||||
|
||||
if( pVm && ALWAYS(pVm->db) ){
|
||||
sqlite3_mutex_enter(pVm->db->mutex);
|
||||
sqlite3Error(pVm->db, SQLITE_RANGE, 0);
|
||||
|
@@ -3921,12 +3921,14 @@ static int whereLoopAddBtreeIndex(
|
||||
|
||||
/* Consider using a skip-scan if there are no WHERE clause constraints
|
||||
** available for the left-most terms of the index, and if the average
|
||||
** number of repeats in the left-most terms is at least 50.
|
||||
** number of repeats in the left-most terms is at least 18. The magic
|
||||
** number 18 was found by experimentation to be the payoff point where
|
||||
** skip-scan become faster than a full-scan.
|
||||
*/
|
||||
if( pTerm==0
|
||||
&& saved_nEq==saved_nSkip
|
||||
&& saved_nEq+1<pProbe->nKeyCol
|
||||
&& pProbe->aiRowEst[saved_nEq+1]>50 /* TUNING: Minimum for skip-scan */
|
||||
&& pProbe->aiRowEst[saved_nEq+1]>=18 /* TUNING: Minimum for skip-scan */
|
||||
){
|
||||
LogEst nIter;
|
||||
pNew->u.btree.nEq++;
|
||||
|
@@ -1103,7 +1103,7 @@ do_catchsql_test e_createtable-3.11.5 {
|
||||
# EVIDENCE-OF: R-52382-54248 Each table in SQLite may have at most one
|
||||
# PRIMARY KEY.
|
||||
#
|
||||
# EVIDENCE-OF: R-62315-57691 An error is rasied if more than one PRIMARY
|
||||
# EVIDENCE-OF: R-31826-01813 An error is raised if more than one PRIMARY
|
||||
# KEY clause appears in a CREATE TABLE statement.
|
||||
#
|
||||
# To test the two above, show that zero primary keys is Ok, one primary
|
||||
@@ -1654,6 +1654,10 @@ do_execsql_test 4.19.4 { SELECT * FROM t5 } {}
|
||||
# of the special case-independent names "rowid", "oid", or "_rowid_" in
|
||||
# place of a column name.
|
||||
#
|
||||
# EVIDENCE-OF: R-06726-07466 A column name can be any of the names
|
||||
# defined in the CREATE TABLE statement or one of the following special
|
||||
# identifiers: "ROWID", "OID", or "_ROWID_".
|
||||
#
|
||||
drop_all_tables
|
||||
do_execsql_test 5.1.0 {
|
||||
CREATE TABLE t1(x, y);
|
||||
@@ -1678,6 +1682,10 @@ do_createtable_tests 5.1 {
|
||||
# explicitly declared column and cannot be used to retrieve the integer
|
||||
# rowid value.
|
||||
#
|
||||
# EVIDENCE-OF: R-44615-33286 The special identifiers only refer to the
|
||||
# row key if the CREATE TABLE statement does not define a real column
|
||||
# with the same name.
|
||||
#
|
||||
do_execsql_test 5.2.0 {
|
||||
CREATE TABLE t2(oid, b);
|
||||
CREATE TABLE t3(a, _rowid_);
|
||||
|
@@ -1407,10 +1407,12 @@ do_test e_expr-26.1.6 { set ::evalcount } {5}
|
||||
#-------------------------------------------------------------------------
|
||||
# Test statements related to CAST expressions.
|
||||
#
|
||||
# EVIDENCE-OF: R-65079-31758 Application of a CAST expression is
|
||||
# different to application of a column affinity, as with a CAST
|
||||
# expression the storage class conversion is forced even if it is lossy
|
||||
# and irrreversible.
|
||||
# EVIDENCE-OF: R-20854-17109 A CAST conversion is similar to the
|
||||
# conversion that takes place when a column affinity is applied to a
|
||||
# value except that with the CAST operator the conversion always takes
|
||||
# place even if the conversion lossy and irreversible, whereas column
|
||||
# affinity only changes the data type of a value if the change is
|
||||
# lossless and reversible.
|
||||
#
|
||||
do_execsql_test e_expr-27.1.1 {
|
||||
CREATE TABLE t3(a TEXT, b REAL, c INTEGER);
|
||||
@@ -1594,17 +1596,20 @@ do_expr_test e_expr-30.4.1 { CAST('' AS INTEGER) } integer 0
|
||||
do_expr_test e_expr-30.4.2 { CAST('not a number' AS INTEGER) } integer 0
|
||||
do_expr_test e_expr-30.4.3 { CAST('XXI' AS INTEGER) } integer 0
|
||||
|
||||
# EVIDENCE-OF: R-00741-38776 A cast of a REAL value into an INTEGER will
|
||||
# truncate the fractional part of the REAL.
|
||||
# EVIDENCE-OF: R-02752-50091 A cast of a REAL value into an INTEGER
|
||||
# results in the integer between the REAL value and zero that is closest
|
||||
# to the REAL value.
|
||||
#
|
||||
do_expr_test e_expr-31.1.1 { CAST(3.14159 AS INTEGER) } integer 3
|
||||
do_expr_test e_expr-31.1.2 { CAST(1.99999 AS INTEGER) } integer 1
|
||||
do_expr_test e_expr-31.1.3 { CAST(-1.99999 AS INTEGER) } integer -1
|
||||
do_expr_test e_expr-31.1.4 { CAST(-0.99999 AS INTEGER) } integer 0
|
||||
|
||||
# EVIDENCE-OF: R-49503-28105 If a REAL is too large to be represented as
|
||||
# an INTEGER then the result of the cast is the largest negative
|
||||
# integer: -9223372036854775808.
|
||||
# EVIDENCE-OF: R-51517-40824 If a REAL is greater than the greatest
|
||||
# possible signed integer (+9223372036854775807) then the result is the
|
||||
# greatest possible signed integer and if the REAL is less than the
|
||||
# least possible signed integer (-9223372036854775808) then the result
|
||||
# is the least possible signed integer.
|
||||
#
|
||||
do_expr_test e_expr-31.2.1 { CAST(2e+50 AS INT) } integer 9223372036854775807
|
||||
do_expr_test e_expr-31.2.2 { CAST(-2e+50 AS INT) } integer -9223372036854775808
|
||||
@@ -1847,5 +1852,43 @@ foreach {tn expr} {
|
||||
do_expr_test e_expr-36.4.$tn $expr null {}
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-62477-06476 For example, the values NULL, 0.0, 0,
|
||||
# 'english' and '0' are all considered to be false.
|
||||
#
|
||||
do_execsql_test e_expr-37.1 {
|
||||
SELECT CASE WHEN NULL THEN 'true' ELSE 'false' END;
|
||||
} {false}
|
||||
do_execsql_test e_expr-37.2 {
|
||||
SELECT CASE WHEN 0.0 THEN 'true' ELSE 'false' END;
|
||||
} {false}
|
||||
do_execsql_test e_expr-37.3 {
|
||||
SELECT CASE WHEN 0 THEN 'true' ELSE 'false' END;
|
||||
} {false}
|
||||
do_execsql_test e_expr-37.4 {
|
||||
SELECT CASE WHEN 'engligh' THEN 'true' ELSE 'false' END;
|
||||
} {false}
|
||||
do_execsql_test e_expr-37.5 {
|
||||
SELECT CASE WHEN '0' THEN 'true' ELSE 'false' END;
|
||||
} {false}
|
||||
|
||||
# EVIDENCE-OF: R-55532-10108 Values 1, 1.0, 0.1, -0.1 and '1english' are
|
||||
# considered to be true.
|
||||
#
|
||||
do_execsql_test e_expr-37.6 {
|
||||
SELECT CASE WHEN 1 THEN 'true' ELSE 'false' END;
|
||||
} {true}
|
||||
do_execsql_test e_expr-37.7 {
|
||||
SELECT CASE WHEN 1.0 THEN 'true' ELSE 'false' END;
|
||||
} {true}
|
||||
do_execsql_test e_expr-37.8 {
|
||||
SELECT CASE WHEN 0.1 THEN 'true' ELSE 'false' END;
|
||||
} {true}
|
||||
do_execsql_test e_expr-37.9 {
|
||||
SELECT CASE WHEN -0.1 THEN 'true' ELSE 'false' END;
|
||||
} {true}
|
||||
do_execsql_test e_expr-37.10 {
|
||||
SELECT CASE WHEN '1english' THEN 'true' ELSE 'false' END;
|
||||
} {true}
|
||||
|
||||
|
||||
finish_test
|
||||
|
@@ -128,21 +128,52 @@ db2 close
|
||||
# depopulation of indices, to make sure the update-hook is not
|
||||
# invoked incorrectly.
|
||||
#
|
||||
# EVIDENCE-OF: R-21999-45122 The sqlite3_update_hook() interface
|
||||
# registers a callback function with the database connection identified
|
||||
# by the first argument to be invoked whenever a row is updated,
|
||||
# inserted or deleted in a rowid table.
|
||||
|
||||
# Simple tests
|
||||
do_test hook-4.1.1 {
|
||||
do_test hook-4.1.1a {
|
||||
catchsql {
|
||||
DROP TABLE t1;
|
||||
}
|
||||
unset -nocomplain ::update_hook
|
||||
set ::update_hook {}
|
||||
db update_hook [list lappend ::update_hook]
|
||||
#
|
||||
# EVIDENCE-OF: R-52223-27275 The update hook is not invoked when
|
||||
# internal system tables are modified (i.e. sqlite_master and
|
||||
# sqlite_sequence).
|
||||
#
|
||||
execsql {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
|
||||
CREATE TABLE t1w(a INT PRIMARY KEY, b) WITHOUT ROWID;
|
||||
}
|
||||
set ::update_hook
|
||||
} {}
|
||||
do_test hook-4.1.1b {
|
||||
execsql {
|
||||
INSERT INTO t1 VALUES(1, 'one');
|
||||
INSERT INTO t1 VALUES(2, 'two');
|
||||
INSERT INTO t1 VALUES(3, 'three');
|
||||
INSERT INTO t1w SELECT * FROM t1;
|
||||
}
|
||||
db update_hook [list lappend ::update_hook]
|
||||
} {}
|
||||
|
||||
# EVIDENCE-OF: R-15506-57666 The second callback argument is one of
|
||||
# SQLITE_INSERT, SQLITE_DELETE, or SQLITE_UPDATE, depending on the
|
||||
# operation that caused the callback to be invoked.
|
||||
#
|
||||
# EVIDENCE-OF: R-29213-61195 The third and fourth arguments to the
|
||||
# callback contain pointers to the database and table name containing
|
||||
# the affected row.
|
||||
#
|
||||
# EVIDENCE-OF: R-30809-57812 The final callback parameter is the rowid
|
||||
# of the row.
|
||||
#
|
||||
do_test hook-4.1.2 {
|
||||
set ::update_hook {}
|
||||
execsql {
|
||||
INSERT INTO t1 VALUES(4, 'four');
|
||||
DELETE FROM t1 WHERE b = 'two';
|
||||
@@ -160,6 +191,24 @@ do_test hook-4.1.2 {
|
||||
DELETE main t1 4 \
|
||||
]
|
||||
|
||||
# EVIDENCE-OF: R-61808-14344 The sqlite3_update_hook() interface does
|
||||
# not fire callbacks for changes to a WITHOUT ROWID table.
|
||||
#
|
||||
# EVIDENCE-OF: R-33257-44249 The update hook is not invoked when WITHOUT
|
||||
# ROWID tables are modified.
|
||||
#
|
||||
breakpoint
|
||||
do_test hook-4.1.2w {
|
||||
set ::update_hook {}
|
||||
execsql {
|
||||
INSERT INTO t1w VALUES(4, 'four');
|
||||
DELETE FROM t1w WHERE b = 'two';
|
||||
UPDATE t1w SET b = '' WHERE a = 1 OR a = 3;
|
||||
DELETE FROM t1w WHERE 1; -- Avoid the truncate optimization (for now)
|
||||
}
|
||||
set ::update_hook
|
||||
} {}
|
||||
|
||||
ifcapable trigger {
|
||||
# Update hook is not invoked for changes to sqlite_master
|
||||
#
|
||||
|
@@ -36,6 +36,17 @@ do_test lastinsert-1.1 {
|
||||
}
|
||||
} {0 3}
|
||||
|
||||
# EVIDENCE-OF: R-47220-63683 The sqlite3_last_insert_rowid() function
|
||||
# does not work for WITHOUT ROWID tables.
|
||||
#
|
||||
do_test lastinsert-1.1w {
|
||||
catchsql {
|
||||
create table t1w (k integer primary key) WITHOUT ROWID;
|
||||
insert into t1w values (123456);
|
||||
select last_insert_rowid(); -- returns 3 from above.
|
||||
}
|
||||
} {0 3}
|
||||
|
||||
# LIRID unchanged after an update on a table
|
||||
do_test lastinsert-1.2 {
|
||||
catchsql {
|
||||
|
@@ -12,7 +12,9 @@
|
||||
# focus of this file is testing the magic ROWID column that is
|
||||
# found on all tables.
|
||||
#
|
||||
# $Id: rowid.test,v 1.21 2009/06/26 15:14:55 drh Exp $
|
||||
# EVIDENCE-OF: R-36924-43758 By default, every row in SQLite has a
|
||||
# special column, usually called the "rowid", that uniquely identifies
|
||||
# that row within the table.
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
190
test/skipscan2.test
Normal file
190
test/skipscan2.test
Normal file
@@ -0,0 +1,190 @@
|
||||
# 2013-11-27
|
||||
#
|
||||
# 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 file implements tests of the "skip-scan" query strategy.
|
||||
#
|
||||
# The test cases in this file are derived from the description of
|
||||
# the skip-scan query strategy in the "optoverview.html" document.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
do_execsql_test skipscan2-1.1 {
|
||||
CREATE TABLE people(
|
||||
name TEXT PRIMARY KEY,
|
||||
role TEXT NOT NULL,
|
||||
height INT NOT NULL, -- in cm
|
||||
CHECK( role IN ('student','teacher') )
|
||||
);
|
||||
CREATE INDEX people_idx1 ON people(role, height);
|
||||
} {}
|
||||
do_execsql_test skipscan2-1.2 {
|
||||
INSERT INTO people VALUES('Alice','student',156);
|
||||
INSERT INTO people VALUES('Bob','student',161);
|
||||
INSERT INTO people VALUES('Cindy','student',155);
|
||||
INSERT INTO people VALUES('David','student',181);
|
||||
INSERT INTO people VALUES('Emily','teacher',158);
|
||||
INSERT INTO people VALUES('Fred','student',163);
|
||||
INSERT INTO people VALUES('Ginny','student',169);
|
||||
INSERT INTO people VALUES('Harold','student',172);
|
||||
INSERT INTO people VALUES('Imma','student',179);
|
||||
INSERT INTO people VALUES('Jack','student',181);
|
||||
INSERT INTO people VALUES('Karen','student',163);
|
||||
INSERT INTO people VALUES('Logan','student',177);
|
||||
INSERT INTO people VALUES('Megan','teacher',159);
|
||||
INSERT INTO people VALUES('Nathan','student',163);
|
||||
INSERT INTO people VALUES('Olivia','student',161);
|
||||
INSERT INTO people VALUES('Patrick','teacher',180);
|
||||
INSERT INTO people VALUES('Quiana','student',182);
|
||||
INSERT INTO people VALUES('Robert','student',159);
|
||||
INSERT INTO people VALUES('Sally','student',166);
|
||||
INSERT INTO people VALUES('Tom','student',171);
|
||||
INSERT INTO people VALUES('Ursula','student',170);
|
||||
INSERT INTO people VALUES('Vance','student',179);
|
||||
INSERT INTO people VALUES('Willma','student',175);
|
||||
INSERT INTO people VALUES('Xavier','teacher',185);
|
||||
INSERT INTO people VALUES('Yvonne','student',149);
|
||||
INSERT INTO people VALUES('Zach','student',170);
|
||||
}
|
||||
|
||||
# Without ANALYZE, a skip-scan is not used
|
||||
#
|
||||
do_execsql_test skipscan2-1.3 {
|
||||
SELECT name FROM people WHERE height>=180 ORDER BY +name;
|
||||
} {David Jack Patrick Quiana Xavier}
|
||||
do_execsql_test skipscan2-1.3eqp {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT name FROM people WHERE height>=180 ORDER BY +name;
|
||||
} {~/*INDEX people_idx1 */}
|
||||
|
||||
# Now do an ANALYZE. A skip-scan can be used after ANALYZE.
|
||||
#
|
||||
do_execsql_test skipscan2-1.4 {
|
||||
ANALYZE;
|
||||
-- We do not have enough people above to actually force the use
|
||||
-- of a skip-scan. So make a manual adjustment to the stat1 table
|
||||
-- to make it seem like there are many more.
|
||||
UPDATE sqlite_stat1 SET stat='10000 5000 20' WHERE idx='people_idx1';
|
||||
ANALYZE sqlite_master;
|
||||
}
|
||||
db cache flush
|
||||
do_execsql_test skipscan2-1.5 {
|
||||
SELECT name FROM people WHERE height>=180 ORDER BY +name;
|
||||
} {David Jack Patrick Quiana Xavier}
|
||||
do_execsql_test skipscan2-1.5eqp {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT name FROM people WHERE height>=180 ORDER BY +name;
|
||||
} {/*INDEX people_idx1 */}
|
||||
|
||||
# Same answer with other formulations of the same query
|
||||
#
|
||||
do_execsql_test skipscan2-1.6 {
|
||||
SELECT name FROM people
|
||||
WHERE role IN (SELECT DISTINCT role FROM people)
|
||||
AND height>=180 ORDER BY +name;
|
||||
} {David Jack Patrick Quiana Xavier}
|
||||
do_execsql_test skipscan2-1.7 {
|
||||
SELECT name FROM people WHERE role='teacher' AND height>=180
|
||||
UNION ALL
|
||||
SELECT name FROM people WHERE role='student' AND height>=180
|
||||
ORDER BY 1;
|
||||
} {David Jack Patrick Quiana Xavier}
|
||||
|
||||
# Add 8 more people, bringing the total to 34. Then the number of
|
||||
# duplicates in the left-column of the index will be 17 and
|
||||
# skip-scan should not be used after an (unfudged) ANALYZE.
|
||||
#
|
||||
do_execsql_test skipscan2-1.8 {
|
||||
INSERT INTO people VALUES('Angie','student',166);
|
||||
INSERT INTO people VALUES('Brad','student',176);
|
||||
INSERT INTO people VALUES('Claire','student',168);
|
||||
INSERT INTO people VALUES('Donald','student',162);
|
||||
INSERT INTO people VALUES('Elaine','student',177);
|
||||
INSERT INTO people VALUES('Frazier','student',159);
|
||||
INSERT INTO people VALUES('Grace','student',179);
|
||||
INSERT INTO people VALUES('Horace','student',166);
|
||||
ANALYZE;
|
||||
SELECT stat FROM sqlite_stat1 WHERE idx='people_idx1';
|
||||
} {{34 17 2}}
|
||||
db cache flush
|
||||
do_execsql_test skipscan2-1.9 {
|
||||
SELECT name FROM people WHERE height>=180 ORDER BY +name;
|
||||
} {David Jack Patrick Quiana Xavier}
|
||||
do_execsql_test skipscan2-1.9eqp {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT name FROM people WHERE height>=180 ORDER BY +name;
|
||||
} {~/*INDEX people_idx1 */}
|
||||
|
||||
# Add 2 more people, bringing the total to 36. Then the number of
|
||||
# duplicates in the left-column of the index will be 18 and
|
||||
# skip-scan will be used after an (unfudged) ANALYZE.
|
||||
#
|
||||
do_execsql_test skipscan2-1.10 {
|
||||
INSERT INTO people VALUES('Ingrad','student',155);
|
||||
INSERT INTO people VALUES('Jacob','student',179);
|
||||
ANALYZE;
|
||||
SELECT stat FROM sqlite_stat1 WHERE idx='people_idx1';
|
||||
} {{36 18 2}}
|
||||
db cache flush
|
||||
do_execsql_test skipscan2-1.11 {
|
||||
SELECT name FROM people WHERE height>=180 ORDER BY +name;
|
||||
} {David Jack Patrick Quiana Xavier}
|
||||
do_execsql_test skipscan2-1.11eqp {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT name FROM people WHERE height>=180 ORDER BY +name;
|
||||
} {/*INDEX people_idx1 */}
|
||||
|
||||
|
||||
# Repeat using a WITHOUT ROWID table.
|
||||
#
|
||||
do_execsql_test skipscan2-2.1 {
|
||||
CREATE TABLE peoplew(
|
||||
name TEXT PRIMARY KEY,
|
||||
role TEXT NOT NULL,
|
||||
height INT NOT NULL, -- in cm
|
||||
CHECK( role IN ('student','teacher') )
|
||||
) WITHOUT ROWID;
|
||||
CREATE INDEX peoplew_idx1 ON peoplew(role, height);
|
||||
INSERT INTO peoplew(name,role,height)
|
||||
SELECT name, role, height FROM people;
|
||||
ALTER TABLE people RENAME TO old_people;
|
||||
SELECT name FROM peoplew WHERE height>=180 ORDER BY +name;
|
||||
} {David Jack Patrick Quiana Xavier}
|
||||
do_execsql_test skipscan2-2.2 {
|
||||
SELECT name FROM peoplew
|
||||
WHERE role IN (SELECT DISTINCT role FROM peoplew)
|
||||
AND height>=180 ORDER BY +name;
|
||||
} {David Jack Patrick Quiana Xavier}
|
||||
do_execsql_test skipscan2-2.2 {
|
||||
SELECT name FROM peoplew WHERE role='teacher' AND height>=180
|
||||
UNION ALL
|
||||
SELECT name FROM peoplew WHERE role='student' AND height>=180
|
||||
ORDER BY 1;
|
||||
} {David Jack Patrick Quiana Xavier}
|
||||
|
||||
# Now do an ANALYZE. A skip-scan can be used after ANALYZE.
|
||||
#
|
||||
do_execsql_test skipscan2-2.4 {
|
||||
ANALYZE;
|
||||
}
|
||||
db cache flush
|
||||
do_execsql_test skipscan2-2.5 {
|
||||
SELECT name FROM peoplew WHERE height>=180 ORDER BY +name;
|
||||
} {David Jack Patrick Quiana Xavier}
|
||||
do_execsql_test skipscan2-2.5eqp {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT name FROM peoplew WHERE height>=180 ORDER BY +name;
|
||||
} {/*INDEX peoplew_idx1 */}
|
||||
|
||||
|
||||
|
||||
finish_test
|
@@ -122,8 +122,8 @@ static int integerValue(const char *zArg){
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( v>=2147483648 ) fatal_error("parameter to large - max 2147483648");
|
||||
return isNeg? -v : v;
|
||||
if( v>0x7fffffff ) fatal_error("parameter too large - max 2147483648");
|
||||
return (int)(isNeg? -v : v);
|
||||
}
|
||||
|
||||
/* Return the current wall-clock time, in milliseconds */
|
||||
@@ -256,8 +256,8 @@ void speedtest1_begin_test(int iTestNum, const char *zTestName, ...){
|
||||
sqlite3_free(zName);
|
||||
g.nResult = 0;
|
||||
g.iStart = speedtest1_timestamp();
|
||||
g.x = 2903710987;
|
||||
g.y = 1157229256;
|
||||
g.x = 0xad131d0b;
|
||||
g.y = 0x44f9eac8;
|
||||
}
|
||||
|
||||
/* Complete a test case */
|
||||
|
201
test/without_rowid5.test
Normal file
201
test/without_rowid5.test
Normal file
@@ -0,0 +1,201 @@
|
||||
# 2013-11-26
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Requirements testing for WITHOUT ROWID tables.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
|
||||
# EVIDENCE-OF: R-36924-43758 By default, every row in SQLite has a
|
||||
# special column, usually called the "rowid", that uniquely identifies
|
||||
# that row within the table.
|
||||
#
|
||||
# EVIDENCE-OF: R-32341-39358 However if the phrase "WITHOUT ROWID" is
|
||||
# added to the end of a CREATE TABLE statement, then the special "rowid"
|
||||
# column is omitted.
|
||||
#
|
||||
do_execsql_test without_rowid5-1.1 {
|
||||
CREATE TABLE t1(a PRIMARY KEY,b,c);
|
||||
CREATE TABLE t1w(a PRIMARY KEY,b,c) WITHOUT ROWID;
|
||||
INSERT INTO t1 VALUES(1565,681,1148),(1429,1190,1619),(425,358,1306);
|
||||
INSERT INTO t1w SELECT a,b,c FROM t1;
|
||||
SELECT rowid, _rowid_, oid FROM t1 ORDER BY a DESC;
|
||||
} {1 1 1 2 2 2 3 3 3}
|
||||
do_catchsql_test without_rowid5-1.2 {
|
||||
SELECT rowid FROM t1w;
|
||||
} {1 {no such column: rowid}}
|
||||
do_catchsql_test without_rowid5-1.3 {
|
||||
SELECT _rowid_ FROM t1w;
|
||||
} {1 {no such column: _rowid_}}
|
||||
do_catchsql_test without_rowid5-1.4 {
|
||||
SELECT oid FROM t1w;
|
||||
} {1 {no such column: oid}}
|
||||
|
||||
# EVIDENCE-OF: R-00217-01605 To create a WITHOUT ROWID table, simply add
|
||||
# the keywords "WITHOUT ROWID" to the end of the CREATE TABLE statement.
|
||||
# For example: CREATE TABLE IF NOT EXISTS wordcount( word TEXT PRIMARY
|
||||
# KEY, cnt INTEGER ) WITHOUT ROWID;
|
||||
#
|
||||
do_execsql_test without_rowid5-2.1 {
|
||||
CREATE TABLE IF NOT EXISTS wordcount(
|
||||
word TEXT PRIMARY KEY,
|
||||
cnt INTEGER
|
||||
) WITHOUT ROWID;
|
||||
INSERT INTO wordcount VALUES('one',1);
|
||||
} {}
|
||||
do_catchsql_test without_rowid5-2.2 {
|
||||
SELECT rowid FROM wordcount;
|
||||
} {1 {no such column: rowid}}
|
||||
|
||||
# EVIDENCE-OF: R-24770-17719 As with all SQL syntax, the case of the
|
||||
# keywords does not matter. One can write "WITHOUT rowid" or "without
|
||||
# rowid" or "WiThOuT rOwId" and it will mean the same thing.
|
||||
#
|
||||
do_execsql_test without_rowid5-2.3 {
|
||||
CREATE TABLE IF NOT EXISTS wordcount_b(
|
||||
word TEXT PRIMARY KEY,
|
||||
cnt INTEGER
|
||||
) WITHOUT rowid;
|
||||
INSERT INTO wordcount_b VALUES('one',1);
|
||||
} {}
|
||||
do_catchsql_test without_rowid5-2.4 {
|
||||
SELECT rowid FROM wordcount_b;
|
||||
} {1 {no such column: rowid}}
|
||||
do_execsql_test without_rowid5-2.5 {
|
||||
CREATE TABLE IF NOT EXISTS wordcount_c(
|
||||
word TEXT PRIMARY KEY,
|
||||
cnt INTEGER
|
||||
) without rowid;
|
||||
INSERT INTO wordcount_c VALUES('one',1);
|
||||
} {}
|
||||
do_catchsql_test without_rowid5-2.6 {
|
||||
SELECT rowid FROM wordcount_c;
|
||||
} {1 {no such column: rowid}}
|
||||
do_execsql_test without_rowid5-2.7 {
|
||||
CREATE TABLE IF NOT EXISTS wordcount_d(
|
||||
word TEXT PRIMARY KEY,
|
||||
cnt INTEGER
|
||||
) WITHOUT rowid;
|
||||
INSERT INTO wordcount_d VALUES('one',1);
|
||||
} {}
|
||||
do_catchsql_test without_rowid5-2.8 {
|
||||
SELECT rowid FROM wordcount_d;
|
||||
} {1 {no such column: rowid}}
|
||||
|
||||
# EVIDENCE-OF: R-01418-51310 However, only "rowid" works as the keyword
|
||||
# in the CREATE TABLE statement.
|
||||
#
|
||||
do_catchsql_test without_rowid5-3.1 {
|
||||
CREATE TABLE IF NOT EXISTS error1(
|
||||
word TEXT PRIMARY KEY,
|
||||
cnt INTEGER
|
||||
) WITHOUT _rowid_;
|
||||
} {1 {unknown table option: _rowid_}}
|
||||
do_catchsql_test without_rowid5-3.2 {
|
||||
CREATE TABLE IF NOT EXISTS error2(
|
||||
word TEXT PRIMARY KEY,
|
||||
cnt INTEGER
|
||||
) WITHOUT oid;
|
||||
} {1 {unknown table option: oid}}
|
||||
|
||||
# EVIDENCE-OF: R-58033-17334 An error is raised if a CREATE TABLE
|
||||
# statement with the WITHOUT ROWID clause lacks a PRIMARY KEY.
|
||||
#
|
||||
# EVIDENCE-OF: R-63443-09418 Every WITHOUT ROWID table must have a
|
||||
# PRIMARY KEY.
|
||||
#
|
||||
# EVIDENCE-OF: R-27966-31616 An attempt to create a WITHOUT ROWID table
|
||||
# without a PRIMARY KEY results in an error.
|
||||
#
|
||||
do_catchsql_test without_rowid5-4.1 {
|
||||
CREATE TABLE IF NOT EXISTS error3(
|
||||
word TEXT UNIQUE,
|
||||
cnt INTEGER
|
||||
) WITHOUT ROWID;
|
||||
} {1 {PRIMARY KEY missing on table error3}}
|
||||
|
||||
# EVIDENCE-OF: R-48230-36247 The special behaviors associated "INTEGER
|
||||
# PRIMARY KEY" do not apply on WITHOUT ROWID tables.
|
||||
#
|
||||
do_execsql_test without_rowid5-5.1 {
|
||||
CREATE TABLE ipk(key INTEGER PRIMARY KEY, val TEXT) WITHOUT ROWID;
|
||||
INSERT INTO ipk VALUES('rival','bonus'); -- ok to insert non-integer key
|
||||
SELECT * FROM ipk;
|
||||
} {rival bonus}
|
||||
do_catchsql_test without_rowid5-5.2 {
|
||||
INSERT INTO ipk VALUES(NULL,'sample'); -- no automatic generation of keys
|
||||
} {1 {NOT NULL constraint failed: ipk.key}}
|
||||
|
||||
# EVIDENCE-OF: R-33142-02092 AUTOINCREMENT does not work on WITHOUT
|
||||
# ROWID tables.
|
||||
#
|
||||
# EVIDENCE-OF: R-53084-07740 An error is raised if the "AUTOINCREMENT"
|
||||
# keyword is used in the CREATE TABLE statement for a WITHOUT ROWID
|
||||
# table.
|
||||
#
|
||||
do_catchsql_test without_rowid5-5.3 {
|
||||
CREATE TABLE ipk2(key INTEGER PRIMARY KEY AUTOINCREMENT, val TEXT)WITHOUT ROWID;
|
||||
} {1 {AUTOINCREMENT not allowed on WITHOUT ROWID tables}}
|
||||
|
||||
# EVIDENCE-OF: R-27831-00579 NOT NULL is enforced on every column of the
|
||||
# PRIMARY KEY in a WITHOUT ROWID table.
|
||||
#
|
||||
# EVIDENCE-OF: R-29781-51289 So, ordinary rowid tables in SQLite violate
|
||||
# the SQL standard and allow NULL values in PRIMARY KEY fields.
|
||||
#
|
||||
# EVIDENCE-OF: R-27472-62612 But WITHOUT ROWID tables do follow the
|
||||
# standard and will throw an error on any attempt to insert a NULL into
|
||||
# a PRIMARY KEY column.
|
||||
#
|
||||
do_execsql_test without_rowid5-5.4 {
|
||||
CREATE TABLE nn(a, b, c, d, e, PRIMARY KEY(c,a,e));
|
||||
CREATE TABLE nnw(a, b, c, d, e, PRIMARY KEY(c,a,e)) WITHOUT ROWID;
|
||||
INSERT INTO nn VALUES(1,2,3,4,5);
|
||||
INSERT INTO nnw VALUES(1,2,3,4,5);
|
||||
} {}
|
||||
do_execsql_test without_rowid5-5.5 {
|
||||
INSERT INTO nn VALUES(NULL, 3,4,5,6);
|
||||
INSERT INTO nn VALUES(3,4,NULL,7,8);
|
||||
INSERT INTO nn VALUES(4,5,6,7,NULL);
|
||||
SELECT count(*) FROM nn;
|
||||
} {4}
|
||||
do_catchsql_test without_rowid5-5.6 {
|
||||
INSERT INTO nnw VALUES(NULL, 3,4,5,6);
|
||||
} {1 {NOT NULL constraint failed: nnw.a}}
|
||||
do_catchsql_test without_rowid5-5.7 {
|
||||
INSERT INTO nnw VALUES(3,4,NULL,7,8)
|
||||
} {1 {NOT NULL constraint failed: nnw.c}}
|
||||
do_catchsql_test without_rowid5-5.8 {
|
||||
INSERT INTO nnw VALUES(4,5,6,7,NULL)
|
||||
} {1 {NOT NULL constraint failed: nnw.e}}
|
||||
do_execsql_test without_rowid5-5.9 {
|
||||
SELECT count(*) FROM nnw;
|
||||
} {1}
|
||||
|
||||
# EVIDENCE-OF: R-12643-30541 The incremental blob I/O mechanism does not
|
||||
# work for WITHOUT ROWID tables.
|
||||
#
|
||||
# EVIDENCE-OF: R-25760-33257 The sqlite3_blob_open() interface will fail
|
||||
# for a WITHOUT ROWID table.
|
||||
#
|
||||
do_execsql_test without_rowid5-6.1 {
|
||||
CREATE TABLE b1(a INTEGER PRIMARY KEY, b BLOB) WITHOUT ROWID;
|
||||
INSERT INTO b1 VALUES(1,x'0102030405060708090a0b0c0d0e0f');
|
||||
} {}
|
||||
do_test without_rowid5-6.2 {
|
||||
set rc [catch {db incrblob b1 b 1} msg]
|
||||
lappend rc $msg
|
||||
} {1 {cannot open table without rowid: b1}}
|
||||
|
||||
|
||||
finish_test
|
Reference in New Issue
Block a user