Index: VERSION
==================================================================
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
-3.30.0
+3.30.1
Index: configure
==================================================================
--- configure
+++ configure
@@ -1,8 +1,8 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for sqlite 3.30.0.
+# Generated by GNU Autoconf 2.69 for sqlite 3.30.1.
#
#
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
#
#
@@ -724,12 +724,12 @@
MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='sqlite'
PACKAGE_TARNAME='sqlite'
-PACKAGE_VERSION='3.30.0'
-PACKAGE_STRING='sqlite 3.30.0'
+PACKAGE_VERSION='3.30.1'
+PACKAGE_STRING='sqlite 3.30.1'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
# Factoring default headers for most tests.
ac_includes_default="\
@@ -1464,11 +1464,11 @@
#
if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures sqlite 3.30.0 to adapt to many kinds of systems.
+\`configure' configures sqlite 3.30.1 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
To assign environment variables (e.g., CC, CFLAGS...), specify them as
VAR=VALUE. See below for descriptions of some of the useful variables.
@@ -1529,11 +1529,11 @@
_ACEOF
fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of sqlite 3.30.0:";;
+ short | recursive ) echo "Configuration of sqlite 3.30.1:";;
esac
cat <<\_ACEOF
Optional Features:
--disable-option-checking ignore unrecognized --enable/--with options
@@ -1655,11 +1655,11 @@
fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-sqlite configure 3.30.0
+sqlite configure 3.30.1
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
This configure script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it.
@@ -2074,11 +2074,11 @@
} # ac_fn_c_check_header_mongrel
cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by sqlite $as_me 3.30.0, which was
+It was created by sqlite $as_me 3.30.1, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
_ACEOF
@@ -12230,11 +12230,11 @@
cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# Save the log message, to keep $0 and so on meaningful, and to
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by sqlite $as_me 3.30.0, which was
+This file was extended by sqlite $as_me 3.30.1, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
CONFIG_HEADERS = $CONFIG_HEADERS
CONFIG_LINKS = $CONFIG_LINKS
@@ -12296,11 +12296,11 @@
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-sqlite config.status 3.30.0
+sqlite config.status 3.30.1
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
Copyright (C) 2012 Free Software Foundation, Inc.
This config.status script is free software; the Free Software Foundation
Index: ext/fts5/test/fts5misc.test
==================================================================
--- ext/fts5/test/fts5misc.test
+++ ext/fts5/test/fts5misc.test
@@ -56,8 +56,56 @@
do_catchsql_test 1.3.3 {
SELECT a FROM t1
WHERE rank = (SELECT highlight(t1, 4, '', '') FROM t1('*reads'));
} {1 {no such cursor: 1}}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 2.0 {
+ CREATE TABLE t0(c0);
+ CREATE VIRTUAL TABLE vt0 USING fts5(c0);
+}
+do_execsql_test 2.1.1 {
+ BEGIN TRANSACTION;
+ INSERT INTO vt0(c0) VALUES ('xyz');
+}
+do_execsql_test 2.1.2 {
+ ALTER TABLE t0 ADD COLUMN c5;
+}
+do_execsql_test 2.1.3 {
+ INSERT INTO vt0(vt0) VALUES('integrity-check');
+}
+do_execsql_test 2.1.4 {
+ INSERT INTO vt0(c0) VALUES ('abc');
+ COMMIT
+}
+do_execsql_test 2.1.5 {
+ INSERT INTO vt0(vt0) VALUES('integrity-check');
+}
+
+reset_db
+do_execsql_test 2.2.1 {
+ CREATE TABLE t0(c0);
+ CREATE VIRTUAL TABLE vt0 USING fts5(c0);
+ BEGIN TRANSACTION;
+ INSERT INTO vt0(c0) VALUES ('xyz');
+}
+
+breakpoint
+do_execsql_test 2.2.2 {
+ ALTER TABLE t0 RENAME TO t1;
+}
+do_execsql_test 2.2.3 {
+ INSERT INTO vt0(vt0) VALUES('integrity-check');
+}
+do_execsql_test 2.2.4 {
+ INSERT INTO vt0(c0) VALUES ('abc');
+ COMMIT;
+}
+do_execsql_test 2.2.5 {
+ INSERT INTO vt0(vt0) VALUES('integrity-check');
+}
+
finish_test
Index: src/alter.c
==================================================================
--- src/alter.c
+++ src/alter.c
@@ -29,13 +29,12 @@
** Or, if zName is not a system table, zero is returned.
*/
static int isAlterableTable(Parse *pParse, Table *pTab){
if( 0==sqlite3StrNICmp(pTab->zName, "sqlite_", 7)
#ifndef SQLITE_OMIT_VIRTUALTABLE
- || ( (pTab->tabFlags & TF_Shadow)
- && (pParse->db->flags & SQLITE_Defensive)
- && pParse->db->nVdbeExec==0
+ || ( (pTab->tabFlags & TF_Shadow)!=0
+ && sqlite3ReadOnlyShadowTables(pParse->db)
)
#endif
){
sqlite3ErrorMsg(pParse, "table %s may not be altered", pTab->zName);
return 1;
@@ -433,10 +432,11 @@
}
if( SQLITE_OK!=isAlterableTable(pParse, pTab) ){
goto exit_begin_add_column;
}
+ sqlite3MayAbort(pParse);
assert( pTab->addColOffset>0 );
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
/* Put a copy of the Table struct in Parse.pNewTable for the
** sqlite3AddColumn() function and friends to modify. But modify
Index: src/build.c
==================================================================
--- src/build.c
+++ src/build.c
@@ -854,17 +854,18 @@
sqlite3ErrorMsg(pParse, ""); /* corruptSchema() will supply the error */
return SQLITE_ERROR;
}
}
}else{
- if( pParse->nested==0
- && 0==sqlite3StrNICmp(zName, "sqlite_", 7)
+ if( (pParse->nested==0 && 0==sqlite3StrNICmp(zName, "sqlite_", 7))
+ || (sqlite3ReadOnlyShadowTables(db) && sqlite3ShadowTableName(db, zName))
){
sqlite3ErrorMsg(pParse, "object name reserved for internal use: %s",
zName);
return SQLITE_ERROR;
}
+
}
return SQLITE_OK;
}
/*
@@ -2000,11 +2001,11 @@
** connection.
**
** zName is temporarily modified while this routine is running, but is
** restored to its original value prior to this routine returning.
*/
-static int isShadowTableName(sqlite3 *db, char *zName){
+int sqlite3ShadowTableName(sqlite3 *db, const char *zName){
char *zTail; /* Pointer to the last "_" in zName */
Table *pTab; /* Table that zName is a shadow of */
Module *pMod; /* Module for the virtual table */
zTail = strrchr(zName, '_');
@@ -2018,12 +2019,10 @@
if( pMod==0 ) return 0;
if( pMod->pModule->iVersion<3 ) return 0;
if( pMod->pModule->xShadowName==0 ) return 0;
return pMod->pModule->xShadowName(zTail+1);
}
-#else
-# define isShadowTableName(x,y) 0
#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
/*
** This routine is called to report the final ")" that terminates
** a CREATE TABLE statement.
@@ -2061,11 +2060,11 @@
}
assert( !db->mallocFailed );
p = pParse->pNewTable;
if( p==0 ) return;
- if( pSelect==0 && isShadowTableName(db, p->zName) ){
+ if( pSelect==0 && sqlite3ShadowTableName(db, p->zName) ){
p->tabFlags |= TF_Shadow;
}
/* If the db->init.busy is 1 it means we are reading the SQL off the
** "sqlite_master" or "sqlite_temp_master" table on the disk.
@@ -2743,10 +2742,41 @@
}
sqlite3VdbeAddOp4(v, OP_DropTable, iDb, 0, 0, pTab->zName, 0);
sqlite3ChangeCookie(pParse, iDb);
sqliteViewResetAll(db, iDb);
}
+
+/*
+** Return TRUE if shadow tables should be read-only in the current
+** context.
+*/
+int sqlite3ReadOnlyShadowTables(sqlite3 *db){
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( (db->flags & SQLITE_Defensive)!=0
+ && db->pVtabCtx==0
+ && db->nVdbeExec==0
+ ){
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+/*
+** Return true if it is not allowed to drop the given table
+*/
+static int tableMayNotBeDropped(sqlite3 *db, Table *pTab){
+ if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 ){
+ if( sqlite3StrNICmp(pTab->zName+7, "stat", 4)==0 ) return 0;
+ if( sqlite3StrNICmp(pTab->zName+7, "parameters", 10)==0 ) return 0;
+ return 1;
+ }
+ if( (pTab->tabFlags & TF_Shadow)!=0 && sqlite3ReadOnlyShadowTables(db) ){
+ return 1;
+ }
+ return 0;
+}
/*
** This routine is called to do the work of a DROP TABLE statement.
** pName is the name of the table to be dropped.
*/
@@ -2813,13 +2843,11 @@
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){
goto exit_drop_table;
}
}
#endif
- if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0
- && sqlite3StrNICmp(pTab->zName+7, "stat", 4)!=0
- && sqlite3StrNICmp(pTab->zName+7, "parameters", 10)!=0 ){
+ if( tableMayNotBeDropped(db, pTab) ){
sqlite3ErrorMsg(pParse, "table %s may not be dropped", pTab->zName);
goto exit_drop_table;
}
#ifndef SQLITE_OMIT_VIEW
Index: src/delete.c
==================================================================
--- src/delete.c
+++ src/delete.c
@@ -68,15 +68,11 @@
db = pParse->db;
if( (pTab->tabFlags & TF_Readonly)!=0 ){
return sqlite3WritableSchema(db)==0 && pParse->nested==0;
}
assert( pTab->tabFlags & TF_Shadow );
- return (db->flags & SQLITE_Defensive)!=0
-#ifndef SQLITE_OMIT_VIRTUALTABLE
- && db->pVtabCtx==0
-#endif
- && db->nVdbeExec==0;
+ return sqlite3ReadOnlyShadowTables(db);
}
/*
** Check to make sure the given table is writable. If it is not
** writable, generate an error message and return 1. If it is
Index: src/expr.c
==================================================================
--- src/expr.c
+++ src/expr.c
@@ -5144,18 +5144,20 @@
case TK_IS:
case TK_OR:
case TK_CASE:
case TK_IN:
case TK_FUNCTION:
+ case TK_TRUTH:
testcase( pExpr->op==TK_ISNOT );
testcase( pExpr->op==TK_ISNULL );
testcase( pExpr->op==TK_NOTNULL );
testcase( pExpr->op==TK_IS );
testcase( pExpr->op==TK_OR );
testcase( pExpr->op==TK_CASE );
testcase( pExpr->op==TK_IN );
testcase( pExpr->op==TK_FUNCTION );
+ testcase( pExpr->op==TK_TRUTH );
return WRC_Prune;
case TK_COLUMN:
if( pWalker->u.iCur==pExpr->iTable ){
pWalker->eCode = 1;
return WRC_Abort;
Index: src/loadext.c
==================================================================
--- src/loadext.c
+++ src/loadext.c
@@ -466,10 +466,12 @@
#ifndef SQLITE_OMIT_VIRTUALTABLE
sqlite3_drop_modules,
#else
0,
#endif
+ /* Version 3.31.0 and later */
+ sqlite3_hard_heap_limit64,
};
/*
** Attempt to load an SQLite extension library contained in the file
** zFile. The entry point is zProc. zProc may be 0 in which case a
Index: src/malloc.c
==================================================================
--- src/malloc.c
+++ src/malloc.c
@@ -30,23 +30,31 @@
UNUSED_PARAMETER(n);
return 0;
#endif
}
+/*
+** Default value of the hard heap limit. 0 means "no limit".
+*/
+#ifndef SQLITE_MAX_MEMORY
+# define SQLITE_MAX_MEMORY 0
+#endif
+
/*
** State information local to the memory allocation subsystem.
*/
static SQLITE_WSD struct Mem0Global {
sqlite3_mutex *mutex; /* Mutex to serialize access */
sqlite3_int64 alarmThreshold; /* The soft heap limit */
+ sqlite3_int64 hardLimit; /* The hard upper bound on memory */
/*
** True if heap is nearly "full" where "full" is defined by the
** sqlite3_soft_heap_limit() setting.
*/
int nearlyFull;
-} mem0 = { 0, 0, 0 };
+} mem0 = { 0, SQLITE_MAX_MEMORY, SQLITE_MAX_MEMORY, 0 };
#define mem0 GLOBAL(struct Mem0Global, mem0)
/*
** Return the memory allocator mutex. sqlite3_status() needs it.
@@ -72,12 +80,19 @@
return SQLITE_OK;
}
#endif
/*
-** Set the soft heap-size limit for the library. Passing a zero or
-** negative value indicates no limit.
+** Set the soft heap-size limit for the library. An argument of
+** zero disables the limit. A negative argument is a no-op used to
+** obtain the return value.
+**
+** The return value is the value of the heap limit just before this
+** interface was called.
+**
+** If the hard heap limit is enabled, then the soft heap limit cannot
+** be disabled nor raised above the hard heap limit.
*/
sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 n){
sqlite3_int64 priorLimit;
sqlite3_int64 excess;
sqlite3_int64 nUsed;
@@ -88,10 +103,13 @@
sqlite3_mutex_enter(mem0.mutex);
priorLimit = mem0.alarmThreshold;
if( n<0 ){
sqlite3_mutex_leave(mem0.mutex);
return priorLimit;
+ }
+ if( mem0.hardLimit>0 && (n>mem0.hardLimit || n==0) ){
+ n = mem0.hardLimit;
}
mem0.alarmThreshold = n;
nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
mem0.nearlyFull = (n>0 && n<=nUsed);
sqlite3_mutex_leave(mem0.mutex);
@@ -101,10 +119,41 @@
}
void sqlite3_soft_heap_limit(int n){
if( n<0 ) n = 0;
sqlite3_soft_heap_limit64(n);
}
+
+/*
+** Set the hard heap-size limit for the library. An argument of zero
+** disables the hard heap limit. A negative argument is a no-op used
+** to obtain the return value without affecting the hard heap limit.
+**
+** The return value is the value of the hard heap limit just prior to
+** calling this interface.
+**
+** Setting the hard heap limit will also activate the soft heap limit
+** and constrain the soft heap limit to be no more than the hard heap
+** limit.
+*/
+sqlite3_int64 sqlite3_hard_heap_limit64(sqlite3_int64 n){
+ sqlite3_int64 priorLimit;
+#ifndef SQLITE_OMIT_AUTOINIT
+ int rc = sqlite3_initialize();
+ if( rc ) return -1;
+#endif
+ sqlite3_mutex_enter(mem0.mutex);
+ priorLimit = mem0.hardLimit;
+ if( n>=0 ){
+ mem0.hardLimit = n;
+ if( nSQLITE_MAX_MEMORY ){
- *pp = 0;
- return;
- }
-#endif
-
sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, n);
if( mem0.alarmThreshold>0 ){
sqlite3_int64 nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
if( nUsed >= mem0.alarmThreshold - nFull ){
mem0.nearlyFull = 1;
sqlite3MallocAlarm(nFull);
+ if( mem0.hardLimit ){
+ nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
+ if( nUsed >= mem0.hardLimit - nFull ){
+ *pp = 0;
+ return;
+ }
+ }
}else{
mem0.nearlyFull = 0;
}
}
p = sqlite3GlobalConfig.m.xMalloc(nFull);
Index: src/pragma.c
==================================================================
--- src/pragma.c
+++ src/pragma.c
@@ -2077,10 +2077,31 @@
sqlite3_soft_heap_limit64(N);
}
returnSingleInt(v, sqlite3_soft_heap_limit64(-1));
break;
}
+
+ /*
+ ** PRAGMA hard_heap_limit
+ ** PRAGMA hard_heap_limit = N
+ **
+ ** Invoke sqlite3_hard_heap_limit64() to query or set the hard heap
+ ** limit. The hard heap limit can be activated or lowered by this
+ ** pragma, but not raised or deactivated. Only the
+ ** sqlite3_hard_heap_limit64() C-language API can raise or deactivate
+ ** the hard heap limit. This allows an application to set a heap limit
+ ** constraint that cannot be relaxed by an untrusted SQL script.
+ */
+ case PragTyp_HARD_HEAP_LIMIT: {
+ sqlite3_int64 N;
+ if( zRight && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK ){
+ sqlite3_int64 iPrior = sqlite3_hard_heap_limit64(-1);
+ if( N>0 && (iPrior==0 || iPrior>N) ) sqlite3_hard_heap_limit64(N);
+ }
+ returnSingleInt(v, sqlite3_hard_heap_limit64(-1));
+ break;
+ }
/*
** PRAGMA threads
** PRAGMA threads = N
**
Index: src/pragma.h
==================================================================
--- src/pragma.h
+++ src/pragma.h
@@ -19,38 +19,39 @@
#define PragTyp_DEFAULT_CACHE_SIZE 11
#define PragTyp_ENCODING 12
#define PragTyp_FOREIGN_KEY_CHECK 13
#define PragTyp_FOREIGN_KEY_LIST 14
#define PragTyp_FUNCTION_LIST 15
-#define PragTyp_INCREMENTAL_VACUUM 16
-#define PragTyp_INDEX_INFO 17
-#define PragTyp_INDEX_LIST 18
-#define PragTyp_INTEGRITY_CHECK 19
-#define PragTyp_JOURNAL_MODE 20
-#define PragTyp_JOURNAL_SIZE_LIMIT 21
-#define PragTyp_LOCK_PROXY_FILE 22
-#define PragTyp_LOCKING_MODE 23
-#define PragTyp_PAGE_COUNT 24
-#define PragTyp_MMAP_SIZE 25
-#define PragTyp_MODULE_LIST 26
-#define PragTyp_OPTIMIZE 27
-#define PragTyp_PAGE_SIZE 28
-#define PragTyp_PRAGMA_LIST 29
-#define PragTyp_SECURE_DELETE 30
-#define PragTyp_SHRINK_MEMORY 31
-#define PragTyp_SOFT_HEAP_LIMIT 32
-#define PragTyp_SYNCHRONOUS 33
-#define PragTyp_TABLE_INFO 34
-#define PragTyp_TEMP_STORE 35
-#define PragTyp_TEMP_STORE_DIRECTORY 36
-#define PragTyp_THREADS 37
-#define PragTyp_WAL_AUTOCHECKPOINT 38
-#define PragTyp_WAL_CHECKPOINT 39
-#define PragTyp_ACTIVATE_EXTENSIONS 40
-#define PragTyp_KEY 41
-#define PragTyp_LOCK_STATUS 42
-#define PragTyp_STATS 43
+#define PragTyp_HARD_HEAP_LIMIT 16
+#define PragTyp_INCREMENTAL_VACUUM 17
+#define PragTyp_INDEX_INFO 18
+#define PragTyp_INDEX_LIST 19
+#define PragTyp_INTEGRITY_CHECK 20
+#define PragTyp_JOURNAL_MODE 21
+#define PragTyp_JOURNAL_SIZE_LIMIT 22
+#define PragTyp_LOCK_PROXY_FILE 23
+#define PragTyp_LOCKING_MODE 24
+#define PragTyp_PAGE_COUNT 25
+#define PragTyp_MMAP_SIZE 26
+#define PragTyp_MODULE_LIST 27
+#define PragTyp_OPTIMIZE 28
+#define PragTyp_PAGE_SIZE 29
+#define PragTyp_PRAGMA_LIST 30
+#define PragTyp_SECURE_DELETE 31
+#define PragTyp_SHRINK_MEMORY 32
+#define PragTyp_SOFT_HEAP_LIMIT 33
+#define PragTyp_SYNCHRONOUS 34
+#define PragTyp_TABLE_INFO 35
+#define PragTyp_TEMP_STORE 36
+#define PragTyp_TEMP_STORE_DIRECTORY 37
+#define PragTyp_THREADS 38
+#define PragTyp_WAL_AUTOCHECKPOINT 39
+#define PragTyp_WAL_CHECKPOINT 40
+#define PragTyp_ACTIVATE_EXTENSIONS 41
+#define PragTyp_KEY 42
+#define PragTyp_LOCK_STATUS 43
+#define PragTyp_STATS 44
/* Property flags associated with various pragma. */
#define PragFlg_NeedSchema 0x01 /* Force schema load before running */
#define PragFlg_NoColumns 0x02 /* OP_ResultRow called with zero columns */
#define PragFlg_NoColumns1 0x04 /* zero columns if RHS argument is present */
@@ -317,10 +318,15 @@
/* ePragFlg: */ PragFlg_Result0,
/* ColNames: */ 41, 2,
/* iArg: */ 0 },
#endif
#endif
+ {/* zName: */ "hard_heap_limit",
+ /* ePragTyp: */ PragTyp_HARD_HEAP_LIMIT,
+ /* ePragFlg: */ PragFlg_Result0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#if defined(SQLITE_HAS_CODEC)
{/* zName: */ "hexkey",
/* ePragTyp: */ PragTyp_KEY,
/* ePragFlg: */ 0,
/* ColNames: */ 0, 0,
Index: src/select.c
==================================================================
--- src/select.c
+++ src/select.c
@@ -98,13 +98,13 @@
sqlite3ExprDelete(db, p->pLimit);
#ifndef SQLITE_OMIT_WINDOWFUNC
if( OK_IF_ALWAYS_TRUE(p->pWinDefn) ){
sqlite3WindowListDelete(db, p->pWinDefn);
}
-#endif
- if( OK_IF_ALWAYS_TRUE(p->pWith) ) sqlite3WithDelete(db, p->pWith);
assert( p->pWin==0 );
+#endif
+ if( OK_IF_ALWAYS_TRUE(p->pWith) ) sqlite3WithDelete(db, p->pWith);
if( bFree ) sqlite3DbFreeNN(db, p);
p = pPrior;
bFree = 1;
}
}
@@ -3501,10 +3501,18 @@
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
substSelect(pSubst, pExpr->x.pSelect, 1);
}else{
substExprList(pSubst, pExpr->x.pList);
}
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ if( ExprHasProperty(pExpr, EP_WinFunc) ){
+ Window *pWin = pExpr->y.pWin;
+ pWin->pFilter = substExpr(pSubst, pWin->pFilter);
+ substExprList(pSubst, pWin->pPartition);
+ substExprList(pSubst, pWin->pOrderBy);
+ }
+#endif
}
return pExpr;
}
static void substExprList(
SubstContext *pSubst, /* Description of the substitution */
Index: src/sqlite.h.in
==================================================================
--- src/sqlite.h.in
+++ src/sqlite.h.in
@@ -1740,10 +1740,11 @@
** ^The SQLITE_CONFIG_MEMSTATUS option takes single argument of type int,
** interpreted as a boolean, which enables or disables the collection of
** memory allocation statistics. ^(When memory allocation statistics are
** disabled, the following SQLite interfaces become non-operational:
**
+** - [sqlite3_hard_heap_limit64()]
**
- [sqlite3_memory_used()]
**
- [sqlite3_memory_highwater()]
**
- [sqlite3_soft_heap_limit64()]
**
- [sqlite3_status64()]
**
)^
@@ -6113,10 +6114,13 @@
*/
int sqlite3_db_release_memory(sqlite3*);
/*
** CAPI3REF: Impose A Limit On Heap Size
+**
+** These interfaces impose limits on the amount of heap memory that will be
+** by all database connections within a single process.
**
** ^The sqlite3_soft_heap_limit64() interface sets and/or queries the
** soft limit on the amount of heap memory that may be allocated by SQLite.
** ^SQLite strives to keep heap memory utilization below the soft heap
** limit by reducing the number of pages held in the page cache
@@ -6124,24 +6128,45 @@
** ^The soft heap limit is "soft" because even though SQLite strives to stay
** below the limit, it will exceed the limit rather than generate
** an [SQLITE_NOMEM] error. In other words, the soft heap limit
** is advisory only.
**
-** ^The return value from sqlite3_soft_heap_limit64() is the size of
-** the soft heap limit prior to the call, or negative in the case of an
+** ^The sqlite3_hard_heap_limit64(N) interface sets a hard upper bound of
+** N bytes on the amount of memory that will be allocated. ^The
+** sqlite3_hard_heap_limit64(N) interface is similar to
+** sqlite3_soft_heap_limit64(N) except that memory allocations will fail
+** when the hard heap limit is reached.
+**
+** ^The return value from both sqlite3_soft_heap_limit64() and
+** sqlite3_hard_heap_limit64() is the size of
+** the heap limit prior to the call, or negative in the case of an
** error. ^If the argument N is negative
-** then no change is made to the soft heap limit. Hence, the current
-** size of the soft heap limit can be determined by invoking
-** sqlite3_soft_heap_limit64() with a negative argument.
+** then no change is made to the heap limit. Hence, the current
+** size of heap limits can be determined by invoking
+** sqlite3_soft_heap_limit64(-1) or sqlite3_hard_heap_limit(-1).
**
-** ^If the argument N is zero then the soft heap limit is disabled.
+** ^Setting the heap limits to zero disables the heap limiter mechanism.
**
-** ^(The soft heap limit is not enforced in the current implementation
+** ^The soft heap limit may not be greater than the hard heap limit.
+** ^If the hard heap limit is enabled and if sqlite3_soft_heap_limit(N)
+** is invoked with a value of N that is greater than the hard heap limit,
+** the the soft heap limit is set to the value of the hard heap limit.
+** ^The soft heap limit is automatically enabled whenever the hard heap
+** limit is enabled. ^When sqlite3_hard_heap_limit64(N) is invoked and
+** the soft heap limit is outside the range of 1..N, then the soft heap
+** limit is set to N. ^Invoking sqlite3_soft_heap_limit64(0) when the
+** hard heap limit is enabled makes the soft heap limit equal to the
+** hard heap limit.
+**
+** The memory allocation limits can also be adjusted using
+** [PRAGMA soft_heap_limit] and [PRAGMA hard_heap_limit].
+**
+** ^(The heap limits are not enforced in the current implementation
** if one or more of following conditions are true:
**
**
-** - The soft heap limit is set to zero.
+**
- The limit value is set to zero.
**
- Memory accounting is disabled using a combination of the
** [sqlite3_config]([SQLITE_CONFIG_MEMSTATUS],...) start-time option and
** the [SQLITE_DEFAULT_MEMSTATUS] compile-time option.
**
- An alternative page cache implementation is specified using
** [sqlite3_config]([SQLITE_CONFIG_PCACHE2],...).
@@ -6148,25 +6173,15 @@
**
- The page cache allocates from its own memory pool supplied
** by [sqlite3_config]([SQLITE_CONFIG_PAGECACHE],...) rather than
** from the heap.
**
)^
**
-** Beginning with SQLite [version 3.7.3] ([dateof:3.7.3]),
-** the soft heap limit is enforced
-** regardless of whether or not the [SQLITE_ENABLE_MEMORY_MANAGEMENT]
-** compile-time option is invoked. With [SQLITE_ENABLE_MEMORY_MANAGEMENT],
-** the soft heap limit is enforced on every memory allocation. Without
-** [SQLITE_ENABLE_MEMORY_MANAGEMENT], the soft heap limit is only enforced
-** when memory is allocated by the page cache. Testing suggests that because
-** the page cache is the predominate memory user in SQLite, most
-** applications will achieve adequate soft heap limit enforcement without
-** the use of [SQLITE_ENABLE_MEMORY_MANAGEMENT].
-**
-** The circumstances under which SQLite will enforce the soft heap limit may
+** The circumstances under which SQLite will enforce the heap limits may
** changes in future releases of SQLite.
*/
sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N);
+sqlite3_int64 sqlite3_hard_heap_limit64(sqlite3_int64 N);
/*
** CAPI3REF: Deprecated Soft Heap Limit Interface
** DEPRECATED
**
Index: src/sqlite3ext.h
==================================================================
--- src/sqlite3ext.h
+++ src/sqlite3ext.h
@@ -322,10 +322,11 @@
/* Version 3.28.0 and later */
int (*stmt_isexplain)(sqlite3_stmt*);
int (*value_frombind)(sqlite3_value*);
/* Version 3.30.0 and later */
int (*drop_modules)(sqlite3*,const char**);
+ sqlite3_int64 (*hard_heap_limit64)(sqlite3_int64);
};
/*
** This is the function signature used for all extension entry points. It
** is also defined in the file "loadext.c".
@@ -616,10 +617,11 @@
/* Version 3.28.0 and later */
#define sqlite3_stmt_isexplain sqlite3_api->isexplain
#define sqlite3_value_frombind sqlite3_api->frombind
/* Version 3.30.0 and later */
#define sqlite3_drop_modules sqlite3_api->drop_modules
+#define sqlite3_hard_heap_limit64 sqlite3_api->hard_heap_limit64
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
/* This case when the file really is being compiled as a loadable
** extension */
Index: src/sqliteInt.h
==================================================================
--- src/sqliteInt.h
+++ src/sqliteInt.h
@@ -2583,13 +2583,17 @@
/*
** True if the expression passed as an argument was a function with
** an OVER() clause (a window function).
*/
-#define IsWindowFunc(p) ( \
+#ifdef SQLITE_OMIT_WINDOWFUNC
+# define IsWindowFunc(p) 0
+#else
+# define IsWindowFunc(p) ( \
ExprHasProperty((p), EP_WinFunc) && p->y.pWin->eFrmType!=TK_FILTER \
-)
+ )
+#endif
/*
** A list of expressions. Each expression may optionally have a
** name. An expr/name combination can be used in several ways, such
** as the list of "expr AS ID" fields following a "SELECT" or in the
@@ -4478,10 +4482,16 @@
const sqlite3_module*,
void*,
void(*)(void*)
);
# define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0)
+#endif
+int sqlite3ReadOnlyShadowTables(sqlite3 *db);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ int sqlite3ShadowTableName(sqlite3 *db, const char *zName);
+#else
+# define sqlite3ShadowTableName(A,B) 0
#endif
int sqlite3VtabEponymousTableInit(Parse*,Module*);
void sqlite3VtabEponymousTableClear(sqlite3*,Module*);
void sqlite3VtabMakeWritable(Parse*,Table*);
void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*, int);
Index: src/test1.c
==================================================================
--- src/test1.c
+++ src/test1.c
@@ -5523,10 +5523,37 @@
}
amt = sqlite3_soft_heap_limit64(N);
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(amt));
return TCL_OK;
}
+
+/*
+** Usage: sqlite3_hard_heap_limit ?N?
+**
+** Query or set the hard heap limit for the current thread. The
+** limit is only changed if the N is present. The previous limit
+** is returned.
+*/
+static int SQLITE_TCLAPI test_hard_heap_limit(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ sqlite3_int64 amt;
+ Tcl_WideInt N = -1;
+ if( objc!=1 && objc!=2 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "?N?");
+ return TCL_ERROR;
+ }
+ if( objc==2 ){
+ if( Tcl_GetWideIntFromObj(interp, objv[1], &N) ) return TCL_ERROR;
+ }
+ amt = sqlite3_hard_heap_limit64(N);
+ Tcl_SetObjResult(interp, Tcl_NewWideIntObj(amt));
+ return TCL_OK;
+}
/*
** Usage: sqlite3_thread_cleanup
**
** Call the sqlite3_thread_cleanup API.
@@ -7971,10 +7998,12 @@
{ "sqlite3_db_cacheflush", test_db_cacheflush, 0},
{ "sqlite3_system_errno", test_system_errno, 0},
{ "sqlite3_db_filename", test_db_filename, 0},
{ "sqlite3_db_readonly", test_db_readonly, 0},
{ "sqlite3_soft_heap_limit", test_soft_heap_limit, 0},
+ { "sqlite3_soft_heap_limit64", test_soft_heap_limit, 0},
+ { "sqlite3_hard_heap_limit64", test_hard_heap_limit, 0},
{ "sqlite3_thread_cleanup", test_thread_cleanup, 0},
{ "sqlite3_pager_refcounts", test_pager_refcounts, 0},
{ "sqlite3_load_extension", test_load_extension, 0},
{ "sqlite3_enable_load_extension", test_enable_load, 0},
Index: src/treeview.c
==================================================================
--- src/treeview.c
+++ src/treeview.c
@@ -64,11 +64,11 @@
}
if( zFormat!=0 ){
va_start(ap, zFormat);
sqlite3_str_vappendf(&acc, zFormat, ap);
va_end(ap);
- assert( acc.nChar>0 );
+ assert( acc.nChar>0 || acc.accError );
sqlite3_str_append(&acc, "\n", 1);
}
sqlite3StrAccumFinish(&acc);
fprintf(stdout,"%s", zBuf);
fflush(stdout);
Index: src/vdbe.c
==================================================================
--- src/vdbe.c
+++ src/vdbe.c
@@ -4536,27 +4536,31 @@
u64 iKey;
pIn3 = &aMem[pOp->p3];
testcase( pIn3->flags & MEM_Int );
testcase( pIn3->flags & MEM_IntReal );
+ testcase( pIn3->flags & MEM_Real );
+ testcase( (pIn3->flags & (MEM_Str|MEM_Int))==MEM_Str );
if( (pIn3->flags & (MEM_Int|MEM_IntReal))==0 ){
- /* Make sure pIn3->u.i contains a valid integer representation of
- ** the key value, but do not change the datatype of the register, as
- ** other parts of the perpared statement might be depending on the
- ** current datatype. */
- u16 origFlags = pIn3->flags;
- int isNotInt;
- applyAffinity(pIn3, SQLITE_AFF_NUMERIC, encoding);
- isNotInt = (pIn3->flags & MEM_Int)==0;
- pIn3->flags = origFlags;
- if( isNotInt ) goto jump_to_p2;
+ /* If pIn3->u.i does not contain an integer, compute iKey as the
+ ** integer value of pIn3. Jump to P2 if pIn3 cannot be converted
+ ** into an integer without loss of information. Take care to avoid
+ ** changing the datatype of pIn3, however, as it is used by other
+ ** parts of the prepared statement. */
+ Mem x = pIn3[0];
+ applyAffinity(&x, SQLITE_AFF_NUMERIC, encoding);
+ if( (x.flags & MEM_Int)==0 ) goto jump_to_p2;
+ iKey = x.u.i;
+ goto notExistsWithKey;
}
/* Fall through into OP_NotExists */
case OP_NotExists: /* jump, in3 */
pIn3 = &aMem[pOp->p3];
assert( (pIn3->flags & MEM_Int)!=0 || pOp->opcode==OP_SeekRowid );
assert( pOp->p1>=0 && pOp->p1nCursor );
+ iKey = pIn3->u.i;
+notExistsWithKey:
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
#ifdef SQLITE_DEBUG
if( pOp->opcode==OP_SeekRowid ) pC->seekOp = OP_SeekRowid;
#endif
@@ -4563,11 +4567,10 @@
assert( pC->isTable );
assert( pC->eCurType==CURTYPE_BTREE );
pCrsr = pC->uc.pCursor;
assert( pCrsr!=0 );
res = 0;
- iKey = pIn3->u.i;
rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0, &res);
assert( rc==SQLITE_OK || res==0 );
pC->movetoTarget = iKey; /* Used by OP_Delete */
pC->nullRow = 0;
pC->cacheStatus = CACHE_STALE;
Index: src/vdbeaux.c
==================================================================
--- src/vdbeaux.c
+++ src/vdbeaux.c
@@ -638,11 +638,11 @@
while( (pOp = opIterNext(&sIter))!=0 ){
int opcode = pOp->opcode;
if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename
|| opcode==OP_VDestroy
- || (opcode==OP_Function0 && pOp->p4.pFunc->funcFlags&SQLITE_FUNC_INTERNAL)
+ || (opcode==OP_ParseSchema && pOp->p4.z==0)
|| ((opcode==OP_Halt || opcode==OP_HaltIfNull)
&& ((pOp->p1)!=SQLITE_OK && pOp->p2==OE_Abort))
){
hasAbort = 1;
break;
Index: test/altertab.test
==================================================================
--- test/altertab.test
+++ test/altertab.test
@@ -544,15 +544,36 @@
do_catchsql_test 16.1 {
INSERT INTO y1_segments VALUES(1, X'1234567890');
} {1 {table y1_segments may not be modified}}
- do_catchsql_test 16.2 {
+ do_catchsql_test 16.20 {
+ DROP TABLE y1_segments;
+ } {1 {table y1_segments may not be dropped}}
+
+ do_catchsql_test 16.21 {
+ DROP TABLE y1_segments;
+ } {1 {table y1_segments may not be dropped}}
+
+ sqlite3_db_config db DEFENSIVE 0
+ do_catchsql_test 16.22 {
ALTER TABLE y1_segments RENAME TO abc;
- } {1 {table y1_segments may not be altered}}
+ } {0 {}}
+ sqlite3_db_config db DEFENSIVE 1
+ do_catchsql_test 16.23 {
+ CREATE TABLE y1_segments AS SELECT * FROM abc;
+ } {1 {object name reserved for internal use: y1_segments}}
+ do_catchsql_test 16.24 {
+ CREATE VIEW y1_segments AS SELECT * FROM abc;
+ } {1 {object name reserved for internal use: y1_segments}}
+ sqlite3_db_config db DEFENSIVE 0
+ do_catchsql_test 16.25 {
+ ALTER TABLE abc RENAME TO y1_segments;
+ } {0 {}}
+ sqlite3_db_config db DEFENSIVE 1
- do_execsql_test 16.3 {
+ do_execsql_test 16.30 {
ALTER TABLE y1 RENAME TO z1;
}
do_execsql_test 16.4 {
SELECT * FROM z1_segments;
Index: test/filter1.test
==================================================================
--- test/filter1.test
+++ test/filter1.test
@@ -161,8 +161,28 @@
SELECT a, avg(c) FILTER (WHERE b!=1) AS h FROM t1 GROUP BY a ORDER BY avg(c);
} {c 2.0 a 10.0 b 5.0}
do_execsql_test 4.4 {
SELECT a, avg(c) FILTER (WHERE b!=1) FROM t1 GROUP BY a ORDER BY 2
} {c 2.0 b 5.0 a 10.0}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 5.0 {
+ CREATE TABLE t1(a, b);
+ INSERT INTO t1 VALUES(1, 2);
+ INSERT INTO t1 VALUES(1, 3);
+}
+
+do_execsql_test 5.1 {
+ SELECT count(*) FILTER (WHERE b>2) FROM (SELECT * FROM t1)
+} {1}
+
+do_execsql_test 5.2 {
+ SELECT count(*) FILTER (WHERE b>2) OVER () FROM (SELECT * FROM t1)
+} {1 1}
+
+do_execsql_test 5.3 {
+ SELECT count(*) FILTER (WHERE b>2) OVER (ORDER BY b) FROM (SELECT * FROM t1)
+} {0 1}
finish_test
Index: test/fuzzcheck.c
==================================================================
--- test/fuzzcheck.c
+++ test/fuzzcheck.c
@@ -450,10 +450,13 @@
/* Maximum number of progress handler callbacks */
static unsigned int mxProgressCb = 2000;
/* Maximum string length in SQLite */
static int lengthLimit = 1000000;
+
+/* Limit on the amount of heap memory that can be used */
+static sqlite3_int64 heapLimit = 1000000000;
/* Maximum byte-code program length in SQLite */
static int vdbeOpLimit = 25000;
/* Maximum size of the in-memory database */
@@ -775,10 +778,11 @@
sqlite3_limit(cx.db, SQLITE_LIMIT_VDBE_OP, vdbeOpLimit);
}
if( lengthLimit>0 ){
sqlite3_limit(cx.db, SQLITE_LIMIT_LENGTH, lengthLimit);
}
+ sqlite3_hard_heap_limit64(heapLimit);
if( nDb>=20 && aDb[18]==2 && aDb[19]==2 ){
aDb[18] = aDb[19] = 1;
}
rc = sqlite3_deserialize(cx.db, "main", aDb, nDb, nDb,
@@ -1339,11 +1343,11 @@
char *zDbName = ""; /* Appreviated name of a source database */
const char *zFailCode = 0; /* Value of the TEST_FAILURE env variable */
int cellSzCkFlag = 0; /* --cell-size-check */
int sqlFuzz = 0; /* True for SQL fuzz. False for DB fuzz */
int iTimeout = 120; /* Default 120-second timeout */
- int nMem = 0; /* Memory limit */
+ int nMem = 0; /* Memory limit override */
int nMemThisDb = 0; /* Memory limit set by the CONFIG table */
char *zExpDb = 0; /* Write Databases to files in this directory */
char *zExpSql = 0; /* Write SQL to files in this directory */
void *pHeap = 0; /* Heap for use by SQLite */
int ossFuzz = 0; /* enable OSS-FUZZ testing */
@@ -1389,17 +1393,12 @@
}else
if( strcmp(z,"info")==0 ){
infoFlag = 1;
}else
if( strcmp(z,"limit-mem")==0 ){
-#if !defined(SQLITE_ENABLE_MEMSYS3) && !defined(SQLITE_ENABLE_MEMSYS5)
- fatalError("the %s option requires -DSQLITE_ENABLE_MEMSYS5 or _MEMSYS3",
- argv[i]);
-#else
if( i>=argc-1 ) fatalError("missing arguments on %s", argv[i]);
nMem = integerValue(argv[++i]);
-#endif
}else
if( strcmp(z,"limit-vdbe")==0 ){
vdbeLimitFlag = 1;
}else
if( strcmp(z,"load-sql")==0 ){
@@ -1584,18 +1583,13 @@
if( zName==0 ) continue;
if( strcmp(zName, "oss-fuzz")==0 ){
ossFuzzThisDb = sqlite3_column_int(pStmt,1);
if( verboseFlag ) printf("Config: oss-fuzz=%d\n", ossFuzzThisDb);
}
- if( strcmp(zName, "limit-mem")==0 && !nativeMalloc ){
-#if !defined(SQLITE_ENABLE_MEMSYS3) && !defined(SQLITE_ENABLE_MEMSYS5)
- fatalError("the limit-mem option requires -DSQLITE_ENABLE_MEMSYS5"
- " or _MEMSYS3");
-#else
+ if( strcmp(zName, "limit-mem")==0 ){
nMemThisDb = sqlite3_column_int(pStmt,1);
if( verboseFlag ) printf("Config: limit-mem=%d\n", nMemThisDb);
-#endif
}
}
sqlite3_finalize(pStmt);
}
@@ -1718,16 +1712,22 @@
fatalError("SQLite has memory in use before the start of testing");
}
/* Limit available memory, if requested */
sqlite3_shutdown();
- if( nMemThisDb>0 && !nativeMalloc ){
- pHeap = realloc(pHeap, nMemThisDb);
- if( pHeap==0 ){
- fatalError("failed to allocate %d bytes of heap memory", nMem);
+ if( nMemThisDb>0 && nMem==0 ){
+ if( !nativeMalloc ){
+ pHeap = realloc(pHeap, nMemThisDb);
+ if( pHeap==0 ){
+ fatalError("failed to allocate %d bytes of heap memory", nMem);
+ }
+ sqlite3_config(SQLITE_CONFIG_HEAP, pHeap, nMemThisDb, 128);
+ }else{
+ sqlite3_hard_heap_limit64((sqlite3_int64)nMemThisDb);
}
- sqlite3_config(SQLITE_CONFIG_HEAP, pHeap, nMemThisDb, 128);
+ }else{
+ sqlite3_hard_heap_limit64(0);
}
/* Disable lookaside with the --native-malloc option */
if( nativeMalloc ){
sqlite3_config(SQLITE_CONFIG_LOOKASIDE, 0, 0);
Index: test/join.test
==================================================================
--- test/join.test
+++ test/join.test
@@ -881,7 +881,29 @@
} {1 1 1 1}
do_execsql_test join-17.110 {
SELECT * FROM t1 LEFT JOIN (SELECT abs(1)+2 AS y FROM t1) ON x
WHERE NOT(y='a');
} {1 3 1 3}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test join-18.1 {
+ CREATE TABLE t0(a);
+ CREATE TABLE t1(b);
+ CREATE VIEW v0 AS SELECT a FROM t1 LEFT JOIN t0;
+ INSERT INTO t1 VALUES (1);
+} {}
+
+do_execsql_test join-18.2 {
+ SELECT * FROM v0 WHERE NOT(v0.a IS FALSE);
+} {{}}
+
+do_execsql_test join-18.3 {
+ SELECT * FROM t1 LEFT JOIN t0 WHERE NOT(a IS FALSE);
+} {1 {}}
+
+do_execsql_test join-18.4 {
+ SELECT NOT(v0.a IS FALSE) FROM v0
+} {1}
finish_test
+
Index: test/ossfuzz.c
==================================================================
--- test/ossfuzz.c
+++ test/ossfuzz.c
@@ -152,10 +152,13 @@
sqlite3_progress_handler(cx.db, 10, progress_handler, (void*)&cx);
#endif
/* Set a limit on the maximum size of a prepared statement */
sqlite3_limit(cx.db, SQLITE_LIMIT_VDBE_OP, 25000);
+
+ /* Limit total memory available to SQLite to 20MB */
+ sqlite3_hard_heap_limit64(20000000);
/* Set a limit on the maximum length of a string or BLOB. Without this
** limit, fuzzers will invoke randomblob(N) for a large N, and the process
** will timeout trying to generate the huge blob */
sqlite3_limit(cx.db, SQLITE_LIMIT_LENGTH, 50000);
Index: test/tester.tcl
==================================================================
--- test/tester.tcl
+++ test/tester.tcl
@@ -386,10 +386,11 @@
#
proc print_help_and_quit {} {
puts {Options:
--pause Wait for user input before continuing
--soft-heap-limit=N Set the soft-heap-limit to N
+ --hard-heap-limit=N Set the hard-heap-limit to N
--maxerror=N Quit after N errors
--verbose=(0|1) Control the amount of output. Default '1'
--output=FILE set --verbose=2 and output to FILE. Implies -q
-q Shorthand for --verbose=0
--help This message
@@ -406,10 +407,11 @@
# Parse any options specified in the $argv array. This script accepts the
# following options:
#
# --pause
# --soft-heap-limit=NN
+ # --hard-heap-limit=NN
# --maxerror=NN
# --malloctrace=N
# --backtrace=N
# --binarylog=N
# --soak=N
@@ -422,10 +424,11 @@
# -q Reduce output
# --testdir=$dir Run tests in subdirectory $dir
# --help
#
set cmdlinearg(soft-heap-limit) 0
+ set cmdlinearg(hard-heap-limit) 0
set cmdlinearg(maxerror) 1000
set cmdlinearg(malloctrace) 0
set cmdlinearg(backtrace) 10
set cmdlinearg(binarylog) 0
set cmdlinearg(soak) 0
@@ -448,10 +451,13 @@
gets stdin
}
{^-+soft-heap-limit=.+$} {
foreach {dummy cmdlinearg(soft-heap-limit)} [split $a =] break
}
+ {^-+hard-heap-limit=.+$} {
+ foreach {dummy cmdlinearg(hard-heap-limit)} [split $a =] break
+ }
{^-+maxerror=.+$} {
foreach {dummy cmdlinearg(maxerror)} [split $a =] break
}
{^-+malloctrace=.+$} {
foreach {dummy cmdlinearg(malloctrace)} [split $a =] break
@@ -584,11 +590,12 @@
# Update the soft-heap-limit each time this script is run. In that
# way if an individual test file changes the soft-heap-limit, it
# will be reset at the start of the next test file.
#
-sqlite3_soft_heap_limit $cmdlinearg(soft-heap-limit)
+sqlite3_soft_heap_limit64 $cmdlinearg(soft-heap-limit)
+sqlite3_hard_heap_limit64 $cmdlinearg(hard-heap-limit)
# Create a test database
#
proc reset_db {} {
catch {db close}
@@ -1205,11 +1212,12 @@
sqlite3 db {}
# sqlite3_clear_tsd_memdebug
db close
sqlite3_reset_auto_extension
- sqlite3_soft_heap_limit 0
+ sqlite3_soft_heap_limit64 0
+ sqlite3_hard_heap_limit64 0
set nTest [incr_ntest]
set nErr [set_test_counter errors]
set nKnown 0
if {[file readable known-problems.txt]} {
Index: test/window1.test
==================================================================
--- test/window1.test
+++ test/window1.test
@@ -1187,7 +1187,51 @@
WINDOW win1 AS (ORDER BY a GROUPS BETWEEN 4 PRECEDING AND 1 FOLLOWING
EXCLUDE CURRENT ROW),
win2 AS (PARTITION BY b ORDER BY a),
win3 AS (win2 RANGE BETWEEN 5.2 PRECEDING AND true PRECEDING );
} {1 1}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 31.1 {
+ CREATE TABLE t1(a, b);
+ CREATE TABLE t2(c, d);
+ CREATE TABLE t3(e, f);
+
+ INSERT INTO t1 VALUES(1, 1);
+ INSERT INTO t2 VALUES(1, 1);
+ INSERT INTO t3 VALUES(1, 1);
+}
+
+do_execsql_test 31.2 {
+ SELECT d IN (SELECT sum(c) OVER (ORDER BY e+c) FROM t3) FROM (
+ SELECT * FROM t2
+ );
+} {1}
+
+do_execsql_test 31.3 {
+ SELECT d IN (SELECT sum(c) OVER (PARTITION BY d ORDER BY e+c) FROM t3) FROM (
+ SELECT * FROM t2
+ );
+} {1}
+
+do_catchsql_test 31.3 {
+ SELECT d IN (
+ SELECT sum(c) OVER ( ROWS BETWEEN d FOLLOWING AND UNBOUNDED FOLLOWING)
+ FROM t3
+ )
+ FROM (
+ SELECT * FROM t2
+ );
+} {1 {frame starting offset must be a non-negative integer}}
+
+do_catchsql_test 31.3 {
+ SELECT d IN (
+ SELECT sum(c) OVER ( ROWS BETWEEN CURRENT ROW AND c FOLLOWING)
+ FROM t3
+ )
+ FROM (
+ SELECT * FROM t2
+ );
+} {1 {frame ending offset must be a non-negative integer}}
finish_test
Index: tool/mkpragmatab.tcl
==================================================================
--- tool/mkpragmatab.tcl
+++ tool/mkpragmatab.tcl
@@ -403,10 +403,13 @@
NAME: activate_extensions
IF: defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
NAME: soft_heap_limit
FLAG: Result0
+
+ NAME: hard_heap_limit
+ FLAG: Result0
NAME: threads
FLAG: Result0
NAME: optimize