diff --git a/ext/icu/icu.c b/ext/icu/icu.c index 3f45646194..4d19dfbd62 100644 --- a/ext/icu/icu.c +++ b/ext/icu/icu.c @@ -354,15 +354,17 @@ static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){ ** http://www.icu-project.org/userguide/posix.html#case_mappings */ static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){ - const UChar *zInput; - UChar *zOutput = 0; - int nInput; - int nOut; + const UChar *zInput; /* Pointer to input string */ + UChar *zOutput = 0; /* Pointer to output buffer */ + int nInput; /* Size of utf-16 input string in bytes */ + int nOut; /* Size of output buffer in bytes */ int cnt; + int bToUpper; /* True for toupper(), false for tolower() */ UErrorCode status; const char *zLocale = 0; assert(nArg==1 || nArg==2); + bToUpper = (sqlite3_user_data(p)!=0); if( nArg==2 ){ zLocale = (const char *)sqlite3_value_text(apArg[1]); } @@ -386,19 +388,23 @@ static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){ } zOutput = zNew; status = U_ZERO_ERROR; - if( sqlite3_user_data(p) ){ + if( bToUpper ){ nOut = 2*u_strToUpper(zOutput,nOut/2,zInput,nInput/2,zLocale,&status); }else{ nOut = 2*u_strToLower(zOutput,nOut/2,zInput,nInput/2,zLocale,&status); } - if( !U_SUCCESS(status) ){ - if( status==U_BUFFER_OVERFLOW_ERROR ) continue; - icuFunctionError(p, - sqlite3_user_data(p) ? "u_strToUpper" : "u_strToLower", status); - return; + + if( U_SUCCESS(status) ){ + sqlite3_result_text16(p, zOutput, nOut, xFree); + }else if( status==U_BUFFER_OVERFLOW_ERROR ){ + assert( cnt==0 ); + continue; + }else{ + icuFunctionError(p, bToUpper ? "u_strToUpper" : "u_strToLower", status); } + return; } - sqlite3_result_text16(p, zOutput, nOut, xFree); + assert( 0 ); /* Unreachable */ } /* diff --git a/manifest b/manifest index 4b67df4189..a150702877 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C sqlite3PCachePerecentDirty()\sshould\sreturn\s0\sif\sthe\spcache\sis\sempty. -D 2016-04-18T13:30:50.144 +C Merge\srecent\strunk\schanges. +D 2016-04-18T13:36:17.439 F Makefile.in eba680121821b8a60940a81454316f47a341487a F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.msc 71b8b16cf9393f68e2e2035486ca104872558836 @@ -201,7 +201,7 @@ F ext/fts5/tool/loadfts5.tcl 95b03429ee6b138645703c6ca192c3ac96eaf093 F ext/fts5/tool/mkfts5c.tcl d1c2a9ab8e0ec690a52316f33dd9b1d379942f45 F ext/fts5/tool/showfts5.tcl d54da0e067306663e2d5d523965ca487698e722c F ext/icu/README.txt d9fbbad0c2f647c3fdf715fc9fd64af53aedfc43 -F ext/icu/icu.c 4bdf4c5daedabcd8e6eb6e6a377657f7b978f9f7 +F ext/icu/icu.c 43df9d8ef2fae7a325100ebd713ab089dc829dd7 F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37 F ext/misc/amatch.c 211108e201105e4bb0c076527b8cfd34330fc234 F ext/misc/closure.c 0d2a038df8fbae7f19de42e7c7d71f2e4dc88704 @@ -355,15 +355,15 @@ F src/mutex_noop.c 9d4309c075ba9cc7249e19412d3d62f7f94839c4 F src/mutex_unix.c 27bb6cc49485ee46711a6580ab7b3f1402211d23 F src/mutex_w32.c 5e6fe1c298fb5a8a15aaed4161d5759311431c17 F src/notify.c 9711a7575036f0d3040ba61bc6e217f13a9888e7 -F src/os.c ca10edb445ad2c5fdc7285b49d72bcdf261fa23e -F src/os.h 91ff889115ecd01f436d3611f7f5ea4dc12d92f1 +F src/os.c 4d83917f072ad958fba9235136fa2ed43df47905 +F src/os.h 8e976e59eb4ca1c0fca6d35ee803e38951cb0343 F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85 F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa -F src/os_unix.c bde4844f0849cab5924c6a81178f8500774ce76b +F src/os_unix.c d0b41a47eb5f0dc00e423a1723aadeab0e78c85f F src/os_win.c b169437dff859e308b3726594094a2f8ca922941 F src/os_win.h eb7a47aa17b26b77eb97e4823f20a00b8bda12ca F src/pager.c 4d849ad718980d698157cd136a40dc91cbeff4d3 -F src/pager.h e1d38a2f14849e219df0f91f8323504d134c8a56 +F src/pager.h 329bdf078a4e0a3b35084534d58625d21fd03681 F src/parse.y 10eb2f3fb62341291528c7984498054731f9d31e F src/pcache.c b3230ecfc7f797063fbe167f2845da363e8f07f8 F src/pcache.h 60bc9893bfc0e16f8178fb5d8b6fcb8fab1d93c0 @@ -375,12 +375,12 @@ F src/printf.c 63e6fb12bbe702dd664dc3703776c090383a5a26 F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 F src/resolve.c b8f7174e5f8c33c44ded3a25a973d0bb89228c20 F src/rowset.c 9fe4b3ad7cc00944386bb600233d8f523de07a6e -F src/select.c a07e6022e2b559f3c2ec80442472c5965fa7a3fc -F src/shell.c aeaab68456010319cb71406cbaca05865b295154 +F src/select.c 30217121bdf6b587462150b8ee9e1467f7a6036b +F src/shell.c 14ff7f660530a52b117d110ba3390b7b2eb719b6 F src/sqlite.h.in 64eb70a3b309751bebf73a5552a51244f68f0ea5 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 98f72cbfe00169c39089115427d06ea05fe4b4a2 -F src/sqliteInt.h b3744b29555b83054f315f62d61b3a6558fa9e1c +F src/sqliteInt.h 49cd2b5cd07cca7c462608540cb6dfa8ab03ba89 F src/sqliteLimit.h c0373387c287c8d0932510b5547ecde31b5da247 F src/status.c 70912d7be68e9e2dbc4010c93d344af61d4c59ba F src/table.c 5226df15ab9179b9ed558d89575ea0ce37b03fc9 @@ -402,14 +402,14 @@ F src/test_blob.c b2551a9b5573232db5f66f292307c37067937239 F src/test_btree.c 2e9978eca99a9a4bfa8cae949efb00886860a64f F src/test_config.c 7003f6f35134de6f19c6588f44783e43390ea277 F src/test_demovfs.c 0de72c2c89551629f58486fde5734b7d90758852 -F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc +F src/test_devsym.c 7e73009d5297b603c11c66d7c7d6723d4b5c73e1 F src/test_fs.c f10f840ca4f8c72e4837908bd8347ac4bcab074b F src/test_func.c 37453d346cfcf118774efd5bf6187f7e6a7e3254 F src/test_hexio.c abfdecb6fa58c354623978efceb088ca18e379cd F src/test_init.c 66b33120ffe9cd853b5a905ec850d51151337b32 F src/test_intarray.c 870124b95ec4c645d4eb84f15efb7133528fb1a5 F src/test_intarray.h 9dc57417fb65bc7835cc18548852cc08cc062202 -F src/test_journal.c 5360fbe1d1e4416ca36290562fd5a2e3f70f32aa +F src/test_journal.c da540964c675fde39487da2bc664096af97190d8 F src/test_loadext.c 337056bae59f80b9eb00ba82088b39d0f4fe6dfd F src/test_malloc.c 94c18e88d6df6d471a0d04ddb809f833d1739950 F src/test_multiplex.c eafc567ebe162e36f17b5062285dfe90461cf8e9 @@ -425,10 +425,10 @@ F src/test_schema.c 2bdba21b82f601da69793e1f1d11bf481a79b091 F src/test_server.c a2615049954cbb9cfb4a62e18e2f0616e4dc38fe F src/test_sqllog.c 0d138a8180a312bf996b37fa66da5c5799d4d57b F src/test_superlock.c 06797157176eb7085027d9dd278c0d7a105e3ec9 -F src/test_syscall.c 2e21ca7f7dc54a028f1967b63f1e76155c356f9b +F src/test_syscall.c 4889d374f5a5856b7951f7a67c6401f7b938c6f5 F src/test_tclvar.c d86412527da65468ee6fa1b8607c65d0af736bc4 F src/test_thread.c af391ec03d23486dffbcc250b7e58e073f172af9 -F src/test_vfs.c 3b65d42e18b262805716bd96178c81da8f2d9283 +F src/test_vfs.c 4d02f38bfb8f7f273da7ba84bfe000f5babf206c F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698 F src/test_windirent.c 8f5fada630348558d5745b334702f301da1ffc61 F src/test_windirent.h b12055cab6227f7be10f5c19296f67c60cc5e2a5 @@ -448,15 +448,15 @@ F src/vdbeapi.c ba85b78fe08dc4a9ce747e62c89a2b4a4547e74c F src/vdbeaux.c ace1875da40b7185e604586768d5ac90de7e4f7f F src/vdbeblob.c c9f2f494b911c6fa34efd9803f0a10807da80f77 F src/vdbemem.c 5cfef60e60e19cab6275d1b975bf4c791d575beb -F src/vdbesort.c 307460bfa4de4d1c3901fcd42089159131e34062 +F src/vdbesort.c 0a8f98366ae794442e6d1ef71d9553226d885d19 F src/vdbetrace.c f75c5455d8cf389ef86a8bfdfd3177e0e3692484 F src/vtab.c 23b6cdfa996152d43b390504ed4a942c8caf3a00 F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c 4db22ed7e77bcf672b1a685d6ddeffba8d5be302 F src/wal.h 2f7c831cf3b071fa548bf2d5cac640846a7ff19c F src/walker.c 0f142b5bd3ed2041fc52d773880748b212e63354 -F src/where.c 24ab561466d92d313747c04edb1a36a7af8663be -F src/whereInt.h 93297d56edd137b7ea004490690fb6e2ce028a34 +F src/where.c bae50f2f18f9e8584549a77363858623b07e4915 +F src/whereInt.h 7de94b751f088fe3fdc8cc04a491376f0900a059 F src/wherecode.c 8fdad9fbba723df1c1e8d07e7ea8507572040340 F src/whereexpr.c eacc0e60d029a082b4fc0cc42ea98544add1319e F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 @@ -1073,7 +1073,7 @@ F test/sort.test c2adc635c2564241fefec0b3a68391ef6868fd3b F test/sort2.test cc23b7c19d684657559e8a55b02f7fcee03851d0 F test/sort3.test 1480ed7c4c157682542224e05e3b75faf4a149e5 F test/sort4.test 5c34d9623a4ae5921d956dfa2b70e77ed0fc6e5c -F test/sort5.test d3041ce3c475aa04142a959ae56ef6593f98a99f +F test/sort5.test e47ec7a490b9b36787755874175d8f413a3883d9 F test/sortfault.test d4ccf606a0c77498e2beb542764fd9394acb4d66 F test/speed1.test f2974a91d79f58507ada01864c0e323093065452 F test/speed1p.explain d841e650a04728b39e6740296b852dccdca9b2cb @@ -1484,7 +1484,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P ae16310c4e9a9b7e94874bd912fc6a4324cfaa2b -R 0620b8f840563243b73e6076ebdcd81f +P 85f3d80eb7319754792eef76996b2c740a2b0073 3a7d72986fabe9434ff5bd02c93169314f072b23 +R 10404030b7871fd2cdace5bd8bb71227 U drh -Z 04d9a6e624a4591b3aa3f8ec5734f1ff +Z 6da7b721a063bb7a65bebbe0704c9e5d diff --git a/manifest.uuid b/manifest.uuid index 9ac43a726e..5a0c9f6cf3 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -85f3d80eb7319754792eef76996b2c740a2b0073 \ No newline at end of file +d9768de502e34da42f3ad955947c23da50f57bce \ No newline at end of file diff --git a/src/os.c b/src/os.c index bfcc9cdd05..6138bf4f3f 100644 --- a/src/os.c +++ b/src/os.c @@ -81,13 +81,11 @@ int sqlite3_memdebug_vfs_oom_test = 1; ** of this would be completely automatic if SQLite were coded using ** C++ instead of plain old C. */ -int sqlite3OsClose(sqlite3_file *pId){ - int rc = SQLITE_OK; +void sqlite3OsClose(sqlite3_file *pId){ if( pId->pMethods ){ - rc = pId->pMethods->xClose(pId); + pId->pMethods->xClose(pId); pId->pMethods = 0; } - return rc; } int sqlite3OsRead(sqlite3_file *id, void *pBuf, int amt, i64 offset){ DO_OS_MALLOC_TEST(id); @@ -305,12 +303,10 @@ int sqlite3OsOpenMalloc( } return rc; } -int sqlite3OsCloseFree(sqlite3_file *pFile){ - int rc = SQLITE_OK; +void sqlite3OsCloseFree(sqlite3_file *pFile){ assert( pFile ); - rc = sqlite3OsClose(pFile); + sqlite3OsClose(pFile); sqlite3_free(pFile); - return rc; } /* diff --git a/src/os.h b/src/os.h index f813541561..947f88b36e 100644 --- a/src/os.h +++ b/src/os.h @@ -160,7 +160,7 @@ int sqlite3OsInit(void); /* ** Functions for accessing sqlite3_file methods */ -int sqlite3OsClose(sqlite3_file*); +void sqlite3OsClose(sqlite3_file*); int sqlite3OsRead(sqlite3_file*, void*, int amt, i64 offset); int sqlite3OsWrite(sqlite3_file*, const void*, int amt, i64 offset); int sqlite3OsTruncate(sqlite3_file*, i64 size); @@ -205,6 +205,6 @@ int sqlite3OsCurrentTimeInt64(sqlite3_vfs *, sqlite3_int64*); ** sqlite3_malloc() to obtain space for the file-handle structure. */ int sqlite3OsOpenMalloc(sqlite3_vfs *, const char *, sqlite3_file **, int,int*); -int sqlite3OsCloseFree(sqlite3_file *); +void sqlite3OsCloseFree(sqlite3_file *); #endif /* _SQLITE_OS_H_ */ diff --git a/src/os_unix.c b/src/os_unix.c index a797541e8f..aa86f00d70 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -405,7 +405,7 @@ static struct unix_syscall { #else { "pread64", (sqlite3_syscall_ptr)0, 0 }, #endif -#define osPread64 ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[10].pCurrent) +#define osPread64 ((ssize_t(*)(int,void*,size_t,off64_t))aSyscall[10].pCurrent) { "write", (sqlite3_syscall_ptr)write, 0 }, #define osWrite ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent) @@ -423,7 +423,7 @@ static struct unix_syscall { #else { "pwrite64", (sqlite3_syscall_ptr)0, 0 }, #endif -#define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\ +#define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off64_t))\ aSyscall[13].pCurrent) { "fchmod", (sqlite3_syscall_ptr)fchmod, 0 }, diff --git a/src/pager.h b/src/pager.h index 38a4982150..077fcd8b7f 100644 --- a/src/pager.h +++ b/src/pager.h @@ -68,7 +68,11 @@ typedef struct PgHdr DbPage; #define PAGER_LOCKINGMODE_EXCLUSIVE 1 /* -** Numeric constants that encode the journalmode. +** Numeric constants that encode the journalmode. +** +** The numeric values encoded here (other than PAGER_JOURNALMODE_QUERY) +** are exposed in the API via the "PRAGMA journal_mode" command and +** therefore cannot be changed without a compatibility break. */ #define PAGER_JOURNALMODE_QUERY (-1) /* Query the value of journalmode */ #define PAGER_JOURNALMODE_DELETE 0 /* Commit by deleting journal file */ @@ -86,6 +90,11 @@ typedef struct PgHdr DbPage; /* ** Flags for sqlite3PagerSetFlags() +** +** Value constraints (enforced via assert()): +** PAGER_FULLFSYNC == SQLITE_FullFSync +** PAGER_CKPT_FULLFSYNC == SQLITE_CkptFullFSync +** PAGER_CACHE_SPILL == SQLITE_CacheSpill */ #define PAGER_SYNCHRONOUS_OFF 0x01 /* PRAGMA synchronous=OFF */ #define PAGER_SYNCHRONOUS_NORMAL 0x02 /* PRAGMA synchronous=NORMAL */ diff --git a/src/select.c b/src/select.c index fc37db5747..b86e040f0f 100644 --- a/src/select.c +++ b/src/select.c @@ -3787,6 +3787,8 @@ static int pushDownWhereTerms( int nChng = 0; if( pWhere==0 ) return 0; if( (pSubq->selFlags & (SF_Aggregate|SF_Recursive))!=0 ){ + testcase( pSubq->selFlags & SF_Aggregate ); + testcase( pSubq->selFlags & SF_Recursive ); return 0; /* restrictions (1) and (2) */ } if( pSubq->pLimit!=0 ){ @@ -5092,6 +5094,13 @@ int sqlite3Select( ** the sDistinct.isTnct is still set. Hence, isTnct represents the ** original setting of the SF_Distinct flag, not the current setting */ assert( sDistinct.isTnct ); + +#if SELECTTRACE_ENABLED + if( sqlite3SelectTrace & 0x400 ){ + SELECTTRACE(0x400,pParse,p,("Transform DISTINCT into GROUP BY:\n")); + sqlite3TreeViewSelect(0, p, 0); + } +#endif } /* If there is an ORDER BY clause, then create an ephemeral index to diff --git a/src/shell.c b/src/shell.c index 33010e5ff1..5148177372 100644 --- a/src/shell.c +++ b/src/shell.c @@ -1062,7 +1062,7 @@ static int shell_callback( } case MODE_Pretty: { /* .schema and .fullschema with --indent */ char *z; - int i,j; + int j; int nParen = 0; char cEnd = 0; char c; @@ -1089,8 +1089,7 @@ static int shell_callback( while( j>0 && IsSpace(z[j-1]) ){ j--; } z[j] = 0; if( strlen30(z)>=79 ){ - for(i=j=0; z[i]; i++){ - char c = z[i]; + for(i=j=0; (c = z[i])!=0; i++){ if( c==cEnd ){ cEnd = 0; }else if( c=='"' || c=='\'' || c=='`' ){ @@ -1734,7 +1733,7 @@ static void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){ if( str_in_array(zOp, azGoto) && p2opnIndent && (abYield[p2op] || sqlite3_column_int(pSql, 2)) ){ - for(i=p2op+1; iaiIndent[i] += 2; + for(i=p2op; iaiIndent[i] += 2; } } @@ -1753,6 +1752,104 @@ static void explain_data_delete(ShellState *p){ p->iIndent = 0; } +/* +** Disable and restore .wheretrace and .selecttrace settings. +*/ +#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE) +extern int sqlite3SelectTrace; +static int savedSelectTrace; +#endif +#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE) +extern int sqlite3WhereTrace; +static int savedWhereTrace; +#endif +static void disable_debug_trace_modes(void){ +#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE) + savedSelectTrace = sqlite3SelectTrace; + sqlite3SelectTrace = 0; +#endif +#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE) + savedWhereTrace = sqlite3WhereTrace; + sqlite3WhereTrace = 0; +#endif +} +static void restore_debug_trace_modes(void){ +#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE) + sqlite3SelectTrace = savedSelectTrace; +#endif +#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE) + sqlite3WhereTrace = savedWhereTrace; +#endif +} + +/* +** Run a prepared statement +*/ +static void exec_prepared_stmt( + ShellState *pArg, /* Pointer to ShellState */ + sqlite3_stmt *pStmt, /* Statment to run */ + int (*xCallback)(void*,int,char**,char**,int*) /* Callback function */ +){ + int rc; + + /* perform the first step. this will tell us if we + ** have a result set or not and how wide it is. + */ + rc = sqlite3_step(pStmt); + /* if we have a result set... */ + if( SQLITE_ROW == rc ){ + /* if we have a callback... */ + if( xCallback ){ + /* allocate space for col name ptr, value ptr, and type */ + int nCol = sqlite3_column_count(pStmt); + void *pData = sqlite3_malloc64(3*nCol*sizeof(const char*) + 1); + if( !pData ){ + rc = SQLITE_NOMEM; + }else{ + char **azCols = (char **)pData; /* Names of result columns */ + char **azVals = &azCols[nCol]; /* Results */ + int *aiTypes = (int *)&azVals[nCol]; /* Result types */ + int i, x; + assert(sizeof(int) <= sizeof(char *)); + /* save off ptrs to column names */ + for(i=0; icMode==MODE_Insert ){ + azVals[i] = ""; + }else{ + azVals[i] = (char*)sqlite3_column_text(pStmt, i); + } + if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){ + rc = SQLITE_NOMEM; + break; /* from for */ + } + } /* end for */ + + /* if data and types extracted successfully... */ + if( SQLITE_ROW == rc ){ + /* call the supplied callback with the result row data */ + if( xCallback(pArg, nCol, azVals, azCols, aiTypes) ){ + rc = SQLITE_ABORT; + }else{ + rc = sqlite3_step(pStmt); + } + } + } while( SQLITE_ROW == rc ); + sqlite3_free(pData); + } + }else{ + do{ + rc = sqlite3_step(pStmt); + } while( rc == SQLITE_ROW ); + } + } +} + /* ** Execute a statement or set of statements. Print ** any result rows/columns depending on the current mode @@ -1780,6 +1877,7 @@ static int shell_exec( } while( zSql[0] && (SQLITE_OK == rc) ){ + static const char *zStmtSql; rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover); if( SQLITE_OK != rc ){ if( pzErrMsg ){ @@ -1792,6 +1890,8 @@ static int shell_exec( while( IsSpace(zSql[0]) ) zSql++; continue; } + zStmtSql = sqlite3_sql(pStmt); + while( IsSpace(zStmtSql[0]) ) zStmtSql++; /* save off the prepared statment handle and reset row count */ if( pArg ){ @@ -1801,15 +1901,15 @@ static int shell_exec( /* echo the sql statement if echo on */ if( pArg && pArg->echoOn ){ - const char *zStmtSql = sqlite3_sql(pStmt); utf8_printf(pArg->out, "%s\n", zStmtSql ? zStmtSql : zSql); } /* Show the EXPLAIN QUERY PLAN if .eqp is on */ - if( pArg && pArg->autoEQP ){ + if( pArg && pArg->autoEQP && sqlite3_strlike("EXPLAIN%",zStmtSql,0)!=0 ){ sqlite3_stmt *pExplain; - char *zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", - sqlite3_sql(pStmt)); + char *zEQP; + disable_debug_trace_modes(); + zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", zStmtSql); rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0); if( rc==SQLITE_OK ){ while( sqlite3_step(pExplain)==SQLITE_ROW ){ @@ -1821,13 +1921,27 @@ static int shell_exec( } sqlite3_finalize(pExplain); sqlite3_free(zEQP); + if( pArg->autoEQP>=2 ){ + /* Also do an EXPLAIN for ".eqp full" mode */ + zEQP = sqlite3_mprintf("EXPLAIN %s", zStmtSql); + rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0); + if( rc==SQLITE_OK ){ + pArg->cMode = MODE_Explain; + explain_data_prepare(pArg, pExplain); + exec_prepared_stmt(pArg, pExplain, xCallback); + explain_data_delete(pArg); + } + sqlite3_finalize(pExplain); + sqlite3_free(zEQP); + } + restore_debug_trace_modes(); } if( pArg ){ pArg->cMode = pArg->mode; if( pArg->autoExplain && sqlite3_column_count(pStmt)==8 - && sqlite3_strlike("%EXPLAIN%", sqlite3_sql(pStmt),0)==0 + && sqlite3_strlike("EXPLAIN%", zStmtSql,0)==0 ){ pArg->cMode = MODE_Explain; } @@ -1839,63 +1953,7 @@ static int shell_exec( } } - /* perform the first step. this will tell us if we - ** have a result set or not and how wide it is. - */ - rc = sqlite3_step(pStmt); - /* if we have a result set... */ - if( SQLITE_ROW == rc ){ - /* if we have a callback... */ - if( xCallback ){ - /* allocate space for col name ptr, value ptr, and type */ - int nCol = sqlite3_column_count(pStmt); - void *pData = sqlite3_malloc64(3*nCol*sizeof(const char*) + 1); - if( !pData ){ - rc = SQLITE_NOMEM; - }else{ - char **azCols = (char **)pData; /* Names of result columns */ - char **azVals = &azCols[nCol]; /* Results */ - int *aiTypes = (int *)&azVals[nCol]; /* Result types */ - int i, x; - assert(sizeof(int) <= sizeof(char *)); - /* save off ptrs to column names */ - for(i=0; icMode==MODE_Insert ){ - azVals[i] = ""; - }else{ - azVals[i] = (char*)sqlite3_column_text(pStmt, i); - } - if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){ - rc = SQLITE_NOMEM; - break; /* from for */ - } - } /* end for */ - - /* if data and types extracted successfully... */ - if( SQLITE_ROW == rc ){ - /* call the supplied callback with the result row data */ - if( xCallback(pArg, nCol, azVals, azCols, aiTypes) ){ - rc = SQLITE_ABORT; - }else{ - rc = sqlite3_step(pStmt); - } - } - } while( SQLITE_ROW == rc ); - sqlite3_free(pData); - } - }else{ - do{ - rc = sqlite3_step(pStmt); - } while( rc == SQLITE_ROW ); - } - } - + exec_prepared_stmt(pArg, pStmt, xCallback); explain_data_delete(pArg); /* print usage stats if stats on */ @@ -2085,7 +2143,7 @@ static char zHelp[] = " If TABLE specified, only dump tables matching\n" " LIKE pattern TABLE.\n" ".echo on|off Turn command echo on or off\n" - ".eqp on|off Enable or disable automatic EXPLAIN QUERY PLAN\n" + ".eqp on|off|full Enable or disable automatic EXPLAIN QUERY PLAN\n" ".exit Exit this program\n" ".explain ?on|off|auto? Turn EXPLAIN output mode on or off or to automatic\n" ".fullschema ?--indent? Show schema and the content of sqlite_stat tables\n" @@ -3255,9 +3313,13 @@ static int do_meta_command(char *zLine, ShellState *p){ if( c=='e' && strncmp(azArg[0], "eqp", n)==0 ){ if( nArg==2 ){ - p->autoEQP = booleanValue(azArg[1]); + if( strcmp(azArg[1],"full")==0 ){ + p->autoEQP = 2; + }else{ + p->autoEQP = booleanValue(azArg[1]); + } }else{ - raw_printf(stderr, "Usage: .eqp on|off\n"); + raw_printf(stderr, "Usage: .eqp on|off|full\n"); rc = 1; } }else @@ -4018,7 +4080,6 @@ static int do_meta_command(char *zLine, ShellState *p){ #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE) if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){ - extern int sqlite3SelectTrace; sqlite3SelectTrace = integerValue(azArg[1]); }else #endif @@ -4278,17 +4339,18 @@ static int do_meta_command(char *zLine, ShellState *p){ }else if( c=='s' && strncmp(azArg[0], "show", n)==0 ){ + static const char *azBool[] = { "off", "on", "full", "unk" }; int i; if( nArg!=1 ){ raw_printf(stderr, "Usage: .show\n"); rc = 1; goto meta_command_exit; } - utf8_printf(p->out, "%12.12s: %s\n","echo", p->echoOn ? "on" : "off"); - utf8_printf(p->out, "%12.12s: %s\n","eqp", p->autoEQP ? "on" : "off"); + utf8_printf(p->out, "%12.12s: %s\n","echo", azBool[p->echoOn!=0]); + utf8_printf(p->out, "%12.12s: %s\n","eqp", azBool[p->autoEQP&3]); utf8_printf(p->out, "%12.12s: %s\n","explain", p->mode==MODE_Explain ? "on" : p->autoExplain ? "auto" : "off"); - utf8_printf(p->out,"%12.12s: %s\n","headers", p->showHeader ? "on" : "off"); + utf8_printf(p->out,"%12.12s: %s\n","headers", azBool[p->showHeader!=0]); utf8_printf(p->out, "%12.12s: %s\n","mode", modeDescr[p->mode]); utf8_printf(p->out, "%12.12s: ", "nullvalue"); output_c_string(p->out, p->nullValue); @@ -4301,7 +4363,7 @@ static int do_meta_command(char *zLine, ShellState *p){ utf8_printf(p->out,"%12.12s: ", "rowseparator"); output_c_string(p->out, p->rowSeparator); raw_printf(p->out, "\n"); - utf8_printf(p->out, "%12.12s: %s\n","stats", p->statsOn ? "on" : "off"); + utf8_printf(p->out, "%12.12s: %s\n","stats", azBool[p->statsOn!=0]); utf8_printf(p->out, "%12.12s: ", "width"); for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) { raw_printf(p->out, "%d ", p->colWidth[i]); @@ -4716,7 +4778,6 @@ static int do_meta_command(char *zLine, ShellState *p){ #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE) if( c=='w' && strncmp(azArg[0], "wheretrace", n)==0 ){ - extern int sqlite3WhereTrace; sqlite3WhereTrace = nArg>=2 ? booleanValue(azArg[1]) : 0xff; }else #endif @@ -5384,6 +5445,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ data.echoOn = 1; }else if( strcmp(z,"-eqp")==0 ){ data.autoEQP = 1; + }else if( strcmp(z,"-eqpfull")==0 ){ + data.autoEQP = 2; }else if( strcmp(z,"-stats")==0 ){ data.statsOn = 1; }else if( strcmp(z,"-scanstats")==0 ){ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index f9fab8e321..fe7203b8e1 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1350,6 +1350,11 @@ struct sqlite3 { /* ** Possible values for the sqlite3.flags. +** +** Value constraints (enforced via assert()): +** SQLITE_FullFSync == PAGER_FULLFSYNC +** SQLITE_CkptFullFSync == PAGER_CKPT_FULLFSYNC +** SQLITE_CacheSpill == PAGER_CACHE_SPILL */ #define SQLITE_VdbeTrace 0x00000001 /* True to trace VDBE execution */ #define SQLITE_InternChanges 0x00000002 /* Uncommitted Hash table changes */ @@ -1484,6 +1489,13 @@ struct FuncDestructor { ** values must correspond to OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG. And ** SQLITE_FUNC_CONSTANT must be the same as SQLITE_DETERMINISTIC. There ** are assert() statements in the code to verify this. +** +** Value constraints (enforced via assert()): +** SQLITE_FUNC_MINMAX == NC_MinMaxAgg == SF_MinMaxAgg +** SQLITE_FUNC_LENGTH == OPFLAG_LENGTHARG +** SQLITE_FUNC_TYPEOF == OPFLAG_TYPEOFARG +** SQLITE_FUNC_CONSTANT == SQLITE_DETERMINISTIC from the API +** SQLITE_FUNC_ENCMASK depends on SQLITE_UTF* macros in the API */ #define SQLITE_FUNC_ENCMASK 0x0003 /* SQLITE_UTF8, SQLITE_UTF16BE or UTF16LE */ #define SQLITE_FUNC_LIKE 0x0004 /* Candidate for the LIKE optimization */ @@ -2483,6 +2495,9 @@ struct SrcList { /* ** Flags appropriate for the wctrlFlags parameter of sqlite3WhereBegin() ** and the WhereInfo.wctrlFlags member. +** +** Value constraints (enforced via assert()): +** WHERE_USE_LIMIT == SF_FixedLimit */ #define WHERE_ORDERBY_NORMAL 0x0000 /* No-op */ #define WHERE_ORDERBY_MIN 0x0001 /* ORDER BY processing for min() func */ @@ -2543,15 +2558,16 @@ struct NameContext { /* ** Allowed values for the NameContext, ncFlags field. ** -** Note: NC_MinMaxAgg must have the same value as SF_MinMaxAgg and -** SQLITE_FUNC_MINMAX. +** Value constraints (all checked via assert()): +** NC_HasAgg == SF_HasAgg +** NC_MinMaxAgg == SF_MinMaxAgg == SQLITE_FUNC_MINMAX ** */ #define NC_AllowAgg 0x0001 /* Aggregate functions are allowed here */ -#define NC_HasAgg 0x0002 /* One or more aggregate functions seen */ +#define NC_PartIdx 0x0002 /* True if resolving a partial index WHERE */ #define NC_IsCheck 0x0004 /* True if resolving names in a CHECK constraint */ #define NC_InAggFunc 0x0008 /* True if analyzing arguments to an agg func */ -#define NC_PartIdx 0x0010 /* True if resolving a partial index WHERE */ +#define NC_HasAgg 0x0010 /* One or more aggregate functions seen */ #define NC_IdxExpr 0x0020 /* True if resolving columns of CREATE INDEX */ #define NC_MinMaxAgg 0x1000 /* min/max aggregates seen. See note above */ @@ -2600,24 +2616,30 @@ struct Select { /* ** Allowed values for Select.selFlags. The "SF" prefix stands for ** "Select Flag". +** +** Value constraints (all checked via assert()) +** SF_HasAgg == NC_HasAgg +** SF_MinMaxAgg == NC_MinMaxAgg == SQLITE_FUNC_MINMAX +** SF_FixedLimit == WHERE_USE_LIMIT */ #define SF_Distinct 0x00001 /* Output should be DISTINCT */ #define SF_All 0x00002 /* Includes the ALL keyword */ #define SF_Resolved 0x00004 /* Identifiers have been resolved */ -#define SF_Aggregate 0x00008 /* Contains aggregate functions */ -#define SF_UsesEphemeral 0x00010 /* Uses the OpenEphemeral opcode */ -#define SF_Expanded 0x00020 /* sqlite3SelectExpand() called on this */ -#define SF_HasTypeInfo 0x00040 /* FROM subqueries have Table metadata */ -#define SF_Compound 0x00080 /* Part of a compound query */ -#define SF_Values 0x00100 /* Synthesized from VALUES clause */ -#define SF_MultiValue 0x00200 /* Single VALUES term with multiple rows */ -#define SF_NestedFrom 0x00400 /* Part of a parenthesized FROM clause */ -#define SF_MaybeConvert 0x00800 /* Need convertCompoundSelectToSubquery() */ +#define SF_Aggregate 0x00008 /* Contains agg functions or a GROUP BY */ +#define SF_HasAgg 0x00010 /* Contains aggregate functions */ +#define SF_UsesEphemeral 0x00020 /* Uses the OpenEphemeral opcode */ +#define SF_Expanded 0x00040 /* sqlite3SelectExpand() called on this */ +#define SF_HasTypeInfo 0x00080 /* FROM subqueries have Table metadata */ +#define SF_Compound 0x00100 /* Part of a compound query */ +#define SF_Values 0x00200 /* Synthesized from VALUES clause */ +#define SF_MultiValue 0x00400 /* Single VALUES term with multiple rows */ +#define SF_NestedFrom 0x00800 /* Part of a parenthesized FROM clause */ #define SF_MinMaxAgg 0x01000 /* Aggregate containing min() or max() */ #define SF_Recursive 0x02000 /* The recursive part of a recursive CTE */ #define SF_FixedLimit 0x04000 /* nSelectRow set by a constant LIMIT */ -#define SF_Converted 0x08000 /* By convertCompoundSelectToSubquery() */ -#define SF_IncludeHidden 0x10000 /* Include hidden columns in output */ +#define SF_MaybeConvert 0x08000 /* Need convertCompoundSelectToSubquery() */ +#define SF_Converted 0x10000 /* By convertCompoundSelectToSubquery() */ +#define SF_IncludeHidden 0x20000 /* Include hidden columns in output */ /* @@ -2928,6 +2950,15 @@ struct AuthContext { /* ** Bitfield flags for P5 value in various opcodes. +** +** Value constraints (enforced via assert()): +** OPFLAG_LENGTHARG == SQLITE_FUNC_LENGTH +** OPFLAG_TYPEOFARG == SQLITE_FUNC_TYPEOF +** OPFLAG_BULKCSR == BTREE_BULKLOAD +** OPFLAG_SEEKEQ == BTREE_SEEK_EQ +** OPFLAG_FORDELETE == BTREE_FORDELETE +** OPFLAG_SAVEPOSITION == BTREE_SAVEPOSITION +** OPFLAG_AUXDELETE == BTREE_AUXDELETE */ #define OPFLAG_NCHANGE 0x01 /* OP_Insert: Set to update db->nChange */ /* Also used in P2 (not P5) of OP_Delete */ diff --git a/src/test_devsym.c b/src/test_devsym.c index 21f0f684d8..5fd0935846 100644 --- a/src/test_devsym.c +++ b/src/test_devsym.c @@ -133,7 +133,8 @@ struct DevsymGlobal g = {0, 0, 512}; */ static int devsymClose(sqlite3_file *pFile){ devsym_file *p = (devsym_file *)pFile; - return sqlite3OsClose(p->pReal); + sqlite3OsClose(p->pReal); + return SQLITE_OK; } /* diff --git a/src/test_journal.c b/src/test_journal.c index 6e320b7abb..84c80546a6 100644 --- a/src/test_journal.c +++ b/src/test_journal.c @@ -256,7 +256,8 @@ static int jtClose(sqlite3_file *pFile){ *pp = p->pNext; } leaveJtMutex(); - return sqlite3OsClose(p->pReal); + sqlite3OsClose(p->pReal); + return SQLITE_OK; } /* diff --git a/src/test_syscall.c b/src/test_syscall.c index 0dac2e897e..f9abc1e46d 100644 --- a/src/test_syscall.c +++ b/src/test_syscall.c @@ -108,10 +108,13 @@ static int ts_ftruncate(int fd, off_t n); static int ts_fcntl(int fd, int cmd, ... ); static int ts_read(int fd, void *aBuf, size_t nBuf); static int ts_pread(int fd, void *aBuf, size_t nBuf, off_t off); -static int ts_pread64(int fd, void *aBuf, size_t nBuf, off_t off); +/* Note: pread64() and pwrite64() actually use off64_t as the type on their +** last parameter. But that datatype is not defined on many systems +** (ex: Mac, OpenBSD). So substitute a likely equivalent: sqlite3_uint64 */ +static int ts_pread64(int fd, void *aBuf, size_t nBuf, sqlite3_uint64 off); static int ts_write(int fd, const void *aBuf, size_t nBuf); static int ts_pwrite(int fd, const void *aBuf, size_t nBuf, off_t off); -static int ts_pwrite64(int fd, const void *aBuf, size_t nBuf, off_t off); +static int ts_pwrite64(int fd, const void *aBuf, size_t nBuf, sqlite3_uint64 off); static int ts_fchmod(int fd, mode_t mode); static int ts_fallocate(int fd, off_t off, off_t len); static void *ts_mmap(void *, size_t, int, int, int, off_t); @@ -155,11 +158,11 @@ struct TestSyscallArray { #define orig_fcntl ((int(*)(int,int,...))aSyscall[7].xOrig) #define orig_read ((ssize_t(*)(int,void*,size_t))aSyscall[8].xOrig) #define orig_pread ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[9].xOrig) -#define orig_pread64 ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[10].xOrig) +#define orig_pread64 ((ssize_t(*)(int,void*,size_t,sqlite3_uint64))aSyscall[10].xOrig) #define orig_write ((ssize_t(*)(int,const void*,size_t))aSyscall[11].xOrig) #define orig_pwrite ((ssize_t(*)(int,const void*,size_t,off_t))\ aSyscall[12].xOrig) -#define orig_pwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\ +#define orig_pwrite64 ((ssize_t(*)(int,const void*,size_t,sqlite3_uint64))\ aSyscall[13].xOrig) #define orig_fchmod ((int(*)(int,mode_t))aSyscall[14].xOrig) #define orig_fallocate ((int(*)(int,off_t,off_t))aSyscall[15].xOrig) @@ -326,7 +329,7 @@ static int ts_pread(int fd, void *aBuf, size_t nBuf, off_t off){ /* ** A wrapper around pread64(). */ -static int ts_pread64(int fd, void *aBuf, size_t nBuf, off_t off){ +static int ts_pread64(int fd, void *aBuf, size_t nBuf, sqlite3_uint64 off){ if( tsIsFailErrno("pread64") ){ return -1; } @@ -357,7 +360,7 @@ static int ts_pwrite(int fd, const void *aBuf, size_t nBuf, off_t off){ /* ** A wrapper around pwrite64(). */ -static int ts_pwrite64(int fd, const void *aBuf, size_t nBuf, off_t off){ +static int ts_pwrite64(int fd, const void *aBuf, size_t nBuf, sqlite3_uint64 off){ if( tsIsFailErrno("pwrite64") ){ return -1; } diff --git a/src/test_vfs.c b/src/test_vfs.c index a8c6ae7bf5..b476a42cb4 100644 --- a/src/test_vfs.c +++ b/src/test_vfs.c @@ -306,7 +306,6 @@ static void tvfsExecTcl( ** Close an tvfs-file. */ static int tvfsClose(sqlite3_file *pFile){ - int rc; TestvfsFile *pTestfile = (TestvfsFile *)pFile; TestvfsFd *pFd = pTestfile->pFd; Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; @@ -324,10 +323,10 @@ static int tvfsClose(sqlite3_file *pFile){ if( pFile->pMethods ){ ckfree((char *)pFile->pMethods); } - rc = sqlite3OsClose(pFd->pReal); + sqlite3OsClose(pFd->pReal); ckfree((char *)pFd); pTestfile->pFd = 0; - return rc; + return SQLITE_OK; } /* diff --git a/src/vdbesort.c b/src/vdbesort.c index 5913cda6d0..7d5146cf0b 100644 --- a/src/vdbesort.c +++ b/src/vdbesort.c @@ -931,7 +931,6 @@ int sqlite3VdbeSorterInit( ){ int pgsz; /* Page size of main database */ int i; /* Used to iterate through aTask[] */ - int mxCache; /* Cache size */ VdbeSorter *pSorter; /* The new sorter */ KeyInfo *pKeyInfo; /* Copy of pCsr->pKeyInfo with db==0 */ int szKeyInfo; /* Size of pCsr->pKeyInfo in bytes */ @@ -988,11 +987,20 @@ int sqlite3VdbeSorterInit( } if( !sqlite3TempInMemory(db) ){ + i64 mxCache; /* Cache size in bytes*/ u32 szPma = sqlite3GlobalConfig.szPma; pSorter->mnPmaSize = szPma * pgsz; + mxCache = db->aDb[0].pSchema->cache_size; - if( mxCache<(int)szPma ) mxCache = (int)szPma; - pSorter->mxPmaSize = MIN((i64)mxCache*pgsz, SQLITE_MAX_PMASZ); + if( mxCache<0 ){ + /* A negative cache-size value C indicates that the cache is abs(C) + ** KiB in size. */ + mxCache = mxCache * -1024; + }else{ + mxCache = mxCache * pgsz; + } + mxCache = MIN(mxCache, SQLITE_MAX_PMASZ); + pSorter->mxPmaSize = MAX(pSorter->mnPmaSize, (int)mxCache); /* EVIDENCE-OF: R-26747-61719 When the application provides any amount of ** scratch memory using SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary diff --git a/src/where.c b/src/where.c index b33e062a6d..ca810a3b16 100644 --- a/src/where.c +++ b/src/where.c @@ -3881,9 +3881,9 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ && nRowEst ){ Bitmask notUsed; - int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pResultSet, pFrom, + int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pDistinctSet, pFrom, WHERE_DISTINCTBY, nLoop-1, pFrom->aLoop[nLoop-1], ¬Used); - if( rc==pWInfo->pResultSet->nExpr ){ + if( rc==pWInfo->pDistinctSet->nExpr ){ pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; } } @@ -4098,14 +4098,14 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ ** used. */ WhereInfo *sqlite3WhereBegin( - Parse *pParse, /* The parser context */ - SrcList *pTabList, /* FROM clause: A list of all tables to be scanned */ - Expr *pWhere, /* The WHERE clause */ - ExprList *pOrderBy, /* An ORDER BY (or GROUP BY) clause, or NULL */ - ExprList *pResultSet, /* Result set of the query */ - u16 wctrlFlags, /* One of the WHERE_* flags defined in sqliteInt.h */ - int iAuxArg /* If WHERE_ONETABLE_ONLY is set, index cursor number, - ** If WHERE_USE_LIMIT, then the limit amount */ + Parse *pParse, /* The parser context */ + SrcList *pTabList, /* FROM clause: A list of all tables to be scanned */ + Expr *pWhere, /* The WHERE clause */ + ExprList *pOrderBy, /* An ORDER BY (or GROUP BY) clause, or NULL */ + ExprList *pDistinctSet, /* Try not to output two rows that duplicate these */ + u16 wctrlFlags, /* The WHERE_* flags defined in sqliteInt.h */ + int iAuxArg /* If WHERE_ONETABLE_ONLY is set, index cursor number + ** If WHERE_USE_LIMIT, then the limit amount */ ){ int nByteWInfo; /* Num. bytes allocated for WhereInfo struct */ int nTabList; /* Number of elements in pTabList */ @@ -4180,7 +4180,7 @@ WhereInfo *sqlite3WhereBegin( pWInfo->pParse = pParse; pWInfo->pTabList = pTabList; pWInfo->pOrderBy = pOrderBy; - pWInfo->pResultSet = pResultSet; + pWInfo->pDistinctSet = pDistinctSet; pWInfo->iBreak = pWInfo->iContinue = sqlite3VdbeMakeLabel(v); pWInfo->wctrlFlags = wctrlFlags; pWInfo->iLimit = iAuxArg; @@ -4253,13 +4253,13 @@ WhereInfo *sqlite3WhereBegin( if( db->mallocFailed ) goto whereBeginError; if( wctrlFlags & WHERE_WANT_DISTINCT ){ - if( isDistinctRedundant(pParse, pTabList, &pWInfo->sWC, pResultSet) ){ + if( isDistinctRedundant(pParse, pTabList, &pWInfo->sWC, pDistinctSet) ){ /* The DISTINCT marking is pointless. Ignore it. */ pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; }else if( pOrderBy==0 ){ /* Try to ORDER BY the result set to make distinct processing easier */ pWInfo->wctrlFlags |= WHERE_DISTINCTBY; - pWInfo->pOrderBy = pResultSet; + pWInfo->pOrderBy = pDistinctSet; } } @@ -4338,10 +4338,10 @@ WhereInfo *sqlite3WhereBegin( #endif /* Attempt to omit tables from the join that do not effect the result */ if( pWInfo->nLevel>=2 - && pResultSet!=0 + && pDistinctSet!=0 && OptimizationEnabled(db, SQLITE_OmitNoopJoin) ){ - Bitmask tabUsed = sqlite3WhereExprListUsage(pMaskSet, pResultSet); + Bitmask tabUsed = sqlite3WhereExprListUsage(pMaskSet, pDistinctSet); if( sWLB.pOrderBy ){ tabUsed |= sqlite3WhereExprListUsage(pMaskSet, sWLB.pOrderBy); } diff --git a/src/whereInt.h b/src/whereInt.h index eb6ca326f5..252905aa5a 100644 --- a/src/whereInt.h +++ b/src/whereInt.h @@ -408,7 +408,7 @@ struct WhereInfo { Parse *pParse; /* Parsing and code generating context */ SrcList *pTabList; /* List of tables in the join */ ExprList *pOrderBy; /* The ORDER BY clause or NULL */ - ExprList *pResultSet; /* Result set. DISTINCT operates on these */ + ExprList *pDistinctSet; /* DISTINCT over all these values */ WhereLoop *pLoops; /* List of all WhereLoop objects */ Bitmask revMask; /* Mask of ORDER BY terms that need reversing */ LogEst nRowOut; /* Estimated number of output rows */ @@ -492,6 +492,14 @@ void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereClause*); ** operators that are of interest to the query planner. An ** OR-ed combination of these values can be used when searching for ** particular WhereTerms within a WhereClause. +** +** Value constraints: +** WO_EQ == SQLITE_INDEX_CONSTRAINT_EQ +** WO_LT == SQLITE_INDEX_CONSTRAINT_LT +** WO_LE == SQLITE_INDEX_CONSTRAINT_LE +** WO_GT == SQLITE_INDEX_CONSTRAINT_GT +** WO_GE == SQLITE_INDEX_CONSTRAINT_GE +** WO_MATCH == SQLITE_INDEX_CONSTRAINT_MATCH */ #define WO_IN 0x0001 #define WO_EQ 0x0002 diff --git a/test/sort5.test b/test/sort5.test index 5b1292bb48..9fb2dff281 100644 --- a/test/sort5.test +++ b/test/sort5.test @@ -41,4 +41,76 @@ do_execsql_test 1.2 { db close tvfs delete + +#------------------------------------------------------------------------- +# Test that the PMA size is determined correctly. The PMA size should be +# roughly the same amount of memory allocated to the main pager cache, or +# 250 pages if this is larger. +# +testvfs tvfs +tvfs script tv_callback +tvfs filter {xOpen xWrite} + +proc tv_callback {method args} { + global iTemp + global F + switch $method { + xOpen { + if {[lindex $args 0]==""} { return "temp[incr iTemp]" } + return "SQLITE_OK" + } + + xWrite { + foreach {filename id off amt} $args {} + if {[info exists F($id)]==0 || $F($id)<($off + $amt)} { + set F($id) [expr $off+$amt] + } + } + } +} + +catch { db close } +forcedelete test.db +sqlite3 db test.db -vfs tvfs +execsql { CREATE TABLE t1(x) } + +# Each iteration of the following loop attempts to sort 10001 records +# each a bit over 100 bytes in size. In total a little more than 1MiB +# of data. +# +breakpoint +foreach {tn pgsz cachesz bTemp} { + 2 1024 1000 1 + + 1 4096 1000 0 + 2 1024 1000 1 + + 3 4096 -1000 1 + 4 1024 -1000 1 + + 5 4096 -9000 0 + 6 1024 -9000 0 +} { + do_execsql_test 2.$tn.0 " + PRAGMA page_size = $pgsz; + VACUUM; + PRAGMA cache_size = $cachesz; + " + + do_test 2.$tn.1 { + set ::iTemp 0 + catch { array unset F } + execsql { + WITH x(i, j) AS ( + SELECT 1, randomblob(100) + UNION ALL + SELECT i+1, randomblob(100) FROM x WHERE i<10000 + ) + SELECT * FROM x ORDER BY j; + } + expr {[array names F]!=""} + } $bTemp +} + finish_test +