1
0
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:
drh
2013-11-27 21:53:51 +00:00
17 changed files with 621 additions and 114 deletions

View File

@@ -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

View File

@@ -1 +1 @@
fc9ae839569eb28eb734c52d95676c59b2e27494
3a2a1bd47875e114d8e6f31c1768908f401d2861

View File

@@ -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)

View File

@@ -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++;

View File

@@ -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 */

View File

@@ -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>)^

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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++;

View File

@@ -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_);

View File

@@ -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

View File

@@ -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
#

View File

@@ -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 {

View File

@@ -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
View 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

View File

@@ -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
View 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