aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordan <dan@noemail.net>2019-08-17 15:47:32 +0000
committerdan <dan@noemail.net>2019-08-17 15:47:32 +0000
commit5b32bdff8028a68f3479efad5147c63c8e6398ab (patch)
tree3275e800d0bc7d5c845866134c587ffa4bc763dd /src
parent15750a26fa7127af7b1aa3e3a2046f5379eaca43 (diff)
parent217ca657d82f2324d6c5a97598bf4f77ebbb1fe7 (diff)
downloadsqlite-5b32bdff8028a68f3479efad5147c63c8e6398ab.tar.gz
sqlite-5b32bdff8028a68f3479efad5147c63c8e6398ab.zip
Merge trunk changes into this branch.
FossilOrigin-Name: db1e60800bc260cdcd604739daaba72c6b486158123fc62a3898aca4ead33cd3
Diffstat (limited to 'src')
-rw-r--r--src/analyze.c4
-rw-r--r--src/attach.c1
-rw-r--r--src/btree.c9
-rw-r--r--src/build.c2
-rw-r--r--src/expr.c7
-rw-r--r--src/main.c11
-rw-r--r--src/memjournal.c5
-rw-r--r--src/prepare.c2
-rw-r--r--src/resolve.c20
-rw-r--r--src/select.c12
-rw-r--r--src/shell.c.in19
-rw-r--r--src/sqlite.h.in31
-rw-r--r--src/sqliteInt.h80
-rw-r--r--src/tclsqlite.c126
-rw-r--r--src/treeview.c6
-rw-r--r--src/vtab.c55
-rw-r--r--src/where.c1
-rw-r--r--src/window.c21
18 files changed, 298 insertions, 114 deletions
diff --git a/src/analyze.c b/src/analyze.c
index 31fb6f5b5..1904b9be0 100644
--- a/src/analyze.c
+++ b/src/analyze.c
@@ -1450,7 +1450,9 @@ static void decodeIntArray(
if( sqlite3_strglob("unordered*", z)==0 ){
pIndex->bUnordered = 1;
}else if( sqlite3_strglob("sz=[0-9]*", z)==0 ){
- pIndex->szIdxRow = sqlite3LogEst(sqlite3Atoi(z+3));
+ int sz = sqlite3Atoi(z+3);
+ if( sz<2 ) sz = 2;
+ pIndex->szIdxRow = sqlite3LogEst(sz);
}else if( sqlite3_strglob("noskipscan*", z)==0 ){
pIndex->noSkipScan = 1;
}
diff --git a/src/attach.c b/src/attach.c
index 55e0eb536..61f169ed7 100644
--- a/src/attach.c
+++ b/src/attach.c
@@ -560,6 +560,7 @@ int sqlite3FixExpr(
Expr *pExpr /* The expression to be fixed to one database */
){
while( pExpr ){
+ ExprSetProperty(pExpr, EP_Indirect);
if( pExpr->op==TK_VARIABLE ){
if( pFix->pParse->db->init.busy ){
pExpr->op = TK_NULL;
diff --git a/src/btree.c b/src/btree.c
index 30cd0d128..6e6a9b279 100644
--- a/src/btree.c
+++ b/src/btree.c
@@ -4879,6 +4879,7 @@ static int accessPayload(
assert( aWrite>=pBufStart ); /* due to (6) */
memcpy(aSave, aWrite, 4);
rc = sqlite3OsRead(fd, aWrite, a+4, (i64)pBt->pageSize*(nextPage-1));
+ if( rc && nextPage>pBt->nPage ) rc = SQLITE_CORRUPT_BKPT;
nextPage = get4byte(aWrite);
memcpy(aWrite, aSave, 4);
}else
@@ -7674,7 +7675,7 @@ static int balance_nonroot(
*/
memset(&b.szCell[b.nCell], 0, sizeof(b.szCell[0])*(limit+pOld->nOverflow));
if( pOld->nOverflow>0 ){
- if( limit<pOld->aiOvfl[0] ){
+ if( NEVER(limit<pOld->aiOvfl[0]) ){
rc = SQLITE_CORRUPT_BKPT;
goto balance_cleanup;
}
@@ -8475,7 +8476,9 @@ static int btreeOverwriteCell(BtCursor *pCur, const BtreePayload *pX){
Pgno ovflPgno; /* Next overflow page to write */
u32 ovflPageSize; /* Size to write on overflow page */
- if( pCur->info.pPayload + pCur->info.nLocal > pPage->aDataEnd ){
+ if( pCur->info.pPayload + pCur->info.nLocal > pPage->aDataEnd
+ || pCur->info.pPayload < pPage->aData + pPage->cellOffset
+ ){
return SQLITE_CORRUPT_BKPT;
}
/* Overwrite the local portion first */
@@ -8716,6 +8719,8 @@ int sqlite3BtreeInsert(
memcpy(newCell, oldCell, 4);
}
rc = clearCell(pPage, oldCell, &info);
+ testcase( pCur->curFlags & BTCF_ValidOvfl );
+ invalidateOverflowCache(pCur);
if( info.nSize==szNew && info.nLocal==info.nPayload
&& (!ISAUTOVACUUM || szNew<pPage->minLocal)
){
diff --git a/src/build.c b/src/build.c
index 71c04299b..3f9ab0b97 100644
--- a/src/build.c
+++ b/src/build.c
@@ -3368,7 +3368,7 @@ void sqlite3CreateIndex(
sqlite3ExprAlloc(db, TK_ID, &prevCol, 0));
if( pList==0 ) goto exit_create_index;
assert( pList->nExpr==1 );
- sqlite3ExprListSetSortOrder(pList, sortOrder, 0);
+ sqlite3ExprListSetSortOrder(pList, sortOrder, SQLITE_SO_UNDEFINED);
}else{
sqlite3ExprListCheckLength(pParse, pList, "index");
if( pParse->nErr ) goto exit_create_index;
diff --git a/src/expr.c b/src/expr.c
index 4307c08da..c5072aa61 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -1325,12 +1325,7 @@ static int gatherSelectWindowsCallback(Walker *pWalker, Expr *pExpr){
assert( pWin );
assert( IsWindowFunc(pExpr) );
assert( pWin->ppThis==0 );
- if( pSelect->pWin ){
- pSelect->pWin->ppThis = &pWin->pNextWin;
- }
- pWin->pNextWin = pSelect->pWin;
- pWin->ppThis = &pSelect->pWin;
- pSelect->pWin = pWin;
+ sqlite3WindowLink(pSelect, pWin);
}
return WRC_Continue;
}
diff --git a/src/main.c b/src/main.c
index 06a55eca0..a8c1d4dc6 100644
--- a/src/main.c
+++ b/src/main.c
@@ -836,6 +836,7 @@ int sqlite3_db_config(sqlite3 *db, int op, ...){
} aFlagOp[] = {
{ SQLITE_DBCONFIG_ENABLE_FKEY, SQLITE_ForeignKeys },
{ SQLITE_DBCONFIG_ENABLE_TRIGGER, SQLITE_EnableTrigger },
+ { SQLITE_DBCONFIG_ENABLE_VIEW, SQLITE_EnableView },
{ SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, SQLITE_Fts3Tokenizer },
{ SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, SQLITE_LoadExtension },
{ SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE, SQLITE_NoCkptOnClose },
@@ -1235,11 +1236,8 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
#ifndef SQLITE_OMIT_VIRTUALTABLE
for(i=sqliteHashFirst(&db->aModule); i; i=sqliteHashNext(i)){
Module *pMod = (Module *)sqliteHashData(i);
- if( pMod->xDestroy ){
- pMod->xDestroy(pMod->pAux);
- }
sqlite3VtabEponymousTableClear(db, pMod);
- sqlite3DbFree(db, pMod);
+ sqlite3VtabModuleUnref(db, pMod);
}
sqlite3HashClear(&db->aModule);
#endif
@@ -1720,7 +1718,8 @@ int sqlite3CreateFunc(
}
assert( SQLITE_FUNC_CONSTANT==SQLITE_DETERMINISTIC );
- extraFlags = enc & SQLITE_DETERMINISTIC;
+ assert( SQLITE_FUNC_DIRECT==SQLITE_DIRECTONLY );
+ extraFlags = enc & (SQLITE_DETERMINISTIC|SQLITE_DIRECTONLY);
enc &= (SQLITE_FUNC_ENCMASK|SQLITE_ANY);
#ifndef SQLITE_OMIT_UTF16
@@ -1783,6 +1782,7 @@ int sqlite3CreateFunc(
p->u.pDestructor = pDestructor;
p->funcFlags = (p->funcFlags & SQLITE_FUNC_ENCMASK) | extraFlags;
testcase( p->funcFlags & SQLITE_DETERMINISTIC );
+ testcase( p->funcFlags & SQLITE_DIRECTONLY );
p->xSFunc = xSFunc ? xSFunc : xStep;
p->xFinalize = xFinal;
p->xValue = xValue;
@@ -3075,6 +3075,7 @@ static int openDatabase(
db->nMaxSorterMmap = 0x7FFFFFFF;
db->flags |= SQLITE_ShortColNames
| SQLITE_EnableTrigger
+ | SQLITE_EnableView
| SQLITE_CacheSpill
/* The SQLITE_DQS compile-time option determines the default settings
diff --git a/src/memjournal.c b/src/memjournal.c
index 3b0e7a672..0a14e847a 100644
--- a/src/memjournal.c
+++ b/src/memjournal.c
@@ -96,14 +96,9 @@ static int memjrnlRead(
int iChunkOffset;
FileChunk *pChunk;
-#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
- || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
if( (iAmt+iOfst)>p->endpoint.iOffset ){
return SQLITE_IOERR_SHORT_READ;
}
-#endif
-
- assert( (iAmt+iOfst)<=p->endpoint.iOffset );
assert( p->readpoint.iOffset==0 || p->readpoint.pChunk!=0 );
if( p->readpoint.iOffset!=iOfst || iOfst==0 ){
sqlite3_int64 iOff = 0;
diff --git a/src/prepare.c b/src/prepare.c
index c6d7fba70..70c162658 100644
--- a/src/prepare.c
+++ b/src/prepare.c
@@ -115,7 +115,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
if( db->init.orphanTrigger ){
assert( iDb==1 );
}else{
- pData->rc = rc;
+ if( rc > pData->rc ) pData->rc = rc;
if( rc==SQLITE_NOMEM ){
sqlite3OomFault(db);
}else if( rc!=SQLITE_INTERRUPT && (rc&0xFF)!=SQLITE_LOCKED ){
diff --git a/src/resolve.c b/src/resolve.c
index d88abc4a4..ab2266409 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -823,6 +823,15 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
** SQL is being compiled using sqlite3NestedParse() */
no_such_func = 1;
pDef = 0;
+ }else
+ if( (pDef->funcFlags & SQLITE_FUNC_DIRECT)!=0
+ && ExprHasProperty(pExpr, EP_Indirect)
+ && !IN_RENAME_OBJECT
+ ){
+ /* Functions tagged with SQLITE_DIRECTONLY may not be used
+ ** inside of triggers and views */
+ sqlite3ErrorMsg(pParse, "%s() prohibited in triggers and views",
+ pDef->zName);
}
}
@@ -908,16 +917,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
sqlite3WalkExprList(pWalker, pWin->pPartition);
sqlite3WalkExprList(pWalker, pWin->pOrderBy);
sqlite3WalkExpr(pWalker, pWin->pFilter);
- if( 0==pSel->pWin
- || 0==sqlite3WindowCompare(pParse, pSel->pWin, pWin, 0)
- ){
- pWin->pNextWin = pSel->pWin;
- if( pSel->pWin ){
- pSel->pWin->ppThis = &pWin->pNextWin;
- }
- pSel->pWin = pWin;
- pWin->ppThis = &pSel->pWin;
- }
+ sqlite3WindowLink(pSel, pWin);
pNC->ncFlags |= NC_HasWin;
}else
#endif /* SQLITE_OMIT_WINDOWFUNC */
diff --git a/src/select.c b/src/select.c
index db2667e2a..75541455a 100644
--- a/src/select.c
+++ b/src/select.c
@@ -4405,7 +4405,7 @@ static u8 minMaxQuery(sqlite3 *db, Expr *pFunc, ExprList **ppMinMax){
ExprList *pEList = pFunc->x.pList; /* Arguments to agg function */
const char *zFunc; /* Name of aggregate function pFunc */
ExprList *pOrderBy;
- u8 sortOrder;
+ u8 sortFlags;
assert( *ppMinMax==0 );
assert( pFunc->op==TK_AGG_FUNCTION );
@@ -4416,16 +4416,16 @@ static u8 minMaxQuery(sqlite3 *db, Expr *pFunc, ExprList **ppMinMax){
zFunc = pFunc->u.zToken;
if( sqlite3StrICmp(zFunc, "min")==0 ){
eRet = WHERE_ORDERBY_MIN;
- sortOrder = SQLITE_SO_ASC;
+ sortFlags = KEYINFO_ORDER_BIGNULL;
}else if( sqlite3StrICmp(zFunc, "max")==0 ){
eRet = WHERE_ORDERBY_MAX;
- sortOrder = SQLITE_SO_DESC;
+ sortFlags = KEYINFO_ORDER_DESC;
}else{
return eRet;
}
*ppMinMax = pOrderBy = sqlite3ExprListDup(db, pEList, 0);
assert( pOrderBy!=0 || db->mallocFailed );
- if( pOrderBy ) pOrderBy->a[0].sortFlags = sortOrder;
+ if( pOrderBy ) pOrderBy->a[0].sortFlags = sortFlags;
return eRet;
}
@@ -4906,6 +4906,10 @@ static int selectExpander(Walker *pWalker, Select *p){
u8 eCodeOrig = pWalker->eCode;
if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort;
assert( pFrom->pSelect==0 );
+ if( pTab->pSelect && (db->flags & SQLITE_EnableView)==0 ){
+ sqlite3ErrorMsg(pParse, "access to view \"%s\" prohibited",
+ pTab->zName);
+ }
pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0);
nCol = pTab->nCol;
pTab->nCol = -1;
diff --git a/src/shell.c.in b/src/shell.c.in
index 19280e318..494a3d7e2 100644
--- a/src/shell.c.in
+++ b/src/shell.c.in
@@ -3649,6 +3649,9 @@ static const char *(azHelp[]) = {
" --row Trace each row (SQLITE_TRACE_ROW)",
" --close Trace connection close (SQLITE_TRACE_CLOSE)",
#endif /* SQLITE_OMIT_TRACE */
+#ifdef SQLITE_DEBUG
+ ".unmodule NAME ... Unregister virtual table modules",
+#endif
".vfsinfo ?AUX? Information about the top-level VFS",
".vfslist List all available VFSes",
".vfsname ?AUX? Print the name of the VFS stack",
@@ -7135,6 +7138,7 @@ static int do_meta_command(char *zLine, ShellState *p){
} aDbConfig[] = {
{ "enable_fkey", SQLITE_DBCONFIG_ENABLE_FKEY },
{ "enable_trigger", SQLITE_DBCONFIG_ENABLE_TRIGGER },
+ { "enable_view", SQLITE_DBCONFIG_ENABLE_VIEW },
{ "fts3_tokenizer", SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER },
{ "load_extension", SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION },
{ "no_ckpt_on_close", SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE },
@@ -9400,6 +9404,21 @@ static int do_meta_command(char *zLine, ShellState *p){
}else
#endif /* !defined(SQLITE_OMIT_TRACE) */
+#ifdef SQLITE_DEBUG
+ if( c=='u' && strncmp(azArg[0], "unmodule", n)==0 ){
+ int ii;
+ if( nArg<2 ){
+ raw_printf(stderr, "Usage: .unmodule NAME ...\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
+ open_db(p, 0);
+ for(ii=1; ii<nArg; ii++){
+ sqlite3_create_module(p->db, azArg[ii], 0, 0);
+ }
+ }else
+#endif
+
#if SQLITE_USER_AUTHENTICATION
if( c=='u' && strncmp(azArg[0], "user", n)==0 ){
if( nArg<2 ){
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index d68cef249..ed5e2922c 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -2093,6 +2093,17 @@ struct sqlite3_mem_methods {
** following this call. The second parameter may be a NULL pointer, in
** which case the trigger setting is not reported back. </dd>
**
+** [[SQLITE_DBCONFIG_ENABLE_VIEW]]
+** <dt>SQLITE_DBCONFIG_ENABLE_VIEW</dt>
+** <dd> ^This option is used to enable or disable [CREATE VIEW | views].
+** There should be two additional arguments.
+** The first argument is an integer which is 0 to disable views,
+** positive to enable views or negative to leave the setting unchanged.
+** The second parameter is a pointer to an integer into which
+** is written 0 or 1 to indicate whether views are disabled or enabled
+** following this call. The second parameter may be a NULL pointer, in
+** which case the view setting is not reported back. </dd>
+**
** [[SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER]]
** <dt>SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER</dt>
** <dd> ^This option is used to enable or disable the
@@ -2265,7 +2276,8 @@ struct sqlite3_mem_methods {
#define SQLITE_DBCONFIG_LEGACY_ALTER_TABLE 1012 /* int int* */
#define SQLITE_DBCONFIG_DQS_DML 1013 /* int int* */
#define SQLITE_DBCONFIG_DQS_DDL 1014 /* int int* */
-#define SQLITE_DBCONFIG_MAX 1014 /* Largest DBCONFIG */
+#define SQLITE_DBCONFIG_ENABLE_VIEW 1015 /* int int* */
+#define SQLITE_DBCONFIG_MAX 1015 /* Largest DBCONFIG */
/*
** CAPI3REF: Enable Or Disable Extended Result Codes
@@ -4848,6 +4860,9 @@ int sqlite3_reset(sqlite3_stmt *pStmt);
** function that is not deterministic. The SQLite query planner is able to
** perform additional optimizations on deterministic functions, so use
** of the [SQLITE_DETERMINISTIC] flag is recommended where possible.
+** ^The fourth parameter may also optionally include the [SQLITE_DIRECTONLY]
+** flag, which if present prevents the function from being invoked from
+** within VIEWs or TRIGGERs.
**
** ^(The fifth parameter is an arbitrary pointer. The implementation of the
** function can gain access to this pointer using [sqlite3_user_data()].)^
@@ -4965,8 +4980,16 @@ int sqlite3_create_window_function(
** [SQLITE_UTF8 | preferred text encoding] as the fourth argument
** to [sqlite3_create_function()], [sqlite3_create_function16()], or
** [sqlite3_create_function_v2()].
+**
+** The SQLITE_DETERMINISTIC flag means that the new function will always
+** maps the same inputs into the same output. The abs() function is
+** deterministic, for example, but randomblob() is not.
+**
+** The SQLITE_DIRECTONLY flag means that the function may only be invoked
+** from top-level SQL, and cannot be used in VIEWs or TRIGGERs.
*/
-#define SQLITE_DETERMINISTIC 0x800
+#define SQLITE_DETERMINISTIC 0x000000800
+#define SQLITE_DIRECTONLY 0x000080000
/*
** CAPI3REF: Deprecated Functions
@@ -6612,6 +6635,10 @@ struct sqlite3_index_info {
** ^The sqlite3_create_module()
** interface is equivalent to sqlite3_create_module_v2() with a NULL
** destructor.
+**
+** ^If the third parameter (the pointer to the sqlite3_module object) is
+** NULL then no new module is create and any existing modules with the
+** same name are dropped.
*/
int sqlite3_create_module(
sqlite3 *db, /* SQLite connection to register module with */
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index f036092ba..c47cc6ffc 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -1537,16 +1537,17 @@ struct sqlite3 {
#define SQLITE_Defensive 0x10000000 /* Input SQL is likely hostile */
#define SQLITE_DqsDDL 0x20000000 /* dbl-quoted strings allowed in DDL*/
#define SQLITE_DqsDML 0x40000000 /* dbl-quoted strings allowed in DML*/
+#define SQLITE_EnableView 0x80000000 /* Enable the use of views */
/* Flags used only if debugging */
#define HI(X) ((u64)(X)<<32)
#ifdef SQLITE_DEBUG
-#define SQLITE_SqlTrace HI(0x0001) /* Debug print SQL as it executes */
-#define SQLITE_VdbeListing HI(0x0002) /* Debug listings of VDBE progs */
-#define SQLITE_VdbeTrace HI(0x0004) /* True to trace VDBE execution */
-#define SQLITE_VdbeAddopTrace HI(0x0008) /* Trace sqlite3VdbeAddOp() calls */
-#define SQLITE_VdbeEQP HI(0x0010) /* Debug EXPLAIN QUERY PLAN */
-#define SQLITE_ParserTrace HI(0x0020) /* PRAGMA parser_trace=ON */
+#define SQLITE_SqlTrace HI(0x0100000) /* Debug print SQL as it executes */
+#define SQLITE_VdbeListing HI(0x0200000) /* Debug listings of VDBE progs */
+#define SQLITE_VdbeTrace HI(0x0400000) /* True to trace VDBE execution */
+#define SQLITE_VdbeAddopTrace HI(0x0800000) /* Trace sqlite3VdbeAddOp() calls */
+#define SQLITE_VdbeEQP HI(0x1000000) /* Debug EXPLAIN QUERY PLAN */
+#define SQLITE_ParserTrace HI(0x2000000) /* PRAGMA parser_trace=ON */
#endif
/*
@@ -1663,6 +1664,7 @@ struct FuncDestructor {
** SQLITE_FUNC_LENGTH == OPFLAG_LENGTHARG
** SQLITE_FUNC_TYPEOF == OPFLAG_TYPEOFARG
** SQLITE_FUNC_CONSTANT == SQLITE_DETERMINISTIC from the API
+** SQLITE_FUNC_DIRECT == SQLITE_DIRECTONLY 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 */
@@ -1683,6 +1685,7 @@ struct FuncDestructor {
#define SQLITE_FUNC_OFFSET 0x8000 /* Built-in sqlite_offset() function */
#define SQLITE_FUNC_WINDOW 0x00010000 /* Built-in window-only function */
#define SQLITE_FUNC_INTERNAL 0x00040000 /* For use by NestedParse() only */
+#define SQLITE_FUNC_DIRECT 0x00080000 /* Not for use in TRIGGERs or VIEWs */
/*
** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
@@ -1796,6 +1799,7 @@ struct Savepoint {
struct Module {
const sqlite3_module *pModule; /* Callback pointers */
const char *zName; /* Name passed to create_module() */
+ int nRefModule; /* Number of pointers to this object */
void *pAux; /* pAux passed to create_module() */
void (*xDestroy)(void *); /* Module destructor function */
Table *pEpoTab; /* Eponymous table for this module */
@@ -2497,36 +2501,37 @@ struct Expr {
** EP_Agg == NC_HasAgg == SF_HasAgg
** EP_Win == NC_HasWin
*/
-#define EP_FromJoin 0x000001 /* Originates in ON/USING clause of outer join */
-#define EP_Distinct 0x000002 /* Aggregate function with DISTINCT keyword */
-#define EP_HasFunc 0x000004 /* Contains one or more functions of any kind */
-#define EP_FixedCol 0x000008 /* TK_Column with a known fixed value */
-#define EP_Agg 0x000010 /* Contains one or more aggregate functions */
-#define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */
-#define EP_DblQuoted 0x000040 /* token.z was originally in "..." */
-#define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */
-#define EP_Collate 0x000100 /* Tree contains a TK_COLLATE operator */
-#define EP_Generic 0x000200 /* Ignore COLLATE or affinity on this tree */
-#define EP_IntValue 0x000400 /* Integer value contained in u.iValue */
-#define EP_xIsSelect 0x000800 /* x.pSelect is valid (otherwise x.pList is) */
-#define EP_Skip 0x001000 /* Operator does not contribute to affinity */
-#define EP_Reduced 0x002000 /* Expr struct EXPR_REDUCEDSIZE bytes only */
-#define EP_TokenOnly 0x004000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */
-#define EP_Win 0x008000 /* Contains window functions */
-#define EP_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */
-#define EP_NoReduce 0x020000 /* Cannot EXPRDUP_REDUCE this Expr */
-#define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */
-#define EP_ConstFunc 0x080000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */
-#define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */
-#define EP_Subquery 0x200000 /* Tree contains a TK_SELECT operator */
-#define EP_Alias 0x400000 /* Is an alias for a result set column */
-#define EP_Leaf 0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */
-#define EP_WinFunc 0x1000000 /* TK_FUNCTION with Expr.y.pWin set */
-#define EP_Subrtn 0x2000000 /* Uses Expr.y.sub. TK_IN, _SELECT, or _EXISTS */
-#define EP_Quoted 0x4000000 /* TK_ID was originally quoted */
-#define EP_Static 0x8000000 /* Held in memory not obtained from malloc() */
-#define EP_IsTrue 0x10000000 /* Always has boolean value of TRUE */
-#define EP_IsFalse 0x20000000 /* Always has boolean value of FALSE */
+#define EP_FromJoin 0x000001 /* Originates in ON/USING clause of outer join */
+#define EP_Distinct 0x000002 /* Aggregate function with DISTINCT keyword */
+#define EP_HasFunc 0x000004 /* Contains one or more functions of any kind */
+#define EP_FixedCol 0x000008 /* TK_Column with a known fixed value */
+#define EP_Agg 0x000010 /* Contains one or more aggregate functions */
+#define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */
+#define EP_DblQuoted 0x000040 /* token.z was originally in "..." */
+#define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */
+#define EP_Collate 0x000100 /* Tree contains a TK_COLLATE operator */
+#define EP_Generic 0x000200 /* Ignore COLLATE or affinity on this tree */
+#define EP_IntValue 0x000400 /* Integer value contained in u.iValue */
+#define EP_xIsSelect 0x000800 /* x.pSelect is valid (otherwise x.pList is) */
+#define EP_Skip 0x001000 /* Operator does not contribute to affinity */
+#define EP_Reduced 0x002000 /* Expr struct EXPR_REDUCEDSIZE bytes only */
+#define EP_TokenOnly 0x004000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */
+#define EP_Win 0x008000 /* Contains window functions */
+#define EP_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */
+#define EP_NoReduce 0x020000 /* Cannot EXPRDUP_REDUCE this Expr */
+#define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */
+#define EP_ConstFunc 0x080000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */
+#define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */
+#define EP_Subquery 0x200000 /* Tree contains a TK_SELECT operator */
+#define EP_Alias 0x400000 /* Is an alias for a result set column */
+#define EP_Leaf 0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */
+#define EP_WinFunc 0x1000000 /* TK_FUNCTION with Expr.y.pWin set */
+#define EP_Subrtn 0x2000000 /* Uses Expr.y.sub. TK_IN, _SELECT, or _EXISTS */
+#define EP_Quoted 0x4000000 /* TK_ID was originally quoted */
+#define EP_Static 0x8000000 /* Held in memory not obtained from malloc() */
+#define EP_IsTrue 0x10000000 /* Always has boolean value of TRUE */
+#define EP_IsFalse 0x20000000 /* Always has boolean value of FALSE */
+#define EP_Indirect 0x40000000 /* Contained within a TRIGGER or a VIEW */
/*
** The EP_Propagate mask is a set of properties that automatically propagate
@@ -3612,6 +3617,7 @@ void sqlite3WindowUnlinkFromSelect(Window*);
void sqlite3WindowListDelete(sqlite3 *db, Window *p);
Window *sqlite3WindowAlloc(Parse*, int, int, Expr*, int , Expr*, u8);
void sqlite3WindowAttach(Parse*, Expr*, Window*);
+void sqlite3WindowLink(Select *pSel, Window *pWin);
int sqlite3WindowCompare(Parse*, Window*, Window*, int);
void sqlite3WindowCodeInit(Parse*, Window*);
void sqlite3WindowCodeStep(Parse*, Select*, WhereInfo*, int, int);
@@ -4439,6 +4445,7 @@ void sqlite3AutoLoadExtensions(sqlite3*);
# define sqlite3VtabInSync(db) 0
# define sqlite3VtabLock(X)
# define sqlite3VtabUnlock(X)
+# define sqlite3VtabModuleUnref(D,X)
# define sqlite3VtabUnlockList(X)
# define sqlite3VtabSavepoint(X, Y, Z) SQLITE_OK
# define sqlite3GetVTable(X,Y) ((VTable*)0)
@@ -4450,6 +4457,7 @@ void sqlite3AutoLoadExtensions(sqlite3*);
int sqlite3VtabCommit(sqlite3 *db);
void sqlite3VtabLock(VTable *);
void sqlite3VtabUnlock(VTable *);
+ void sqlite3VtabModuleUnref(sqlite3*,Module*);
void sqlite3VtabUnlockList(sqlite3*);
int sqlite3VtabSavepoint(sqlite3 *, int, int);
void sqlite3VtabImportErrmsg(Vdbe*, sqlite3_vtab*);
diff --git a/src/tclsqlite.c b/src/tclsqlite.c
index a78d5676c..80a057262 100644
--- a/src/tclsqlite.c
+++ b/src/tclsqlite.c
@@ -1917,33 +1917,33 @@ static int SQLITE_TCLAPI DbObjCmd(
"authorizer", "backup", "bind_fallback",
"busy", "cache", "changes",
"close", "collate", "collation_needed",
- "commit_hook", "complete", "copy",
- "deserialize", "enable_load_extension", "errorcode",
- "eval", "exists", "function",
- "incrblob", "interrupt", "last_insert_rowid",
- "nullvalue", "onecolumn", "preupdate",
- "profile", "progress", "rekey",
- "restore", "rollback_hook", "serialize",
- "status", "timeout", "total_changes",
- "trace", "trace_v2", "transaction",
- "unlock_notify", "update_hook", "version",
- "wal_hook", 0
+ "commit_hook", "complete", "config",
+ "copy", "deserialize", "enable_load_extension",
+ "errorcode", "eval", "exists",
+ "function", "incrblob", "interrupt",
+ "last_insert_rowid", "nullvalue", "onecolumn",
+ "preupdate", "profile", "progress",
+ "rekey", "restore", "rollback_hook",
+ "serialize", "status", "timeout",
+ "total_changes", "trace", "trace_v2",
+ "transaction", "unlock_notify", "update_hook",
+ "version", "wal_hook", 0
};
enum DB_enum {
DB_AUTHORIZER, DB_BACKUP, DB_BIND_FALLBACK,
DB_BUSY, DB_CACHE, DB_CHANGES,
DB_CLOSE, DB_COLLATE, DB_COLLATION_NEEDED,
- DB_COMMIT_HOOK, DB_COMPLETE, DB_COPY,
- DB_DESERIALIZE, DB_ENABLE_LOAD_EXTENSION,DB_ERRORCODE,
- DB_EVAL, DB_EXISTS, DB_FUNCTION,
- DB_INCRBLOB, DB_INTERRUPT, DB_LAST_INSERT_ROWID,
- DB_NULLVALUE, DB_ONECOLUMN, DB_PREUPDATE,
- DB_PROFILE, DB_PROGRESS, DB_REKEY,
- DB_RESTORE, DB_ROLLBACK_HOOK, DB_SERIALIZE,
- DB_STATUS, DB_TIMEOUT, DB_TOTAL_CHANGES,
- DB_TRACE, DB_TRACE_V2, DB_TRANSACTION,
- DB_UNLOCK_NOTIFY, DB_UPDATE_HOOK, DB_VERSION,
- DB_WAL_HOOK
+ DB_COMMIT_HOOK, DB_COMPLETE, DB_CONFIG,
+ DB_COPY, DB_DESERIALIZE, DB_ENABLE_LOAD_EXTENSION,
+ DB_ERRORCODE, DB_EVAL, DB_EXISTS,
+ DB_FUNCTION, DB_INCRBLOB, DB_INTERRUPT,
+ DB_LAST_INSERT_ROWID, DB_NULLVALUE, DB_ONECOLUMN,
+ DB_PREUPDATE, DB_PROFILE, DB_PROGRESS,
+ DB_REKEY, DB_RESTORE, DB_ROLLBACK_HOOK,
+ DB_SERIALIZE, DB_STATUS, DB_TIMEOUT,
+ DB_TOTAL_CHANGES, DB_TRACE, DB_TRACE_V2,
+ DB_TRANSACTION, DB_UNLOCK_NOTIFY, DB_UPDATE_HOOK,
+ DB_VERSION, DB_WAL_HOOK
};
/* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */
@@ -2331,6 +2331,74 @@ static int SQLITE_TCLAPI DbObjCmd(
break;
}
+ /* $db config ?OPTION? ?BOOLEAN?
+ **
+ ** Configure the database connection using the sqlite3_db_config()
+ ** interface.
+ */
+ case DB_CONFIG: {
+ static const struct DbConfigChoices {
+ const char *zName;
+ int op;
+ } aDbConfig[] = {
+ { "enable_fkey", SQLITE_DBCONFIG_ENABLE_FKEY },
+ { "enable_trigger", SQLITE_DBCONFIG_ENABLE_TRIGGER },
+ { "enable_view", SQLITE_DBCONFIG_ENABLE_VIEW },
+ { "fts3_tokenizer", SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER },
+ { "load_extension", SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION },
+ { "no_ckpt_on_close", SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE },
+ { "enable_qpsg", SQLITE_DBCONFIG_ENABLE_QPSG },
+ { "trigger_eqp", SQLITE_DBCONFIG_TRIGGER_EQP },
+ { "reset_database", SQLITE_DBCONFIG_RESET_DATABASE },
+ { "defensive", SQLITE_DBCONFIG_DEFENSIVE },
+ { "writable_schema", SQLITE_DBCONFIG_WRITABLE_SCHEMA },
+ { "legacy_alter_table", SQLITE_DBCONFIG_LEGACY_ALTER_TABLE },
+ { "dqs_dml", SQLITE_DBCONFIG_DQS_DML },
+ { "dqs_ddl", SQLITE_DBCONFIG_DQS_DDL },
+ };
+ Tcl_Obj *pResult;
+ int ii;
+ if( objc>4 ){
+ Tcl_WrongNumArgs(interp, 2, objv, "?OPTION? ?BOOLEAN?");
+ return TCL_ERROR;
+ }
+ if( objc==2 ){
+ /* With no arguments, list all configuration options and with the
+ ** current value */
+ pResult = Tcl_NewListObj(0,0);
+ for(ii=0; ii<sizeof(aDbConfig)/sizeof(aDbConfig[0]); ii++){
+ int v = 0;
+ sqlite3_db_config(pDb->db, aDbConfig[ii].op, -1, &v);
+ Tcl_ListObjAppendElement(interp, pResult,
+ Tcl_NewStringObj(aDbConfig[ii].zName,-1));
+ Tcl_ListObjAppendElement(interp, pResult,
+ Tcl_NewIntObj(v));
+ }
+ }else{
+ const char *zOpt = Tcl_GetString(objv[2]);
+ int onoff = -1;
+ int v = 0;
+ if( zOpt[0]=='-' ) zOpt++;
+ for(ii=0; ii<sizeof(aDbConfig)/sizeof(aDbConfig[0]); ii++){
+ if( strcmp(aDbConfig[ii].zName, zOpt)==0 ) break;
+ }
+ if( ii>=sizeof(aDbConfig)/sizeof(aDbConfig[0]) ){
+ Tcl_AppendResult(interp, "unknown config option: \"", zOpt,
+ "\"", (void*)0);
+ return TCL_ERROR;
+ }
+ if( objc==4 ){
+ if( Tcl_GetBooleanFromObj(interp, objv[3], &onoff) ){
+ return TCL_ERROR;
+ }
+ }
+ sqlite3_db_config(pDb->db, aDbConfig[ii].op, onoff, &v);
+ pResult = Tcl_NewIntObj(v);
+ }
+ Tcl_SetObjResult(interp, pResult);
+ break;
+ }
+
/* $db copy conflict-algorithm table filename ?SEPARATOR? ?NULLINDICATOR?
**
** Copy data into table from filename, optionally using SEPARATOR
@@ -2741,10 +2809,16 @@ deserialize_error:
}
/*
- ** $db function NAME [-argcount N] [-deterministic] SCRIPT
+ ** $db function NAME [OPTIONS] SCRIPT
**
** Create a new SQL function called NAME. Whenever that function is
** called, invoke SCRIPT to evaluate the function.
+ **
+ ** Options:
+ ** --argcount N Function has exactly N arguments
+ ** --deterministic The function is pure
+ ** --directonly Prohibit use inside triggers and views
+ ** --returntype TYPE Specify the return type of the function
*/
case DB_FUNCTION: {
int flags = SQLITE_UTF8;
@@ -2777,6 +2851,9 @@ deserialize_error:
if( n>1 && strncmp(z, "-deterministic",n)==0 ){
flags |= SQLITE_DETERMINISTIC;
}else
+ if( n>1 && strncmp(z, "-directonly",n)==0 ){
+ flags |= SQLITE_DIRECTONLY;
+ }else
if( n>1 && strncmp(z, "-returntype", n)==0 ){
const char *azType[] = {"integer", "real", "text", "blob", "any", 0};
assert( SQLITE_INTEGER==1 && SQLITE_FLOAT==2 && SQLITE_TEXT==3 );
@@ -2792,7 +2869,8 @@ deserialize_error:
eType++;
}else{
Tcl_AppendResult(interp, "bad option \"", z,
- "\": must be -argcount, -deterministic or -returntype", (char*)0
+ "\": must be -argcount, -deterministic, -directonly,"
+ " or -returntype", (char*)0
);
return TCL_ERROR;
}
diff --git a/src/treeview.c b/src/treeview.c
index 753f21489..6dfdccd7e 100644
--- a/src/treeview.c
+++ b/src/treeview.c
@@ -557,10 +557,10 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
#endif
}
if( pExpr->op==TK_AGG_FUNCTION ){
- sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q",
- pExpr->op2, pExpr->u.zToken);
+ sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q%s",
+ pExpr->op2, pExpr->u.zToken, zFlgs);
}else{
- sqlite3TreeViewLine(pView, "FUNCTION %Q", pExpr->u.zToken);
+ sqlite3TreeViewLine(pView, "FUNCTION %Q%s", pExpr->u.zToken, zFlgs);
}
if( pFarg ){
sqlite3TreeViewExprList(pView, pFarg, pWin!=0, 0);
diff --git a/src/vtab.c b/src/vtab.c
index 41e26ef62..a711a7be5 100644
--- a/src/vtab.c
+++ b/src/vtab.c
@@ -32,6 +32,9 @@ struct VtabCtx {
** Construct and install a Module object for a virtual table. When this
** routine is called, it is guaranteed that all appropriate locks are held
** and the module is not already part of the connection.
+**
+** If there already exists a module with zName, replace it with the new one.
+** If pModule==0, then delete the module zName if it exists.
*/
Module *sqlite3VtabCreateModule(
sqlite3 *db, /* Database in which module is registered */
@@ -41,25 +44,35 @@ Module *sqlite3VtabCreateModule(
void (*xDestroy)(void *) /* Module destructor function */
){
Module *pMod;
- int nName = sqlite3Strlen30(zName);
- pMod = (Module *)sqlite3Malloc(sizeof(Module) + nName + 1);
- if( pMod==0 ){
- sqlite3OomFault(db);
+ Module *pDel;
+ char *zCopy;
+ if( pModule==0 ){
+ zCopy = (char*)zName;
+ pMod = 0;
}else{
- Module *pDel;
- char *zCopy = (char *)(&pMod[1]);
+ int nName = sqlite3Strlen30(zName);
+ pMod = (Module *)sqlite3Malloc(sizeof(Module) + nName + 1);
+ if( pMod==0 ){
+ sqlite3OomFault(db);
+ return 0;
+ }
+ zCopy = (char *)(&pMod[1]);
memcpy(zCopy, zName, nName+1);
pMod->zName = zCopy;
pMod->pModule = pModule;
pMod->pAux = pAux;
pMod->xDestroy = xDestroy;
pMod->pEpoTab = 0;
- pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,(void*)pMod);
- assert( pDel==0 || pDel==pMod );
- if( pDel ){
+ pMod->nRefModule = 1;
+ }
+ pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,(void*)pMod);
+ if( pDel ){
+ if( pDel==pMod ){
sqlite3OomFault(db);
sqlite3DbFree(db, pDel);
pMod = 0;
+ }else{
+ sqlite3VtabModuleUnref(db, pDel);
}
}
return pMod;
@@ -80,11 +93,7 @@ static int createModule(
int rc = SQLITE_OK;
sqlite3_mutex_enter(db->mutex);
- if( sqlite3HashFind(&db->aModule, zName) ){
- rc = SQLITE_MISUSE_BKPT;
- }else{
- (void)sqlite3VtabCreateModule(db, zName, pModule, pAux, xDestroy);
- }
+ (void)sqlite3VtabCreateModule(db, zName, pModule, pAux, xDestroy);
rc = sqlite3ApiExit(db, rc);
if( rc!=SQLITE_OK && xDestroy ) xDestroy(pAux);
sqlite3_mutex_leave(db->mutex);
@@ -124,6 +133,22 @@ int sqlite3_create_module_v2(
}
/*
+** Decrement the reference count on a Module object. Destroy the
+** module when the reference count reaches zero.
+*/
+void sqlite3VtabModuleUnref(sqlite3 *db, Module *pMod){
+ assert( pMod->nRefModule>0 );
+ pMod->nRefModule--;
+ if( pMod->nRefModule==0 ){
+ if( pMod->xDestroy ){
+ pMod->xDestroy(pMod->pAux);
+ }
+ assert( pMod->pEpoTab==0 );
+ sqlite3DbFree(db, pMod);
+ }
+}
+
+/*
** Lock the virtual table so that it cannot be disconnected.
** Locks nest. Every lock should have a corresponding unlock.
** If an unlock is omitted, resources leaks will occur.
@@ -162,6 +187,7 @@ void sqlite3VtabUnlock(VTable *pVTab){
pVTab->nRef--;
if( pVTab->nRef==0 ){
sqlite3_vtab *p = pVTab->pVtab;
+ sqlite3VtabModuleUnref(pVTab->db, pVTab->pMod);
if( p ){
p->pModule->xDisconnect(p);
}
@@ -566,6 +592,7 @@ static int vtabCallConstructor(
** the sqlite3_vtab object if successful. */
memset(pVTable->pVtab, 0, sizeof(pVTable->pVtab[0]));
pVTable->pVtab->pModule = pMod->pModule;
+ pMod->nRefModule++;
pVTable->nRef = 1;
if( sCtx.bDeclared==0 ){
const char *zFormat = "vtable constructor did not declare schema: %s";
diff --git a/src/where.c b/src/where.c
index 663dcdc4e..37eca3b7e 100644
--- a/src/where.c
+++ b/src/where.c
@@ -2670,6 +2670,7 @@ static int whereLoopAddBtreeIndex(
** it to pNew->rRun, which is currently set to the cost of the index
** seek only. Then, if this is a non-covering index, add the cost of
** visiting the rows in the main table. */
+ assert( pSrc->pTab->szTabRow>0 );
rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow;
pNew->rRun = sqlite3LogEstAdd(rLogSize, rCostIdx);
if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){
diff --git a/src/window.c b/src/window.c
index 287bb114c..b3a7cee1b 100644
--- a/src/window.c
+++ b/src/window.c
@@ -1230,6 +1230,25 @@ void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){
}
/*
+** Possibly link window pWin into the list at pSel->pWin (window functions
+** to be processed as part of SELECT statement pSel). The window is linked
+** in if either (a) there are no other windows already linked to this
+** SELECT, or (b) the windows already linked use a compatible window frame.
+*/
+void sqlite3WindowLink(Select *pSel, Window *pWin){
+ if( 0==pSel->pWin
+ || 0==sqlite3WindowCompare(0, pSel->pWin, pWin, 0)
+ ){
+ pWin->pNextWin = pSel->pWin;
+ if( pSel->pWin ){
+ pSel->pWin->ppThis = &pWin->pNextWin;
+ }
+ pSel->pWin = pWin;
+ pWin->ppThis = &pSel->pWin;
+ }
+}
+
+/*
** Return 0 if the two window objects are identical, or non-zero otherwise.
** Identical window objects can be processed in a single scan.
*/
@@ -1416,6 +1435,8 @@ static void windowAggStep(
int nArg = windowArgCount(pWin);
int i;
+ assert( bInverse==0 || pWin->eStart!=TK_UNBOUNDED );
+
for(i=0; i<nArg; i++){
if( i!=1 || pFunc->zName!=nth_valueName ){
sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+i, reg+i);