Compare commits

..

6 Commits

Author SHA1 Message Date
drh 818d5bcf28 Remove redundant #ifdef accidentally inserted into mkkeywordhash.c
FossilOrigin-Name: b08f3b74495e125f92c8968472fc8028c73d8df5400195df3081e3d8df8bd985
2024-08-26 14:20:20 +00:00
drh 8941cb4817 Add the AGGREGATE clause to the pipeline.
FossilOrigin-Name: 16d32676e2e98a7710787de16850c328e7519e893f81ed56f6155a8fa9cbc3a4
2024-08-26 14:06:08 +00:00
drh 1082e86417 Working better now.
FossilOrigin-Name: 4bdcc18d2cf4d11a7ca81117f6f8932fc8d280780d2c1e612189b2f5359cc778
2024-08-26 13:20:38 +00:00
drh 7267c510ac Reduce rules added to the grammar. Kinda works, but there are still bugs.
FossilOrigin-Name: 3c7a5cc6d0d186e68a5885299f7474ad2e31b839af404a649dbc8f5b8f1d0a62
2024-08-26 12:26:26 +00:00
drh f53ed4e68e Another version of the parser with a slightly richer syntax. The ghastly
pipe operator is now optional, but is never required.  Pipelines cannot
be initiated from an arbitrary SELECT unless the arbitrary SELECT is a subquery
on the initial FROM.

FossilOrigin-Name: 8781d7352b926129027f73d1fe21df78fcb6d21ab3caeefe0f829437c7c1250b
2024-08-26 02:53:31 +00:00
drh 7210e4c5b4 Proof-of-concept grammar rules to parse Google-style "pipe" syntax for SQL,
without the ghastly "|>" operator.  The grammar rules are not connected to
working code.  They just parse the syntax.  Pipelines that begin with an
ordinary SELECT statement must have the keyword "INTO" (rather than the
"|>" operator) separating the SELECT from the start of the pipeline, to
avoid syntactic and semantic ambiguity.

FossilOrigin-Name: 2c4bae3e68eea14a5edbc753a7a2d764924c95060aff95fa1d2141c11fa77fed
2024-08-26 00:15:35 +00:00
15 changed files with 349 additions and 472 deletions
+2 -82
View File
@@ -595,86 +595,6 @@ oPutbUtf8(const char *cBuf, int nAccept){
# endif
}
/*
** Flush the given output stream. Return non-zero for success, else 0.
*/
#if !defined(SQLITE_CIO_NO_FLUSH) && !defined(SQLITE_CIO_NO_SETMODE)
SQLITE_INTERNAL_LINKAGE int
fFlushBuffer(FILE *pfOut){
# if CIO_WIN_WC_XLATE && !defined(SHELL_OMIT_FIO_DUPE)
return FlushFileBuffers(handleOfFile(pfOut))? 1 : 0;
# else
return fflush(pfOut);
# endif
}
#endif
#if CIO_WIN_WC_XLATE \
&& !defined(SHELL_OMIT_FIO_DUPE) \
&& defined(SQLITE_USE_ONLY_WIN32)
static struct FileAltIds {
int fd;
HANDLE fh;
} altIdsOfFile(FILE *pf){
struct FileAltIds rv = { _fileno(pf) };
union { intptr_t osfh; HANDLE fh; } fid = {
(rv.fd>=0)? _get_osfhandle(rv.fd) : (intptr_t)INVALID_HANDLE_VALUE
};
rv.fh = fid.fh;
return rv;
}
SQLITE_INTERNAL_LINKAGE size_t
cfWrite(const void *buf, size_t osz, size_t ocnt, FILE *pf){
size_t rv = 0;
struct FileAltIds fai = altIdsOfFile(pf);
int fmode = _setmode(fai.fd, _O_BINARY);
_setmode(fai.fd, fmode);
while( rv < ocnt ){
size_t nbo = osz;
while( nbo > 0 ){
DWORD dwno = (nbo>(1L<<24))? 1L<<24 : (DWORD)nbo;
BOOL wrc = TRUE;
BOOL genCR = (fmode & _O_TEXT)!=0;
if( genCR ){
const char *pnl = (const char*)memchr(buf, '\n', nbo);
if( pnl ) nbo = pnl - (const char*)buf;
else genCR = 0;
}
if( dwno>0 ) wrc = WriteFile(fai.fh, buf, dwno, 0,0);
if( genCR && wrc ){
wrc = WriteFile(fai.fh, "\r\n", 2, 0,0);
++dwno; /* Skip over the LF */
}
if( !wrc ) return rv;
buf = (const char*)buf + dwno;
nbo += dwno;
}
++rv;
}
return rv;
}
SQLITE_INTERNAL_LINKAGE char *
cfGets(char *cBuf, int n, FILE *pf){
int nci = 0;
struct FileAltIds fai = altIdsOfFile(pf);
int fmode = _setmode(fai.fd, _O_BINARY);
BOOL eatCR = (fmode & _O_TEXT)!=0;
_setmode(fai.fd, fmode);
while( nci < n-1 ){
DWORD nr;
if( !ReadFile(fai.fh, cBuf+nci, 1, &nr, 0) || nr==0 ) break;
if( nr>0 && (!eatCR || cBuf[nci]!='\r') ) nci += nr;
}
if( nci < n ) cBuf[nci] = 0;
return (nci>0)? cBuf : 0;
}
# else
# define cfWrite(b,os,no,f) fwrite(b,os,no,f)
# define cfGets(b,n,f) fgets(b,n,f)
# endif
# ifdef CONSIO_EPUTB
SQLITE_INTERNAL_LINKAGE int
ePutbUtf8(const char *cBuf, int nAccept){
@@ -686,7 +606,7 @@ ePutbUtf8(const char *cBuf, int nAccept){
return conZstrEmit(ppst, cBuf, nAccept);
}else {
# endif
return (int)cfWrite(cBuf, 1, nAccept, pfErr);
return (int)fwrite(cBuf, 1, nAccept, pfErr);
# if CIO_WIN_WC_XLATE
}
# endif
@@ -752,7 +672,7 @@ SQLITE_INTERNAL_LINKAGE char* fGetsUtf8(char *cBuf, int ncMax, FILE *pfIn){
# endif
}else{
# endif
return cfGets(cBuf, ncMax, pfIn);
return fgets(cBuf, ncMax, pfIn);
# if CIO_WIN_WC_XLATE
}
# endif
+4 -11
View File
@@ -176,19 +176,12 @@ SQLITE_INTERNAL_LINKAGE int
ePutbUtf8(const char *cBuf, int nAccept);
#endif
/*
** Flush the given output stream. Return non-zero for success, else 0.
*/
#if !defined(SQLITE_CIO_NO_FLUSH) && !defined(SQLITE_CIO_NO_SETMODE)
SQLITE_INTERNAL_LINKAGE int
fFlushBuffer(FILE *pfOut);
#endif
/*
** Collect input like fgets(...) with special provisions for input
** from the console on such platforms as require same. Newline
** translation may be done as set by set{Binary,Text}Mode().
** As a convenience, pfIn==NULL is treated as stdin.
** from the console on platforms that require same. Defers to the
** C library fgets() when input is not from the console. Newline
** translation may be done as set by set{Binary,Text}Mode(). As a
** convenience, pfIn==NULL is treated as stdin.
*/
SQLITE_INTERNAL_LINKAGE char* fGetsUtf8(char *cBuf, int ncMax, FILE *pfIn);
/* Like fGetsUtf8 except stream is always the designated input. */
+6 -7
View File
@@ -493,19 +493,18 @@ struct Fts5ExtensionApi {
**
** FTS5_TOKENIZER
**
** There is also an fts5_tokenizer object. This is an older, deprecated,
** version of fts5_tokenizer_v2. It is similar except that:
** There is also an fts5_tokenizer object. This is an older version of
** fts5_tokenizer_v2. It is similar except that:
**
** <ul>
** <li> There is no "iVersion" field, and
** <li> The xTokenize() method does not take a locale argument.
** </ul>
**
** Legacy fts5_tokenizer tokenizers must be registered using the
** legacy xCreateTokenizer() function, instead of xCreateTokenizer_v2().
**
** Tokenizer implementations registered using either API may be retrieved
** using both xFindTokenizer() and xFindTokenizer_v2().
** fts5_tokenizer tokenizers should be registered with the xCreateTokenizer()
** function, instead of xCreateTokenizer_v2(). Tokenizers implementations
** registered using either API may be retrieved using both xFindTokenizer()
** and xFindTokenizer_v2().
**
** SYNONYM SUPPORT
**
+12 -13
View File
@@ -3267,9 +3267,7 @@ static int fts5NewTokenizerModule(
*/
typedef struct Fts5VtoVTokenizer Fts5VtoVTokenizer;
struct Fts5VtoVTokenizer {
int bV2Native; /* True if v2 native tokenizer */
fts5_tokenizer x1; /* Tokenizer functions */
fts5_tokenizer_v2 x2; /* V2 tokenizer functions */
Fts5TokenizerModule *pMod;
Fts5Tokenizer *pReal;
};
@@ -3289,9 +3287,7 @@ static int fts5VtoVCreate(
pNew = (Fts5VtoVTokenizer*)sqlite3Fts5MallocZero(&rc, sizeof(*pNew));
if( rc==SQLITE_OK ){
pNew->x1 = pMod->x1;
pNew->x2 = pMod->x2;
pNew->bV2Native = pMod->bV2Native;
pNew->pMod = pMod;
if( pMod->bV2Native ){
rc = pMod->x2.xCreate(pMod->pUserData, azArg, nArg, &pNew->pReal);
}else{
@@ -3313,10 +3309,11 @@ static int fts5VtoVCreate(
static void fts5VtoVDelete(Fts5Tokenizer *pTok){
Fts5VtoVTokenizer *p = (Fts5VtoVTokenizer*)pTok;
if( p ){
if( p->bV2Native ){
p->x2.xDelete(p->pReal);
Fts5TokenizerModule *pMod = p->pMod;
if( pMod->bV2Native ){
pMod->x2.xDelete(p->pReal);
}else{
p->x1.xDelete(p->pReal);
pMod->x1.xDelete(p->pReal);
}
sqlite3_free(p);
}
@@ -3334,8 +3331,9 @@ static int fts5V1toV2Tokenize(
int (*xToken)(void*, int, const char*, int, int, int)
){
Fts5VtoVTokenizer *p = (Fts5VtoVTokenizer*)pTok;
assert( p->bV2Native );
return p->x2.xTokenize(p->pReal, pCtx, flags, pText, nText, 0, 0, xToken);
Fts5TokenizerModule *pMod = p->pMod;
assert( pMod->bV2Native );
return pMod->x2.xTokenize(p->pReal, pCtx, flags, pText, nText, 0, 0, xToken);
}
/*
@@ -3350,9 +3348,10 @@ static int fts5V2toV1Tokenize(
int (*xToken)(void*, int, const char*, int, int, int)
){
Fts5VtoVTokenizer *p = (Fts5VtoVTokenizer*)pTok;
assert( p->bV2Native==0 );
Fts5TokenizerModule *pMod = p->pMod;
assert( pMod->bV2Native==0 );
UNUSED_PARAM2(pLocale,nLocale);
return p->x1.xTokenize(p->pReal, pCtx, flags, pText, nText, xToken);
return pMod->x1.xTokenize(p->pReal, pCtx, flags, pText, nText, xToken);
}
/*
+15 -96
View File
@@ -96,14 +96,14 @@ static int SQLITE_TCLAPI f5tDbAndApi(
rc = sqlite3_prepare_v2(db, "SELECT fts5(?1)", -1, &pStmt, 0);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), (char*)0);
Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), 0);
return TCL_ERROR;
}
sqlite3_bind_pointer(pStmt, 1, (void*)&pApi, "fts5_api_ptr", 0);
sqlite3_step(pStmt);
if( sqlite3_finalize(pStmt)!=SQLITE_OK ){
Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), (char*)0);
Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), 0);
return TCL_ERROR;
}
@@ -392,7 +392,7 @@ static int SQLITE_TCLAPI xF5tApi(
CASE(12, "xSetAuxdata") {
F5tAuxData *pData = (F5tAuxData*)sqlite3_malloc(sizeof(F5tAuxData));
if( pData==0 ){
Tcl_AppendResult(interp, "out of memory", (char*)0);
Tcl_AppendResult(interp, "out of memory", 0);
return TCL_ERROR;
}
pData->pObj = objv[2];
@@ -452,7 +452,7 @@ static int SQLITE_TCLAPI xF5tApi(
rc = p->pApi->xPhraseFirst(p->pFts, iPhrase, &iter, &iCol, &iOff);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, sqlite3ErrName(rc), (char*)0);
Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
return TCL_ERROR;
}
for( ;iCol>=0; p->pApi->xPhraseNext(p->pFts, &iter, &iCol, &iOff) ){
@@ -683,7 +683,7 @@ static int SQLITE_TCLAPI f5tCreateFunction(
pApi, zName, (void*)pCtx, xF5tFunction, xF5tDestroy
);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), (char*)0);
Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), 0);
return TCL_ERROR;
}
@@ -750,7 +750,7 @@ static int SQLITE_TCLAPI f5tTokenize(
if( objc==5 ){
char *zOpt = Tcl_GetString(objv[1]);
if( strcmp("-subst", zOpt) ){
Tcl_AppendResult(interp, "unrecognized option: ", zOpt, (char*)0);
Tcl_AppendResult(interp, "unrecognized option: ", zOpt, 0);
return TCL_ERROR;
}
}
@@ -759,7 +759,7 @@ static int SQLITE_TCLAPI f5tTokenize(
return TCL_ERROR;
}
if( nArg==0 ){
Tcl_AppendResult(interp, "no such tokenizer: ", (char*)0);
Tcl_AppendResult(interp, "no such tokenizer: ", 0);
Tcl_Free((void*)azArg);
return TCL_ERROR;
}
@@ -767,13 +767,13 @@ static int SQLITE_TCLAPI f5tTokenize(
rc = pApi->xFindTokenizer(pApi, azArg[0], &pUserdata, &tokenizer);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, "no such tokenizer: ", azArg[0], (char*)0);
Tcl_AppendResult(interp, "no such tokenizer: ", azArg[0], 0);
return TCL_ERROR;
}
rc = tokenizer.xCreate(pUserdata, &azArg[1], (int)(nArg-1), &pTok);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, "error in tokenizer.xCreate()", (char*)0);
Tcl_AppendResult(interp, "error in tokenizer.xCreate()", 0);
return TCL_ERROR;
}
@@ -787,7 +787,7 @@ static int SQLITE_TCLAPI f5tTokenize(
);
tokenizer.xDelete(pTok);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, "error in tokenizer.xTokenize()", (char*)0);
Tcl_AppendResult(interp, "error in tokenizer.xTokenize()", 0);
Tcl_DecrRefCount(pRet);
return TCL_ERROR;
}
@@ -1049,7 +1049,7 @@ static int SQLITE_TCLAPI f5tTokenizerLocale(
if( p->xToken==0 ){
Tcl_AppendResult(interp,
"sqlite3_fts5_locale may only be used by tokenizer callback", (char*)0
"sqlite3_fts5_locale may only be used by tokenizer callback", 0
);
return TCL_ERROR;
}
@@ -1098,7 +1098,7 @@ static int SQLITE_TCLAPI f5tTokenizerReturn(
if( p->xToken==0 ){
Tcl_AppendResult(interp,
"sqlite3_fts5_token may only be used by tokenizer callback", (char*)0
"sqlite3_fts5_token may only be used by tokenizer callback", 0
);
return TCL_ERROR;
}
@@ -1250,7 +1250,7 @@ static int SQLITE_TCLAPI f5tCreateTokenizer(
Tcl_AppendResult(interp, (
bV2 ? "error in fts5_api.xCreateTokenizer_v2()"
: "error in fts5_api.xCreateTokenizer()"
), (char*)0);
), 0);
return TCL_ERROR;
}
@@ -1540,92 +1540,12 @@ static int SQLITE_TCLAPI f5tRegisterOriginText(
Tcl_ResetResult(interp);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), (void*)0);
Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), 0);
return TCL_ERROR;
}
return TCL_OK;
}
/*
** This function is used to DROP an fts5 table. It works even if the data
** structures fts5 stores within the database are corrupt, which sometimes
** prevents a straight "DROP TABLE" command from succeeding.
**
** The first parameter is the database handle to use for the DROP TABLE
** operation. The second is the name of the database to drop the fts5 table
** from (i.e. "main", "temp" or the name of an attached database). The
** third parameter is the name of the fts5 table to drop.
**
** SQLITE_OK is returned if the table is successfully dropped. Or, if an
** error occurs, an SQLite error code.
*/
static int sqlite3_fts5_drop_corrupt_table(
sqlite3 *db, /* Database handle */
const char *zDb, /* Database name ("main", "temp" etc.) */
const char *zTab /* Name of fts5 table to drop */
){
int rc = SQLITE_OK;
int bDef = 0;
rc = sqlite3_db_config(db, SQLITE_DBCONFIG_DEFENSIVE, -1, &bDef);
if( rc==SQLITE_OK ){
char *zScript = sqlite3_mprintf(
"DELETE FROM %Q.'%q_data';"
"DELETE FROM %Q.'%q_config';"
"INSERT INTO %Q.'%q_data' VALUES(10, X'0000000000');"
"INSERT INTO %Q.'%q_config' VALUES('version', 4);"
"DROP TABLE %Q.'%q';",
zDb, zTab, zDb, zTab, zDb, zTab, zDb, zTab, zDb, zTab
);
if( zScript==0 ){
rc = SQLITE_NOMEM;
}else{
if( bDef ) sqlite3_db_config(db, SQLITE_DBCONFIG_DEFENSIVE, 0, 0);
rc = sqlite3_exec(db, zScript, 0, 0, 0);
if( bDef ) sqlite3_db_config(db, SQLITE_DBCONFIG_DEFENSIVE, 1, 0);
sqlite3_free(zScript);
}
}
return rc;
}
/*
** sqlite3_fts5_drop_corrupt_table DB DATABASE TABLE
**
** Description...
*/
static int SQLITE_TCLAPI f5tDropCorruptTable(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
sqlite3 *db = 0;
const char *zDb = 0;
const char *zTab = 0;
int rc = SQLITE_OK;
if( objc!=4 ){
Tcl_WrongNumArgs(interp, 1, objv, "DB DATABASE TABLE");
return TCL_ERROR;
}
if( f5tDbPointer(interp, objv[1], &db) ){
return TCL_ERROR;
}
zDb = Tcl_GetString(objv[2]);
zTab = Tcl_GetString(objv[3]);
rc = sqlite3_fts5_drop_corrupt_table(db, zDb, zTab);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), (void*)0);
return TCL_ERROR;
}
return TCL_OK;
}
/*
** Entry point.
*/
@@ -1644,8 +1564,7 @@ int Fts5tcl_Init(Tcl_Interp *interp){
{ "sqlite3_fts5_token_hash", f5tTokenHash, 0 },
{ "sqlite3_fts5_register_matchinfo", f5tRegisterMatchinfo, 0 },
{ "sqlite3_fts5_register_fts5tokenize", f5tRegisterTok, 0 },
{ "sqlite3_fts5_register_origintext",f5tRegisterOriginText, 0 },
{ "sqlite3_fts5_drop_corrupt_table", f5tDropCorruptTable, 0 }
{ "sqlite3_fts5_register_origintext",f5tRegisterOriginText, 0 }
};
int i;
F5tTokenizerContext *pContext;
-103
View File
@@ -1,103 +0,0 @@
# 2024 Aug 28
#
# 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.
#
#***********************************************************************
#
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5corrupt8
# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
}
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE t1 USING fts5(x);
}
do_execsql_test 1.1 {
UPDATE t1_data SET block='hello world' WHERE id=10
}
db close
sqlite3 db test.db
do_catchsql_test 1.2 {
SELECT * FROM t1
} {1 {vtable constructor failed: t1}}
do_catchsql_test 1.3 {
DROP TABLE t1
} {1 {vtable constructor failed: t1}}
do_test 1.4 {
sqlite3_db_config db DEFENSIVE 0
} {0}
do_test 1.5 {
sqlite3_fts5_drop_corrupt_table db main t1
} {}
do_test 1.6 {
sqlite3_db_config db DEFENSIVE -1
} {0}
do_execsql_test 1.7 {
SELECT * FROM sqlite_schema
}
do_execsql_test 2.0 {
CREATE VIRTUAL TABLE t1 USING fts5(x);
}
do_execsql_test 2.1 {
UPDATE t1_config SET v=555 WHERE k='version'
}
db close
sqlite3 db test.db
do_catchsql_test 2.2 {
SELECT * FROM t1
} {1 {invalid fts5 file format (found 555, expected 4 or 5) - run 'rebuild'}}
do_catchsql_test 2.3 {
DROP TABLE t1
} {1 {invalid fts5 file format (found 555, expected 4 or 5) - run 'rebuild'}}
do_test 2.4 {
sqlite3_fts5_drop_corrupt_table db main t1
} {}
do_execsql_test 2.5 {
SELECT * FROM sqlite_schema
}
do_execsql_test 3.0 {
CREATE VIRTUAL TABLE t1 USING fts5(x);
}
do_execsql_test 3.1 {
DELETE FROM t1_config;
}
db close
sqlite3 db test.db
do_catchsql_test 3.2 {
SELECT * FROM t1
} {1 {invalid fts5 file format (found 0, expected 4 or 5) - run 'rebuild'}}
do_catchsql_test 3.3 {
DROP TABLE t1
} {1 {invalid fts5 file format (found 0, expected 4 or 5) - run 'rebuild'}}
do_test 3.4 {
sqlite3_db_config db DEFENSIVE 1
} {1}
do_test 3.5 {
sqlite3_fts5_drop_corrupt_table db main t1
} {}
do_test 3.6 {
sqlite3_db_config db DEFENSIVE -1
} {1}
do_execsql_test 3.7 {
SELECT * FROM sqlite_schema
}
finish_test
+17 -18
View File
@@ -1,5 +1,5 @@
C Fix\stypo\sin\sthe\sprevious\scheck-in.\s\sEnsure\sthat\s--status\sheader\slines\sdo\snot\noverflow\sand\swrap.
D 2024-08-27T19:48:19.164
C Remove\sredundant\s#ifdef\saccidentally\sinserted\sinto\smkkeywordhash.c
D 2024-08-26T14:20:20.876
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -53,8 +53,8 @@ F ext/README.md fd5f78013b0a2bc6f0067afb19e6ad040e89a10179b4f6f03eee58fac5f169bd
F ext/async/README.txt e12275968f6fde133a80e04387d0e839b0c51f91
F ext/async/sqlite3async.c 6f247666b495c477628dd19364d279c78ea48cd90c72d9f9b98ad1aff3294f94
F ext/async/sqlite3async.h 46b47c79357b97ad85d20d2795942c0020dc20c532114a49808287f04aa5309a
F ext/consio/console_io.c 6e02dea912a49f55785b0027fe77960aafee6c236307c23f82ec86a69f1a2001 x
F ext/consio/console_io.h b5ebe34aa15b357621ebbea3d3f2e2b24750d4280b5802516409e23947fd9ee5
F ext/consio/console_io.c b4885dfea71ed583315de8f0792a29d5fc7c7460b4a26c0aebe5cda5da8b38f8 x
F ext/consio/console_io.h 0548b83d7c4b7270ad544a67f2bb90cebc519637fa39b1838df4744cf0d87646
F ext/expert/README.md b321c2762bb93c18ea102d5a5f7753a4b8bac646cb392b3b437f633caf2020c3
F ext/expert/expert.c d548d603a4cc9e61f446cc179c120c6713511c413f82a4a32b1e1e69d3f086a4
F ext/expert/expert1.test 661f873fd451127edf822ef0d520088faa319135f6a15bd10be6801ac284ac9b
@@ -92,7 +92,7 @@ F ext/fts3/unicode/UnicodeData.txt cd07314edb62d49fde34debdaf92fa2aa69011e7
F ext/fts3/unicode/mkunicode.tcl 63db9624ccf70d4887836c320eda93ab552f21008f3be7ede551eac3ead62baa
F ext/fts3/unicode/parseunicode.tcl a981bd6466d12dd17967515801c3ff23f74a281be1a03cf1e6f52a6959fc77eb
F ext/fts5/extract_api_docs.tcl 009cf59c77afa86d137b0cca3e3b1a5efbe2264faa2df233f9a7aa8563926d15
F ext/fts5/fts5.h efaaac0df3d3bc740383044c144b582f47921aafa21d7b10eb98f42c24c740b0
F ext/fts5/fts5.h c72759fd15179934f10b71ae51ee999e8558f696335e4ec2d049243b764354ee
F ext/fts5/fts5Int.h 26a71a09cefa4ef6b4516b204ed48da3e1380970a19b3482eea7c5d805655360
F ext/fts5/fts5_aux.c 65a0468dd177d6093aa9ae1622e6d86b0136b8d267c62c0ad6493ad1e9a3d759
F ext/fts5/fts5_buffer.c 0eec58bff585f1a44ea9147eae5da2447292080ea435957f7488c70673cb6f09
@@ -100,9 +100,9 @@ F ext/fts5/fts5_config.c 353d2a0d12678cae6ab5b9ce54aed8dac0825667b69248b5a4ed81c
F ext/fts5/fts5_expr.c 9a56f53700d1860f0ee2f373c2b9074eaf2a7aa0637d0e27a6476de26a3fee33
F ext/fts5/fts5_hash.c adda4272be401566a6e0ba1acbe70ee5cb97fce944bc2e04dc707152a0ec91b1
F ext/fts5/fts5_index.c eb9a0dda3bc6ef969a6be8d2746af56856e67251810ddba08622b45be8477abe
F ext/fts5/fts5_main.c 0dbe241c50b62e24a229a176d66d580e359b3c32cb0970c39bb6dd6b86e125d5
F ext/fts5/fts5_main.c 3d8b778f65fe5be218f6a8e4019048f092c0c09621b035ce3e8804093036b578
F ext/fts5/fts5_storage.c 9a9b880be12901f1962ae2a5a7e1b74348b3099a1e728764e419f75d98e3e612
F ext/fts5/fts5_tcl.c 4db9258a7882c5eac0da4433042132aaf15b87dd1e1636c7a6ca203abd2c8bfe
F ext/fts5/fts5_tcl.c 1dcf08028141c40a32634bdcf2d5601622ce4edc48f82ac4ce0cbe0a92a6961d
F ext/fts5/fts5_test_mi.c 08c11ec968148d4cb4119d96d819f8c1f329812c568bac3684f5464be177d3ee
F ext/fts5/fts5_test_tok.c 3cb0a9b508b30d17ef025ccddd26ae3dc8ddffbe76c057616e59a9aa85d36f3b
F ext/fts5/fts5_tokenize.c ae9c4fa93174ef06ffc138bd4280a1c37f7e13624d3d2706aad4b80573f23c41
@@ -153,7 +153,6 @@ F ext/fts5/test/fts5corrupt4.test dc08d19f5b8943e95a7778a7d8da592042504faf18dd93
F ext/fts5/test/fts5corrupt5.test 11b47126f5772cc37b67e3e8b2ed05895c4d07c05338bc07e4eea225bfe32c76
F ext/fts5/test/fts5corrupt6.test 2d72db743db7b5d9c9a6d0cfef24d799ed1aa5e8192b66c40e871a37ed9eed06
F ext/fts5/test/fts5corrupt7.test 4e830875c33b9ea3c4cf1ba71e692b63893cbb4faae8c69b1071889dc26e211c
F ext/fts5/test/fts5corrupt8.test f78b6de9e4327e16ba7a7958b1ce576f9b5d886b4b97690f90b7f3cf654da458
F ext/fts5/test/fts5delete.test 619295b20dbc1d840b403ee07c878f52378849c3c02e44f2ee143b3e978a0aa7
F ext/fts5/test/fts5detail.test 54015e9c43ec4ba542cfb93268abdf280e0300f350efd08ee411284b03595cc4
F ext/fts5/test/fts5determin.test 1b77879b2ae818b5b71c859e534ee334dac088b7cf3ff3bf76a2c82b1c788d11
@@ -754,7 +753,7 @@ F src/os_win.c 6ff43bac175bd9ed79e7c0f96840b139f2f51d01689a638fd05128becf94908a
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
F src/pager.c b08600ebf0db90b6d1e9b8b6577c6fa3877cbe1a100bd0b2899e4c6e9adad4b3
F src/pager.h 4b1140d691860de0be1347474c51fee07d5420bd7f802d38cbab8ea4ab9f538a
F src/parse.y 5972b7d00af4c8d96fdad781af1ea1d5d51fc3b907ad61bda60e49503274e5ed
F src/parse.y f4c8ded81b05059c284bc9512aaa07f6ecd29add585e35d53d72a67894b6e4d7
F src/pcache.c 588cc3c5ccaaadde689ed35ce5c5c891a1f7b1f4d1f56f6cf0143b74d8ee6484
F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5
F src/pcache1.c 49516ad7718a3626f28f710fa7448ef1fce3c07fd169acbb4817341950264319
@@ -766,7 +765,7 @@ F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
F src/resolve.c 2c127880c0634962837f16f2f48a295e514357af959330cc038de73015d5b5e8
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
F src/select.c 4b14337a2742f0c0beeba490e9a05507e9b4b12184b9cd12773501d08d48e3fe
F src/shell.c.in 40de636c1d90fb8a9ca7f49dc8f50d930f1b60736e73aca5eb37c4c7d0e47f9d
F src/shell.c.in 5a05e1a1d187ab916afe9a628d7e9b20b5997273b595bd748db324814e0ccca9
F src/sqlite.h.in f07bff4225a1244efd604a0ffef81ed69f29d3dbaed7e22f906f26229ba3ca9e
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54
@@ -828,14 +827,14 @@ F src/test_windirent.h da2e5b73c32d09905fbdd00f27cd802212a32a58ead882736fe4f5eb7
F src/test_window.c 6d80e11fba89a1796525e6f0048ff0c7789aa2c6b0b11c80827dc1437bd8ea72
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
F src/tokenize.c 3f703cacdab728d7741e5a6ac242006d74fe1c2754d4f03ed889d7253259bd68
F src/tokenize.c 6fac7f14dd021fecfdd8be93c27937804c4b665d2da9e667a10e4b5f04c6e085
F src/treeview.c 88aa39b754f5ef7214385c1bbbdd2f3dc20efafeed0cf590e8d1199b9c6e44aa
F src/trigger.c 0bb986a5b96047fd597c6aac28588853df56064e576e6b81ba777ef2ccaac461
F src/update.c 0e01aa6a3edf9ec112b33eb714b9016a81241497b1fb7c3e74332f4f71756508
F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1
F src/utf.c f23165685a67b4caf8ec08fb274cb3f319103decfb2a980b7cfd55d18dfa855e
F src/util.c 5d1a0134cf4240648d1c6bb5cc8efaca0ea2b5d5c840985aec7e947271f04375
F src/vacuum.c b763b6457bd058d2072ef9364832351fd8d11e8abf70cbb349657360f7d55c40
F src/vacuum.c 604fcdaebe76f3497c855afcbf91b8fa5046b32de3045bab89cc008d68e40104
F src/vdbe.c be5f58bc29f60252e041a618eae59e8d57d460ba136c5403cf0abf955560c457
F src/vdbe.h c2549a215898a390de6669cfa32adba56f0d7e17ba5a7f7b14506d6fd5f0c36a
F src/vdbeInt.h 949669dfd8a41550d27dcb905b494f2ccde9a2e6c1b0b04daa1227e2e74c2b2c
@@ -1714,8 +1713,8 @@ F test/temptable2.test 76821347810ecc88203e6ef0dd6897b6036ac788e9dd3e6b04fd4d163
F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637
F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc
F test/tester.tcl 2c203a2dd664298f239f0ec3ce22fbc65b5f021c1e09edbae8452af8a694e052
F test/testrunner.tcl c27905c57f54450411be922037d227fee65b08928d09715d784380a398b0e758
F test/testrunner_data.tcl 6a0facfbff26f2f8573ebaeb209426bbb59809d5c0f6925f983bd030ab5248cd
F test/testrunner.tcl 5d02deeba7a53baeadae6aa7641d90aac58fdfa3a7bcac85cfcfd752b1aab87c
F test/testrunner_data.tcl c5ae2b1f9a99210b0600d002fb3af1fee350997cee9416551e83b93501360ebf
F test/thread001.test a0985c117eab62c0c65526e9fa5d1360dd1cac5b03bde223902763274ce21899
F test/thread002.test c24c83408e35ba5a952a3638b7ac03ccdf1ce4409289c54a050ac4c5f1de7502
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
@@ -2132,7 +2131,7 @@ F tool/merge-test.tcl de76b62f2de2a92d4c1ca4f976bce0aea6899e0229e250479b229b2a19
F tool/mkautoconfamal.sh cbdcf993fa83dccbef7fb77b39cdeb31ef9f77d9d88c9e343b58d35ca3898a6a
F tool/mkccode.tcl 86463e68ce9c15d3041610fedd285ce32a5cf7a58fc88b3202b8b76837650dbe x
F tool/mkctimec.tcl 060e9785e9503bf51f8b1b11b542bdeef90fd0ceb0738154f6762acec0c61e5f x
F tool/mkkeywordhash.c b9faa0ae7e14e4dbbcd951cddd786bf46b8a65bb07b129ba8c0cfade723aaffd
F tool/mkkeywordhash.c 8a0a0401a6e0f01ca6e02f58b294a813d067554474875f4fe0222c2b8b0d6ed3
F tool/mkmsvcmin.tcl d76c45efda1cce2d4005bcea7b8a22bb752e3256009f331120fb4fecb14ebb7a
F tool/mkopcodec.tcl 33d20791e191df43209b77d37f0ff0904620b28465cca6990cf8d60da61a07ef
F tool/mkopcodeh.tcl 2b4e6967a670ef21bf53a164964c35c6163277d002a4c6f56fa231d68c88d023
@@ -2211,8 +2210,8 @@ F vsixtest/vsixtest.tcl 6195aba1f12a5e10efc2b8c0009532167be5e301abe5b31385638080
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 7c195f132cb48ee44124eb4af3532937493429f7c45f6ac611f7a9b128799ad7
R 15868716c90b102057036239341d8066
P 16d32676e2e98a7710787de16850c328e7519e893f81ed56f6155a8fa9cbc3a4
R a100ff1c9bda3fc624920cd66e34ae7c
U drh
Z fde036223228b7af985cf94952c295a1
Z 58c98d8befdb125e16f0435abf5b1a98
# Remove this line to create a well-formed Fossil manifest.
+1 -1
View File
@@ -1 +1 @@
2eaea67495fd9961b7145d829789889bf1d8fa7a834d40d1be43e7c74c233bc2
b08f3b74495e125f92c8968472fc8028c73d8df5400195df3081e3d8df8bd985
+231 -40
View File
@@ -268,7 +268,7 @@ columnname(A) ::= nm(A) typetoken(Y). {sqlite3AddColumn(pParse,A,Y);}
GENERATED ALWAYS
%endif
MATERIALIZED
REINDEX RENAME CTIME_KW IF
REINDEX RENAME CTIME_KW IF AGGREGATE
.
%wildcard ANY.
@@ -295,7 +295,8 @@ columnname(A) ::= nm(A) typetoken(Y). {sqlite3AddColumn(pParse,A,Y);}
%left CONCAT PTR.
%left COLLATE.
%right BITNOT.
%nonassoc ON.
%nonassoc ON FROM.
%nonassoc JOIN_KW JOIN.
// An IDENTIFIER can be a generic identifier, or one of several
// keywords. Any non-standard keyword can also be an identifier.
@@ -624,6 +625,233 @@ oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y)
}
%endif
%ifndef SQLITE_OMIT_SUBQUERY
%include {
SQLITE_NOINLINE SrcList *sqlite3SrcListAppendSubFrom(
Parse *pParse, /* Parsing context */
SrcList *pFrom, /* LHS of the FROM clause */
SrcList *pSubFrom, /* New parenthesized sub-FROM to append */
Token *pAs, /* AS-Name of the sub-FROM */
OnOrUsing *pOnUsing /* ON or USING clause associated with the join */
){
if( pFrom==0 && pAs->n==0 && pOnUsing->pOn==0 && pOnUsing->pUsing==0 ){
pFrom = pSubFrom;
}else if( ALWAYS(pSubFrom!=0) && pSubFrom->nSrc==1 ){
pFrom = sqlite3SrcListAppendFromTerm(pParse,pFrom,0,0,pAs,0,pOnUsing);
if( pFrom ){
SrcItem *pNew = &pFrom->a[pFrom->nSrc-1];
SrcItem *pOld = pSubFrom->a;
assert( pOld->fg.fixedSchema==0 );
pNew->zName = pOld->zName;
assert( pOld->fg.fixedSchema==0 );
if( pOld->fg.isSubquery ){
pNew->fg.isSubquery = 1;
pNew->u4.pSubq = pOld->u4.pSubq;
pOld->u4.pSubq = 0;
pOld->fg.isSubquery = 0;
assert( pNew->u4.pSubq!=0 && pNew->u4.pSubq->pSelect!=0 );
if( (pNew->u4.pSubq->pSelect->selFlags & SF_NestedFrom)!=0 ){
pNew->fg.isNestedFrom = 1;
}
}else{
pNew->u4.zDatabase = pOld->u4.zDatabase;
pOld->u4.zDatabase = 0;
}
if( pOld->fg.isTabFunc ){
pNew->u1.pFuncArg = pOld->u1.pFuncArg;
pOld->u1.pFuncArg = 0;
pOld->fg.isTabFunc = 0;
pNew->fg.isTabFunc = 1;
}
pOld->zName = 0;
}
sqlite3SrcListDelete(pParse->db, pSubFrom);
}else{
Select *pSubquery;
sqlite3SrcListShiftJoinType(pParse,pSubFrom);
pSubquery = sqlite3SelectNew(pParse,0,pSubFrom,0,0,0,0,SF_NestedFrom,0);
pFrom = sqlite3SrcListAppendFromTerm(pParse,pFrom,0,0,pAs,pSubquery,pOnUsing);
}
return pFrom;
}
}
%endif SQLITE_OMIT_SUBQUERY
%ifndef SQLITE_OMIT_FROM_FIRST
%include {
/* The Pipe object represents a pipe under construction. It is a transient
** object found only on the LALR(1) parser stack. */
typedef struct Pipe Pipe;
struct Pipe {
SrcList *pFrom; /* The FROM clause */
ExprList *pProj; /* The projection - list of columns to return */
ExprList *pOrderBy; /* The ORDER BY clause */
ExprList *pGroupBy; /* The GROUP BY clause */
Expr *pLimit; /* The LIMIT or LIMIT/OFFSET clause */
Expr *pWhere; /* The WHERE clause */
Expr *pHaving; /* The HAVING clause */
int selFlags; /* SF_DISTINCT or SF_ALL or 0 */
u8 bSeenAgg; /* True if AGGREGATE has been seen */
u8 bNeedPush; /* PipePush needed before adding terms to pProj */
Token sAs; /* Value of a pending AS clause */
};
/* Delete a pipe object */
void sqlite3PipeDelete(sqlite3 *db, Pipe *p){
sqlite3SrcListDelete(db, p->pFrom);
sqlite3ExprListDelete(db, p->pProj);
sqlite3ExprListDelete(db, p->pOrderBy);
sqlite3ExprListDelete(db, p->pGroupBy);
sqlite3ExprDelete(db, p->pLimit);
sqlite3ExprDelete(db, p->pWhere);
sqlite3ExprDelete(db, p->pHaving);
sqlite3DbFree(db, p);
}
/* Generate a Select from the current content of a Pipe. Reset the Pipe
** to be empty, except do not remove the AS token if there is one and do
** not delete the Pipe.
*/
Select *sqlite3SelectFromPipe(Parse *pParse, Pipe *p){
Token sAs = p->sAs;
Select *pSel = sqlite3SelectNew(pParse, p->pProj, p->pFrom, p->pWhere,
p->pGroupBy, p->pHaving, p->pOrderBy,
p->selFlags, p->pLimit);
memset(p, 0, sizeof(*p));
p->sAs = sAs;
return pSel;
}
/* Take the current content of the pipe and make it "FROM <subquery>" pipe.
*/
void sqlite3PipePush(Parse *pParse, Pipe *pPipe, int jointype){
Select *pSel = sqlite3SelectFromPipe(pParse, pPipe);
SrcList *pFrom = pPipe->pFrom;
if( pFrom ) pFrom->a[pFrom->nSrc-1].fg.jointype = jointype;
pPipe->pFrom = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&pPipe->sAs,pSel,0);
pPipe->sAs.z = 0;
}
}
%type pipeline {Pipe*}
%destructor pipeline {sqlite3PipeDelete(pParse->db,$$);}
oneselect(A) ::= pipeline(X). {
Pipe *pPipe = X;
Select *pSel = sqlite3SelectFromPipe(pParse,pPipe);
sqlite3DbFree(pParse->db, pPipe);
A = pSel; /*A-overwrites-X */
}
pipeline(A) ::= FROM seltablist(X). {
Pipe *pPipe = sqlite3DbMallocZero(pParse->db, sizeof(*pPipe));
A = pPipe;
if( pPipe ){
pPipe->pFrom = X;
}else{
sqlite3SrcListDelete(pParse->db, X);
}
}
pipeline(A) ::= pipeline(A) pipe pipejoinop(J) nm(Y) dbnm(D) as(Z) on_using(N). {
Pipe *p = A;
if( p->bNeedPush ) sqlite3PipePush(pParse, p, J);
p->pFrom = sqlite3SrcListAppendFromTerm(pParse, p->pFrom, &Y, &D, &Z, 0, &N);
}
pipeline(A) ::= pipeline(A) pipe
pipejoinop(J) nm(Y) dbnm(D) LP exprlist(E) RP as(Z) on_using(N). {
Pipe *p = A;
if( p->bNeedPush ) sqlite3PipePush(pParse, p, J);
p->pFrom = sqlite3SrcListAppendFromTerm(pParse, p->pFrom, &Y, &D, &Z, 0, &N);
sqlite3SrcListFuncArgs(pParse, p->pFrom, E);
}
pipeline(A) ::= pipeline(A) pipe pipejoinop(J) LP select(S) RP as(Z) on_using(N). {
Pipe *p = A;
if( p->bNeedPush ) sqlite3PipePush(pParse, p, J);
p->pFrom = sqlite3SrcListAppendFromTerm(pParse,p->pFrom,0,0,&Z,S,&N);
}
pipeline(A) ::= pipeline(A) pipe pipejoinop(J) LP seltablist(F) RP as(Z) on_using(N).{
Pipe *p = A;
if( p->bNeedPush ) sqlite3PipePush(pParse, p, J);
p->pFrom = sqlite3SrcListAppendSubFrom(pParse,p->pFrom,F,&Z,&N);
}
pipeline(A) ::= pipeline(A) pipe WHERE expr(W). {
Pipe *p = A;
if( p->bSeenAgg ){
p->pHaving = sqlite3ExprAnd(pParse, A->pHaving, W);
}else{
p->pWhere = sqlite3ExprAnd(pParse, A->pWhere, W);
}
p->bNeedPush = 1;
}
pipeline(A) ::= pipeline(A) pipe HAVING expr(W). {
Pipe *p = A;
p->pHaving = sqlite3ExprAnd(pParse, A->pHaving, W);
p->bNeedPush = 1;
}
pipeline(A) ::= pipeline(A) pipe AGGREGATE selcollist(W) groupby_opt(G). {
Pipe *p = A;
ExprList *pProj = W;
ExprList *pGroupby = G;
if( p->pProj ) sqlite3PipePush(pParse, p, 0);
if( pGroupby ){
int i;
for(i=0; i<pGroupby->nExpr; i++){
pProj = sqlite3ExprListAppend(pParse, pProj,
sqlite3ExprDup(pParse->db, pGroupby->a[i].pExpr, 0));
}
p->pGroupBy = pGroupby;
}
p->pProj = pProj;
p->bSeenAgg = 1;
p->bNeedPush = 1;
}
pipeline(A) ::= pipeline(A) pipe SELECT distinct(D) selcollist(W). {
Pipe *p = A;
if( p->pProj ) sqlite3PipePush(pParse, p, 0);
p->pProj = W;
p->selFlags = D;
p->bNeedPush = 1;
}
pipeline(A) ::= pipeline(A) pipe ORDER BY sortlist(X). {
Pipe *p = A;
if( p->pOrderBy || p->pLimit ) sqlite3PipePush(pParse, p, 0);
p->pOrderBy = X;
p->bNeedPush = 1;
}
pipeline(A) ::= pipeline(A) pipe LIMIT expr(X). {
Pipe *p = A;
Expr *pLimit = sqlite3PExpr(pParse,TK_LIMIT,X,0);
if( pLimit ){
sqlite3ExprDelete(pParse->db, p->pLimit);
p->pLimit = pLimit;
}
p->bNeedPush = 1;
}
pipeline(A) ::= pipeline(A) pipe LIMIT expr(X) OFFSET expr(Y). {
Pipe *p = A;
Expr *pLimit = sqlite3PExpr(pParse,TK_LIMIT,X,Y);
if( pLimit ){
sqlite3ExprDelete(pParse->db, p->pLimit);
p->pLimit = pLimit;
}
p->bNeedPush = 1;
}
pipeline(A) ::= pipeline(A) PIPE AS nm(X). {A->sAs = X; A->bNeedPush = 1;}
pipeline(A) ::= pipeline(A) pipe VIEW nm(X). {A->sAs = X; A->bNeedPush = 1;}
//pipeline ::= pipeline pipe DISTINCT ON nexprlist.
pipe ::= .
pipe ::= PIPE.
%type pipejoinop {int}
pipejoinop(X) ::= JOIN. { X = JT_INNER; }
pipejoinop(X) ::= JOIN_KW(A) JOIN.
{X = sqlite3JoinType(pParse,&A,0,0); /*X-overwrites-A*/}
pipejoinop(X) ::= JOIN_KW(A) nm(B) JOIN.
{X = sqlite3JoinType(pParse,&A,&B,0); /*X-overwrites-A*/}
pipejoinop(X) ::= JOIN_KW(A) nm(B) nm(C) JOIN.
{X = sqlite3JoinType(pParse,&A,&B,&C);/*X-overwrites-A*/}
%endif FROM_first
// Single row VALUES clause.
//
@@ -733,44 +961,7 @@ seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) LP exprlist(E) RP as(Z) on_using(N
A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,S,&N);
}
seltablist(A) ::= stl_prefix(A) LP seltablist(F) RP as(Z) on_using(N). {
if( A==0 && Z.n==0 && N.pOn==0 && N.pUsing==0 ){
A = F;
}else if( ALWAYS(F!=0) && F->nSrc==1 ){
A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,0,&N);
if( A ){
SrcItem *pNew = &A->a[A->nSrc-1];
SrcItem *pOld = F->a;
assert( pOld->fg.fixedSchema==0 );
pNew->zName = pOld->zName;
assert( pOld->fg.fixedSchema==0 );
if( pOld->fg.isSubquery ){
pNew->fg.isSubquery = 1;
pNew->u4.pSubq = pOld->u4.pSubq;
pOld->u4.pSubq = 0;
pOld->fg.isSubquery = 0;
assert( pNew->u4.pSubq!=0 && pNew->u4.pSubq->pSelect!=0 );
if( (pNew->u4.pSubq->pSelect->selFlags & SF_NestedFrom)!=0 ){
pNew->fg.isNestedFrom = 1;
}
}else{
pNew->u4.zDatabase = pOld->u4.zDatabase;
pOld->u4.zDatabase = 0;
}
if( pOld->fg.isTabFunc ){
pNew->u1.pFuncArg = pOld->u1.pFuncArg;
pOld->u1.pFuncArg = 0;
pOld->fg.isTabFunc = 0;
pNew->fg.isTabFunc = 1;
}
pOld->zName = 0;
}
sqlite3SrcListDelete(pParse->db, F);
}else{
Select *pSubquery;
sqlite3SrcListShiftJoinType(pParse,F);
pSubquery = sqlite3SelectNew(pParse,0,F,0,0,0,0,SF_NestedFrom,0);
A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,pSubquery,&N);
}
A = sqlite3SrcListAppendSubFrom(pParse,A,F,&Z,&N);
}
%endif SQLITE_OMIT_SUBQUERY
-3
View File
@@ -246,7 +246,6 @@ extern LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText);
# define SQLITE_CIO_NO_CLASSIFY
# define SQLITE_CIO_NO_TRANSLATE
# define SQLITE_CIO_NO_SETMODE
# define SQLITE_CIO_NO_FLUSH
#endif
INCLUDE ../ext/consio/console_io.h
INCLUDE ../ext/consio/console_io.c
@@ -280,7 +279,6 @@ INCLUDE ../ext/consio/console_io.c
# define eputz(z) ePutsUtf8(z)
# define eputf ePrintfUtf8
# define oputb(buf,na) oPutbUtf8(buf,na)
# define fflush(s) fFlushBuffer(s);
#else
/* For Fiddle, all console handling and emit redirection is omitted. */
@@ -297,7 +295,6 @@ INCLUDE ../ext/consio/console_io.c
# define eputz(z) fputs(z,stderr)
# define sputz(fp,z) fputs(z,fp)
# define oputb(buf,na) fwrite(buf,1,na,stdout)
# undef fflush
#endif
/* True if the timer is enabled */
+9 -4
View File
@@ -372,12 +372,17 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
}
}
case CC_PIPE: {
if( z[1]!='|' ){
*tokenType = TK_BITOR;
return 1;
}else{
if( z[1]=='|' ){
*tokenType = TK_CONCAT;
return 2;
#ifdef TK_PIPE
}else if( z[1]=='>' ){
*tokenType = TK_PIPE;
return 2;
#endif
}else{
*tokenType = TK_BITOR;
return 1;
}
}
case CC_COMMA: {
+9 -14
View File
@@ -162,9 +162,6 @@ SQLITE_NOINLINE int sqlite3RunVacuum(
const char *zDbMain; /* Schema name of database to vacuum */
const char *zOut; /* Name of output file */
u32 pgflags = PAGER_SYNCHRONOUS_OFF; /* sync flags for output db */
u64 iRandom; /* Random value used for zDbVacuum[] */
char zDbVacuum[42]; /* Name of the ATTACH-ed database used for vacuum */
if( !db->autoCommit ){
sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction");
@@ -205,29 +202,27 @@ SQLITE_NOINLINE int sqlite3RunVacuum(
pMain = db->aDb[iDb].pBt;
isMemDb = sqlite3PagerIsMemdb(sqlite3BtreePager(pMain));
/* Attach the temporary database as 'vacuum_XXXXXX'. The synchronous pragma
/* Attach the temporary database as 'vacuum_db'. The synchronous pragma
** can be set to 'off' for this file, as it is not recovered if a crash
** occurs anyway. The integrity of the database is maintained by a
** (possibly synchronous) transaction opened on the main database before
** sqlite3BtreeCopyFile() is called.
**
** An optimization would be to use a non-journaled pager.
** (Later:) I tried setting "PRAGMA vacuum_XXXXXX.journal_mode=OFF" but
** (Later:) I tried setting "PRAGMA vacuum_db.journal_mode=OFF" but
** that actually made the VACUUM run slower. Very little journalling
** actually occurs when doing a vacuum since the vacuum_db is initially
** empty. Only the journal header is written. Apparently it takes more
** time to parse and run the PRAGMA to turn journalling off than it does
** to write the journal header file.
*/
sqlite3_randomness(sizeof(iRandom),&iRandom);
sqlite3_snprintf(sizeof(zDbVacuum), zDbVacuum, "vacuum_%016llx", iRandom);
nDb = db->nDb;
rc = execSqlF(db, pzErrMsg, "ATTACH %Q AS %s", zOut, zDbVacuum);
rc = execSqlF(db, pzErrMsg, "ATTACH %Q AS vacuum_db", zOut);
db->openFlags = saved_openFlags;
if( rc!=SQLITE_OK ) goto end_of_vacuum;
assert( (db->nDb-1)==nDb );
pDb = &db->aDb[nDb];
assert( strcmp(pDb->zDbSName,zDbVacuum)==0 );
assert( strcmp(pDb->zDbSName,"vacuum_db")==0 );
pTemp = pDb->pBt;
if( pOut ){
sqlite3_file *id = sqlite3PagerFile(sqlite3BtreePager(pTemp));
@@ -304,11 +299,11 @@ SQLITE_NOINLINE int sqlite3RunVacuum(
** the contents to the temporary database.
*/
rc = execSqlF(db, pzErrMsg,
"SELECT'INSERT INTO %s.'||quote(name)"
"SELECT'INSERT INTO vacuum_db.'||quote(name)"
"||' SELECT*FROM\"%w\".'||quote(name)"
"FROM %s.sqlite_schema "
"FROM vacuum_db.sqlite_schema "
"WHERE type='table'AND coalesce(rootpage,1)>0",
zDbVacuum, zDbMain, zDbVacuum
zDbMain
);
assert( (db->mDbFlags & DBFLAG_Vacuum)!=0 );
db->mDbFlags &= ~DBFLAG_Vacuum;
@@ -320,11 +315,11 @@ SQLITE_NOINLINE int sqlite3RunVacuum(
** from the schema table.
*/
rc = execSqlF(db, pzErrMsg,
"INSERT INTO %s.sqlite_schema"
"INSERT INTO vacuum_db.sqlite_schema"
" SELECT*FROM \"%w\".sqlite_schema"
" WHERE type IN('view','trigger')"
" OR(type='table'AND rootpage=0)",
zDbVacuum, zDbMain
zDbMain
);
if( rc ) goto end_of_vacuum;
+31 -78
View File
@@ -89,9 +89,7 @@ Other PERMUTATION arguments must be run using testfixture, not tclsh:
If no PATTERN arguments are present, all tests specified by the PERMUTATION
are run. Otherwise, each pattern is interpreted as a glob pattern. Only
those tcl tests for which the final component of the filename matches at
least one specified pattern are run. The glob wildcard '*' is prepended
to the pattern if it does not start with '^' and appended to every
pattern that does not end with '$'.
least one specified pattern are run.
If no PATTERN arguments are present, then various fuzztest, threadtest
and other tests are run as part of the "release" permutation. These are
@@ -279,12 +277,10 @@ set TRG(schema) {
priority INTEGER NOT NULL, -- higher priority jobs may run earlier
/* Fields updated as jobs run */
starttime INTEGER, -- Start time (milliseconds since 1970)
endtime INTEGER, -- End time
starttime INTEGER,
endtime INTEGER,
state TEXT CHECK( state IN ('','ready','running','done','failed','omit') ),
ntest INT, -- Number of test cases run
nerr INT, -- Number of errors reported
output TEXT -- test output
output TEXT
);
CREATE TABLE config(
@@ -393,36 +389,14 @@ if {[string compare -nocase script [lindex $argv 0]]==0} {
exit
}
# Compute an elapse time string MM:SS or HH:MM:SS based on the
# number of milliseconds in the argument.
#
proc elapsetime {ms} {
set s [expr {int(($ms+500.0)*0.001)}]
set hr [expr {$s/3600}]
set mn [expr {($s/60)%60}]
set sc [expr {$s%60}]
if {$hr>0} {
return [format %02d:%02d:%02d $hr $mn $sc]
} else {
return [format %02d:%02d $mn $sc]
}
}
# Helper routine for show_status
#
proc display_job {jobdict {tm ""}} {
array set job $jobdict
if {[string length $job(displayname)]>65} {
set dfname [format %.65s... $job(displayname)]
} else {
set dfname [format %-68s $job(displayname)]
}
set dfname [format %-60s $job(displayname)]
set dtm ""
if {$tm!=""} {
set dtm [expr {$tm-$job(starttime)}]
set dtm [format %8s [elapsetime $dtm]]
} else {
set dtm [format %8s ""]
set dtm [format %-10s "\[[expr {$tm-$job(starttime)}]ms\]"]
}
puts " $dfname $dtm"
}
@@ -457,11 +431,6 @@ proc show_status {db cls} {
incr S($state) $cnt
incr total $cnt
}
set nt 0
set ne 0
$db eval {
SELECT sum(ntest) AS nt, sum(nerr) AS ne FROM jobs HAVING nt>0
} break
set fin [expr $S(done)+$S(failed)]
if {$cmdline!=""} {set cmdline " $cmdline"}
@@ -474,10 +443,14 @@ proc show_status {db cls} {
} else {
set clreol ""
}
puts [format %-79.79s "Command: \[testrunner.tcl$cmdline\]$clreol"]
puts [format %-79.79s "Cores: $nJob max $S(running) active"]
puts [format %-79.79s "Summary: [elapsetime $tm], $fin/$total tasks,\
$ne errors, $nt tests"]
set f ""
if {$S(failed)>0} {
set f "$S(failed) FAILED, "
}
puts "Command line: \[testrunner.tcl$cmdline\]$clreol"
puts "Jobs: $nJob "
puts "Summary: ${tm}ms, ($fin/$total) finished,\
${f}$S(running) running "
set srcdir [file dirname [file dirname $TRG(info_script)]]
if {$S(running)>0} {
@@ -497,7 +470,7 @@ proc show_status {db cls} {
}
set nOmit [$db one {SELECT count(*) FROM jobs WHERE state='omit'}]
if {$nOmit} {
puts [format %-79s "$nOmit jobs omitted due to failures$clreol"]
puts "$nOmit jobs omitted due to failures$clreol"
}
}
if {$cls} {
@@ -869,17 +842,6 @@ proc add_tcl_jobs {build config patternlist {shelldepid ""}} {
if {[llength $patternlist]>0} {
set bMatch 0
foreach p $patternlist {
set p [string trim $p *]
if {[string index $p 0]=="^"} {
set p [string range $p 1 end]
} else {
set p "*$p"
}
if {[string index $p end]=="\$"} {
set p [string range $p 0 end-1]
} else {
set p "$p*"
}
if {[string match $p [file tail $f]]} {
set bMatch 1
break
@@ -1100,13 +1062,25 @@ proc add_jobs_from_cmdline {patternlist} {
}
release {
set config_set {}
set patternlist [lrange $patternlist 1 end]
foreach b [trd_builds $TRG(platform)] {
if {$TRG(config)!="" && ![regexp "\\y$b\\y" $TRG(config)]} continue
if {[regexp "\\y$b\\y" $TRG(omitconfig)]} continue
lappend config_set $b
set bld [add_build_job $b $TRG(testfixture)]
foreach c [trd_configs $TRG(platform) $b] {
add_tcl_jobs $bld $c $patternlist
}
if {$patternlist==""} {
foreach e [trd_extras $TRG(platform) $b] {
if {$e=="fuzztest"} {
add_fuzztest_jobs $b
} else {
add_make_job $bld $e
}
}
}
}
add_devtest_jobs $config_set [lrange $patternlist 1 end]
}
list {
@@ -1146,25 +1120,15 @@ proc make_new_testset {} {
}
proc mark_job_as_finished {jobid output state endtm} {
set ntest 1
set nerr 0
if {$endtm>0} {
if {[regexp {\y(\d+) errors out of (\d+) tests} $output all a b]} {
set nerr $a
set ntest $b
}
}
r_write_db {
if {$state=="failed"} {
set childstate omit
if {$nerr<=0} {set nerr 1}
} else {
set childstate ready
}
trdb eval {
UPDATE jobs
SET output=$output, state=$state, endtime=$endtm,
ntest=$ntest, nerr=$nerr
SET output=$output, state=$state, endtime=$endtm
WHERE jobid=$jobid;
UPDATE jobs SET state=$childstate WHERE depid=$jobid;
}
@@ -1407,17 +1371,6 @@ proc run_testset {} {
puts "\nTest database is $TRG(dbname)"
puts "Test log is $TRG(logname)"
trdb eval {
SELECT sum(ntest) AS totaltest,
sum(nerr) AS totalerr
FROM jobs
} break
trdb eval {
SELECT max(endtime)-min(starttime) AS totaltime
FROM jobs WHERE endtime>0
} break;
set et [elapsetime $totaltime]
puts "$totalerr errors out of $totaltest tests in about $et"
}
# Handle the --buildonly option, if it was specified.
+6 -2
View File
@@ -16,6 +16,7 @@ namespace eval trd {
set tcltest(linux.Have-Not) veryquick
set tcltest(linux.Secure-Delete) veryquick
set tcltest(linux.Unlock-Notify) veryquick
set tcltest(linux.User-Auth) veryquick
set tcltest(linux.Update-Delete-Limit) veryquick
set tcltest(linux.Extra-Robustness) veryquick
set tcltest(linux.Device-Two) veryquick
@@ -115,7 +116,6 @@ namespace eval trd {
}
set build(Stdcall) {
-DUSE_STDCALL=1
-DSQLITE_USE_ONLY_WIN32=1
-O2
}
@@ -139,6 +139,10 @@ namespace eval trd {
-DSQLITE_THREADSAFE
-DSQLITE_TCL_DEFAULT_FULLMUTEX=1
}
set build(User-Auth) {
-O2
-DSQLITE_USER_AUTHENTICATION=1
}
set build(Secure-Delete) {
-O2
-DSQLITE_SECURE_DELETE=1
@@ -218,7 +222,7 @@ namespace eval trd {
-DSQLITE_MAX_PAGE_SIZE=4096
-DSQLITE_OMIT_LOAD_EXTENSION=1
-DSQLITE_OMIT_PROGRESS_CALLBACK=1
-DSQLITE_OMIT_VIRTUALTABLEx=1
-DSQLITE_OMIT_VIRTUALTABLE=1
-DSQLITE_ENABLE_HIDDEN_COLUMNS
-DSQLITE_TEMP_STORE=3
}
+6
View File
@@ -164,6 +164,11 @@ struct Keyword {
#else
# define RETURNING 0x00400000
#endif
#ifdef SQLITE_OMIT_FROM_FIRST
# define PIPE 0
#else
# define PIPE 0x00800000
#endif
/*
@@ -174,6 +179,7 @@ static Keyword aKeywordTable[] = {
{ "ACTION", "TK_ACTION", FKEY, 0 },
{ "ADD", "TK_ADD", ALTER, 1 },
{ "AFTER", "TK_AFTER", TRIGGER, 0 },
{ "AGGREGATE", "TK_AGGREGATE", PIPE, 10 },
{ "ALL", "TK_ALL", ALWAYS, 0 },
{ "ALTER", "TK_ALTER", ALTER, 0 },
{ "ALWAYS", "TK_ALWAYS", GENCOL, 0 },