track 3.6.13

This commit is contained in:
Stephen Lombardo 2009-04-21 10:39:00 -04:00
parent 6e36436ed9
commit 81f606f59f
171 changed files with 9146 additions and 12272 deletions

View File

@ -163,14 +163,14 @@ NAWK = @AWK@
# Object files for the SQLite library (non-amalgamation).
#
OBJS0 = alter.lo analyze.lo attach.lo auth.lo bitvec.lo btmutex.lo \
OBJS0 = alter.lo analyze.lo attach.lo auth.lo backup.lo bitvec.lo btmutex.lo \
btree.lo build.lo callback.lo complete.lo date.lo \
delete.lo expr.lo fault.lo func.lo global.lo \
hash.lo journal.lo insert.lo legacy.lo loadext.lo \
main.lo malloc.lo mem0.lo mem1.lo mem2.lo mem3.lo mem5.lo \
memjournal.lo \
mutex.lo mutex_noop.lo mutex_os2.lo mutex_unix.lo mutex_w32.lo \
opcodes.lo os.lo os_unix.lo os_win.lo os_os2.lo \
notify.lo opcodes.lo os.lo os_unix.lo os_win.lo os_os2.lo \
pager.lo parse.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.lo \
random.lo resolve.lo rowset.lo select.lo status.lo \
table.lo tokenize.lo trigger.lo update.lo \
@ -231,6 +231,7 @@ SRC = \
$(TOP)/src/mutex_os2.c \
$(TOP)/src/mutex_unix.c \
$(TOP)/src/mutex_w32.c \
$(TOP)/src/notify.c \
$(TOP)/src/os.c \
$(TOP)/src/os.h \
$(TOP)/src/os_common.h \
@ -518,6 +519,9 @@ attach.lo: $(TOP)/src/attach.c $(HDR)
auth.lo: $(TOP)/src/auth.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/auth.c
backup.lo: $(TOP)/src/backup.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/backup.c
bitvec.lo: $(TOP)/src/bitvec.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/bitvec.c
@ -608,6 +612,9 @@ mutex_unix.lo: $(TOP)/src/mutex_unix.c $(HDR)
mutex_w32.lo: $(TOP)/src/mutex_w32.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/mutex_w32.c
notify.lo: $(TOP)/src/notify.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/notify.c
pager.lo: $(TOP)/src/pager.c $(HDR) $(TOP)/src/pager.h
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/pager.c
@ -765,9 +772,11 @@ sqlite3_analyzer$(TEXE): $(TESTFIXTURE_SRC) $(TOP)/tool/spaceanal.tcl
$(TEMP_STORE) -o $@ $(TESTFIXTURE_SRC) $(LIBTCL)
install: sqlite3$(BEXE) libsqlite3.la sqlite3.h sqlite3.pc ${HAVE_TCL:1=tcl_install}
lib_install: libsqlite3.la
$(INSTALL) -d $(DESTDIR)$(libdir)
$(LTINSTALL) libsqlite3.la $(DESTDIR)$(libdir)
install: sqlite3$(BEXE) lib_install sqlite3.h sqlite3.pc ${HAVE_TCL:1=tcl_install}
$(INSTALL) -d $(DESTDIR)$(bindir)
$(LTINSTALL) sqlite3$(BEXE) $(DESTDIR)$(bindir)
$(INSTALL) -d $(DESTDIR)$(includedir)
@ -778,7 +787,7 @@ install: sqlite3$(BEXE) libsqlite3.la sqlite3.h sqlite3.pc ${HAVE_TCL:1=tcl_inst
pkgIndex.tcl:
echo 'package ifneeded sqlite3 $(RELEASE) [list load $(TCLLIBDIR)/libtclsqlite3.so sqlite3]' > $@
tcl_install: libtclsqlite3.la pkgIndex.tcl
tcl_install: lib_install libtclsqlite3.la pkgIndex.tcl
$(INSTALL) -d $(DESTDIR)$(TCLLIBDIR)
$(LTINSTALL) libtclsqlite3.la $(DESTDIR)$(TCLLIBDIR)
rm -f $(DESTDIR)$(TCLLIBDIR)/libtclsqlite3.la $(DESTDIR)$(TCLLIBDIR)/libtclsqlite3.a

View File

@ -13,7 +13,7 @@ include $(WIND_USR)/tool/gnu/make.$(FORCPU)
#### The toplevel directory of the source tree. This is the directory
# that contains this "Makefile.in" and the "configure.in" script.
#
TOP = ../sqlite-3.6.5
TOP = .
#### C Compiler and options for use in building executables that
# will run on the platform that is doing the build.
@ -42,13 +42,14 @@ THREADLIB =
#### Specify any extra libraries needed to access required functions.
#
#TLIBS = -lrt # fdatasync on Solaris 8
#for x86 vxWorks
#TLIBS += TLIBS = $(LD_LINK_PATH_ATEND) $(LD_PARTIAL_LAST_FLAGS)
#for SH4 shared library
TLIBS_SHARED += -L$(WIND_USR)/lib/sh/SH32/commonle/PIC
#TLIBS_SHARED += $(LD_LINK_PATH_ATEND) $(LD_PARTIAL_LAST_FLAGS)
#for SH4 static
ifeq ($(CPU),SH32)
# for SH4 shared library
TLIBS_SHARED += -L$(WIND_USR)/lib/sh/SH32/commonle/PIC
else
# for all other CPUs shared library
TLIBS_SHARED += $(LD_LINK_PATH_ATEND) $(LD_PARTIAL_LAST_FLAGS)
endif
# for static library
TLIBS += $(LD_LINK_PATH_ATEND) $(LD_PARTIAL_LAST_FLAGS)
#### Leave SQLITE_DEBUG undefined for maximum speed. Use SQLITE_DEBUG=1
@ -193,18 +194,18 @@ TCCX_SHARED = $(TCC_SHARED) $(OPTS) -I. -I$(TOP)/src -I$(TOP) -I$(TOP)/ext/rtree
# Object files for the SQLite library.
#
LIBOBJ+= alter.o analyze.o attach.o auth.o \
bitvec.o btmutex.o btree.o build.o \
backup.o bitvec.o btmutex.o btree.o build.o \
callback.o complete.o date.o delete.o \
expr.o fault.o func.o global.o hash.o \
icu.o insert.o journal.o legacy.o loadext.o \
main.o malloc.o mem0.o mem1.o mem2.o mem3.o mem5.o memjournal.o \
mutex.o mutex_os2.o mutex_unix.o mutex_w32.o mutex_noop.o \
opcodes.o os.o os_os2.o os_unix.o os_win.o \
pager.o parse.o pcache.o pragma.o prepare.o printf.o \
random.o resolve.o rtree.o select.o status.o \
pager.o parse.o pcache.o pcache1.o pragma.o prepare.o printf.o \
random.o resolve.o rowset.o rtree.o select.o status.o \
table.o tokenize.o trigger.o \
update.o util.o vacuum.o \
vdbe.o vdbeapi.o vdbeaux.o vdbeblob.o vdbefifo.o vdbemem.o \
vdbe.o vdbeapi.o vdbeaux.o vdbeblob.o vdbemem.o \
walker.o where.o utf.o vtab.o
@ -215,6 +216,7 @@ SRC = \
$(TOP)/src/analyze.c \
$(TOP)/src/attach.c \
$(TOP)/src/auth.c \
$(TOP)/src/backup.c \
$(TOP)/src/bitvec.c \
$(TOP)/src/btmutex.c \
$(TOP)/src/btree.c \
@ -260,12 +262,14 @@ SRC = \
$(TOP)/src/pager.h \
$(TOP)/src/parse.y \
$(TOP)/src/pcache.c \
$(TOP)/src/pcache1.c \
$(TOP)/src/pcache.h \
$(TOP)/src/pragma.c \
$(TOP)/src/prepare.c \
$(TOP)/src/printf.c \
$(TOP)/src/random.c \
$(TOP)/src/resolve.c \
$(TOP)/src/rowset.c \
$(TOP)/src/select.c \
$(TOP)/src/status.c \
$(TOP)/src/shell.c \
@ -286,7 +290,6 @@ SRC = \
$(TOP)/src/vdbeapi.c \
$(TOP)/src/vdbeaux.c \
$(TOP)/src/vdbeblob.c \
$(TOP)/src/vdbefifo.c \
$(TOP)/src/vdbemem.c \
$(TOP)/src/vdbeInt.h \
$(TOP)/src/vtab.c \
@ -316,6 +319,8 @@ SRC += \
SRC += \
$(TOP)/ext/fts3/fts3.c \
$(TOP)/ext/fts3/fts3.h \
$(TOP)/ext/fts3/fts3_expr.c \
$(TOP)/ext/fts3/fts3_expr.h \
$(TOP)/ext/fts3/fts3_hash.c \
$(TOP)/ext/fts3/fts3_hash.h \
$(TOP)/ext/fts3/fts3_icu.c \

View File

@ -1 +1 @@
3.6.11
3.6.13

539
configure vendored

File diff suppressed because it is too large Load Diff

View File

@ -89,10 +89,19 @@
#
AC_INIT(sqlite, m4_esyscmd([cat VERSION | tr -d '\n']))
dnl Make sure the local VERSION file matches this configure script
sqlite_version_sanity_check=`cat VERSION | tr -d '\n'`
if test "$PACKAGE_VERSION" != "$sqlite_version_sanity_check" ; then
AC_MSG_ERROR([configure script is out of date:
configure \$PACKAGE_VERSION = $PACKAGE_VERSION
top level VERSION file = $sqlite_version_sanity_check
please regen with autoconf])
fi
dnl Put the RCS revision string after AC_INIT so that it will also
dnl show in in configure.
# The following RCS revision string applies to configure.in
# $Revision: 1.54 $
# $Revision: 1.55 $
#########
# Programs needed

View File

@ -1214,7 +1214,7 @@ static int sql_step_statement(fulltext_vtab *v, fulltext_statement iStmt,
if( rc==SQLITE_BUSY ) continue;
if( rc!=SQLITE_ERROR ) return rc;
/* If an SQLITE_SCHEMA error has occured, then finalizing this
/* If an SQLITE_SCHEMA error has occurred, then finalizing this
* statement is going to delete the fulltext_vtab structure. If
* the statement just executed is in the pFulltextStatements[]
* array, it will be finalized twice. So remove it before

View File

@ -6249,7 +6249,7 @@ static void optimizeFunc(sqlite3_context *pContext,
i++;
}
/* If we managed to succesfully read them all, optimize them. */
/* If we managed to successfully read them all, optimize them. */
if( rc==SQLITE_DONE ){
assert( i==nReaders );
rc = optimizeInternal(v, readers, nReaders, &writer);
@ -6836,7 +6836,7 @@ int sqlite3Fts2Init(sqlite3 *db){
);
}
/* An error has occured. Delete the hash table and return the error code. */
/* An error has occurred. Delete the hash table and return the error code. */
assert( rc!=SQLITE_OK );
if( pHash ){
sqlite3Fts2HashClear(pHash);

File diff suppressed because it is too large Load Diff

View File

@ -6410,7 +6410,7 @@ static void optimizeFunc(sqlite3_context *pContext,
i++;
}
/* If we managed to succesfully read them all, optimize them. */
/* If we managed to successfully read them all, optimize them. */
if( rc==SQLITE_DONE ){
assert( i==nReaders );
rc = optimizeInternal(v, readers, nReaders, &writer);
@ -7001,7 +7001,7 @@ int sqlite3Fts3Init(sqlite3 *db){
);
}
/* An error has occured. Delete the hash table and return the error code. */
/* An error has occurred. Delete the hash table and return the error code. */
assert( rc!=SQLITE_OK );
if( pHash ){
sqlite3Fts3HashClear(pHash);

View File

@ -212,8 +212,6 @@ static int getNextString(
if( ii==0 ){
memset(p, 0, nByte);
p->pPhrase = (Fts3Phrase *)&p[1];
p->eType = FTSQUERY_PHRASE;
p->pPhrase->iColumn = pParse->iDefaultCol;
}
p->pPhrase = (Fts3Phrase *)&p[1];
p->pPhrase->nToken = ii+1;
@ -237,19 +235,25 @@ static int getNextString(
char *zNew;
int nNew = 0;
int nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase);
nByte += (p->pPhrase->nToken-1) * sizeof(struct PhraseToken);
nByte += (p?(p->pPhrase->nToken-1):0) * sizeof(struct PhraseToken);
p = fts3ReallocOrFree(p, nByte + nTemp);
if( !p ){
goto no_mem;
}
if( zTemp ){
zNew = &(((char *)p)[nByte]);
memcpy(zNew, zTemp, nTemp);
}else{
memset(p, 0, nByte+nTemp);
}
p->pPhrase = (Fts3Phrase *)&p[1];
zNew = &(((char *)p)[nByte]);
memcpy(zNew, zTemp, nTemp);
for(jj=0; jj<p->pPhrase->nToken; jj++){
p->pPhrase->aToken[jj].z = &zNew[nNew];
nNew += p->pPhrase->aToken[jj].n;
}
sqlite3_free(zTemp);
p->eType = FTSQUERY_PHRASE;
p->pPhrase->iColumn = pParse->iDefaultCol;
rc = SQLITE_OK;
}

View File

@ -59,7 +59,7 @@ LIBOBJ+= alter.o analyze.o attach.o auth.o \
main.o malloc.o mem0.o mem1.o mem2.o mem3.o mem5.o \
memjournal.o \
mutex.o mutex_noop.o mutex_os2.o mutex_unix.o mutex_w32.o \
opcodes.o os.o os_os2.o os_unix.o os_win.o \
notify.o opcodes.o os.o os_os2.o os_unix.o os_win.o \
pager.o parse.o pcache.o pcache1.o pragma.o prepare.o printf.o \
random.o resolve.o rowset.o rtree.o select.o status.o \
table.o tokenize.o trigger.o \
@ -112,6 +112,7 @@ SRC = \
$(TOP)/src/mutex_os2.c \
$(TOP)/src/mutex_unix.c \
$(TOP)/src/mutex_w32.c \
$(TOP)/src/notify.c \
$(TOP)/src/os.c \
$(TOP)/src/os.h \
$(TOP)/src/os_common.h \

View File

@ -1,150 +0,0 @@
EXPORTS
sqlite3_aggregate_context
sqlite3_aggregate_count
sqlite3_auto_extension
sqlite3_bind_blob
sqlite3_bind_double
sqlite3_bind_int
sqlite3_bind_int64
sqlite3_bind_null
sqlite3_bind_parameter_count
sqlite3_bind_parameter_index
sqlite3_bind_parameter_name
sqlite3_bind_text
sqlite3_bind_text16
sqlite3_bind_value
sqlite3_bind_zeroblob
sqlite3_blob_bytes
sqlite3_blob_close
sqlite3_blob_open
sqlite3_blob_read
sqlite3_blob_write
sqlite3_busy_handler
sqlite3_busy_timeout
sqlite3_changes
sqlite3_clear_bindings
sqlite3_close
sqlite3_collation_needed
sqlite3_collation_needed16
sqlite3_column_blob
sqlite3_column_bytes
sqlite3_column_bytes16
sqlite3_column_count
sqlite3_column_decltype
sqlite3_column_decltype16
sqlite3_column_double
sqlite3_column_int
sqlite3_column_int64
sqlite3_column_name
sqlite3_column_name16
sqlite3_column_text
sqlite3_column_text16
sqlite3_column_type
sqlite3_column_value
sqlite3_commit_hook
sqlite3_complete
sqlite3_complete16
sqlite3_create_collation
sqlite3_create_collation16
sqlite3_create_collation_v2
sqlite3_create_function
sqlite3_create_function16
sqlite3_create_module
sqlite3_create_module_v2
sqlite3_data_count
sqlite3_db_handle
sqlite3_declare_vtab
sqlite3_enable_load_extension
sqlite3_enable_shared_cache
sqlite3_errcode
sqlite3_errmsg
sqlite3_errmsg16
sqlite3_exec
sqlite3_expired
sqlite3_extended_result_codes
sqlite3_file_control
sqlite3_finalize
sqlite3_free
sqlite3_free_table
sqlite3_get_autocommit
sqlite3_get_auxdata
sqlite3_get_table
sqlite3_global_recover
sqlite3_interrupt
sqlite3_last_insert_rowid
sqlite3_libversion
sqlite3_libversion_number
sqlite3_load_extension
sqlite3_malloc
sqlite3_memory_alarm
sqlite3_memory_highwater
sqlite3_memory_used
sqlite3_mprintf
sqlite3_mutex_alloc
sqlite3_mutex_enter
sqlite3_mutex_free
sqlite3_mutex_leave
sqlite3_mutex_try
sqlite3_open
sqlite3_open16
sqlite3_open_v2
sqlite3_overload_function
sqlite3_prepare
sqlite3_prepare16
sqlite3_prepare16_v2
sqlite3_prepare_v2
sqlite3_profile
sqlite3_progress_handler
sqlite3_randomness
sqlite3_realloc
sqlite3_release_memory
sqlite3_reset
sqlite3_reset_auto_extension
sqlite3_result_blob
sqlite3_result_double
sqlite3_result_error
sqlite3_result_error16
sqlite3_result_error_code
sqlite3_result_error_nomem
sqlite3_result_error_toobig
sqlite3_result_int
sqlite3_result_int64
sqlite3_result_null
sqlite3_result_text
sqlite3_result_text16
sqlite3_result_text16be
sqlite3_result_text16le
sqlite3_result_value
sqlite3_result_zeroblob
sqlite3_rollback_hook
sqlite3_set_authorizer
sqlite3_set_auxdata
sqlite3_sleep
sqlite3_snprintf
sqlite3_soft_heap_limit
sqlite3_sql
sqlite3_step
sqlite3_test_control
sqlite3_thread_cleanup
sqlite3_threadsafe
sqlite3_total_changes
sqlite3_trace
sqlite3_transfer_bindings
sqlite3_update_hook
sqlite3_user_data
sqlite3_value_blob
sqlite3_value_bytes
sqlite3_value_bytes16
sqlite3_value_double
sqlite3_value_int
sqlite3_value_int64
sqlite3_value_numeric_type
sqlite3_value_text
sqlite3_value_text16
sqlite3_value_text16be
sqlite3_value_text16le
sqlite3_value_type
sqlite3_vfs_find
sqlite3_vfs_register
sqlite3_vfs_unregister
sqlite3_vmprintf

View File

@ -12,7 +12,7 @@
** This file contains C code routines that used to generate VDBE code
** that implements the ALTER TABLE command.
**
** $Id: alter.c,v 1.53 2009/02/13 03:43:32 drh Exp $
** $Id: alter.c,v 1.55 2009/03/24 15:08:10 drh Exp $
*/
#include "sqliteInt.h"
@ -193,7 +193,7 @@ static char *whereTempTriggers(Parse *pParse, Table *pTab){
*/
if( pTab->pSchema!=pTempSchema ){
sqlite3 *db = pParse->db;
for( pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext ){
for(pTrig=sqlite3TriggerList(pParse, pTab); pTrig; pTrig=pTrig->pNext){
if( pTrig->pSchema==pTempSchema ){
if( !zWhere ){
zWhere = sqlite3MPrintf(db, "name=%Q", pTrig->name);
@ -232,7 +232,7 @@ static void reloadTableSchema(Parse *pParse, Table *pTab, const char *zName){
#ifndef SQLITE_OMIT_TRIGGER
/* Drop any table triggers from the internal schema. */
for(pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext){
for(pTrig=sqlite3TriggerList(pParse, pTab); pTrig; pTrig=pTrig->pNext){
int iTrigDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema);
assert( iTrigDb==iDb || iTrigDb==1 );
sqlite3VdbeAddOp4(v, OP_DropTrigger, iTrigDb, 0, 0, pTrig->name, 0);
@ -593,7 +593,7 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
if( !pNew ) goto exit_begin_add_column;
pParse->pNewTable = pNew;
pNew->nRef = 1;
pNew->db = db;
pNew->dbMem = pTab->dbMem;
pNew->nCol = pTab->nCol;
assert( pNew->nCol>0 );
nAlloc = (((pNew->nCol-1)/8)*8)+8;

View File

@ -11,7 +11,7 @@
*************************************************************************
** This file contains code associated with the ANALYZE command.
**
** @(#) $Id: analyze.c,v 1.48 2009/02/13 16:59:53 drh Exp $
** @(#) $Id: analyze.c,v 1.51 2009/02/28 10:47:42 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_ANALYZE
#include "sqliteInt.h"
@ -74,8 +74,8 @@ static void openStatTable(
if( !createStat1 ){
sqlite3TableLock(pParse, iDb, iRootPage, 1, "sqlite_stat1");
}
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, 3);
sqlite3VdbeAddOp3(v, OP_OpenWrite, iStatCur, iRootPage, iDb);
sqlite3VdbeChangeP4(v, -1, (char *)3, P4_INT32);
sqlite3VdbeChangeP5(v, createStat1);
}
@ -117,7 +117,7 @@ static void analyzeOneTable(
/* Establish a read-lock on the table at the shared-cache level. */
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
iIdxCur = pParse->nTab;
iIdxCur = pParse->nTab++;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
int regFields; /* Register block for building records */
@ -131,7 +131,6 @@ static void analyzeOneTable(
*/
assert( iDb==sqlite3SchemaToIndex(pParse->db, pIdx->pSchema) );
nCol = pIdx->nColumn;
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, nCol+1);
sqlite3VdbeAddOp4(v, OP_OpenRead, iIdxCur, pIdx->tnum, iDb,
(char *)pKey, P4_KEYINFO_HANDOFF);
VdbeComment((v, "%s", pIdx->zName));
@ -189,7 +188,7 @@ static void analyzeOneTable(
** The result is a single row of the sqlite_stat1 table. The first
** two columns are the names of the table and index. The third column
** is a string composed of a list of integer statistics about the
** index. The first integer in the list is the total number of entires
** index. The first integer in the list is the total number of entries
** in the index. There is one additional integer in the list for each
** column of the table. This additional integer is a guess of how many
** rows of the table the index will select. If D is the count of distinct

View File

@ -11,7 +11,7 @@
*************************************************************************
** This file contains code used to implement the ATTACH and DETACH commands.
**
** $Id: attach.c,v 1.82 2009/02/03 16:51:25 danielk1977 Exp $
** $Id: attach.c,v 1.84 2009/04/08 13:51:51 drh Exp $
*/
#include "sqliteInt.h"
@ -488,11 +488,11 @@ int sqlite3FixExpr(
Expr *pExpr /* The expression to be fixed to one database */
){
while( pExpr ){
if( sqlite3FixSelect(pFix, pExpr->pSelect) ){
return 1;
}
if( sqlite3FixExprList(pFix, pExpr->pList) ){
return 1;
if( ExprHasAnyProperty(pExpr, EP_TokenOnly|EP_SpanToken) ) break;
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
if( sqlite3FixSelect(pFix, pExpr->x.pSelect) ) return 1;
}else{
if( sqlite3FixExprList(pFix, pExpr->x.pList) ) return 1;
}
if( sqlite3FixExpr(pFix, pExpr->pRight) ){
return 1;

View File

@ -12,7 +12,7 @@
** This file contains the implementation of the sqlite3_backup_XXX()
** API functions and the related features.
**
** $Id: backup.c,v 1.12 2009/02/16 17:55:47 shane Exp $
** $Id: backup.c,v 1.13 2009/03/16 13:19:36 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "btreeInt.h"
@ -292,10 +292,10 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
int bCloseTrans = 0; /* True if src db requires unlocking */
/* If the source pager is currently in a write-transaction, return
** SQLITE_LOCKED immediately.
** SQLITE_BUSY immediately.
*/
if( p->pDestDb && p->pSrc->pBt->inTransaction==TRANS_WRITE ){
rc = SQLITE_LOCKED;
rc = SQLITE_BUSY;
}else{
rc = SQLITE_OK;
}

View File

@ -34,7 +34,7 @@
** start of a transaction, and is thus usually less than a few thousand,
** but can be as large as 2 billion for a really big database.
**
** @(#) $Id: bitvec.c,v 1.13 2009/01/20 17:06:27 danielk1977 Exp $
** @(#) $Id: bitvec.c,v 1.14 2009/04/01 23:49:04 drh Exp $
*/
#include "sqliteInt.h"
@ -94,8 +94,9 @@
*/
struct Bitvec {
u32 iSize; /* Maximum bit index. Max iSize is 4,294,967,296. */
u32 nSet; /* Number of bits that are set - only valid for aHash element */
/* Max nSet is BITVEC_NINT. For BITVEC_SZ of 512, this would be 125. */
u32 nSet; /* Number of bits that are set - only valid for aHash
** element. Max is BITVEC_NINT. For BITVEC_SZ of 512,
** this would be 125. */
u32 iDivisor; /* Number of bits handled by each apSub[] entry. */
/* Should >=0 for apSub element. */
/* Max iDivisor is max(u32) / BITVEC_NPTR + 1. */
@ -377,7 +378,8 @@ int sqlite3BitvecBuiltinTest(int sz, int *aOp){
** is found.
*/
rc = sqlite3BitvecTest(0,0) + sqlite3BitvecTest(pBitvec, sz+1)
+ sqlite3BitvecTest(pBitvec, 0);
+ sqlite3BitvecTest(pBitvec, 0)
+ (sqlite3BitvecSize(pBitvec) - sz);
for(i=1; i<=sz; i++){
if( (TESTBIT(pV,i))!=sqlite3BitvecTest(pBitvec,i) ){
rc = i;

View File

@ -10,7 +10,7 @@
**
*************************************************************************
**
** $Id: btmutex.c,v 1.12 2008/11/17 19:18:55 danielk1977 Exp $
** $Id: btmutex.c,v 1.15 2009/04/10 12:55:17 danielk1977 Exp $
**
** This file contains code used to implement mutexes on Btree objects.
** This code really belongs in btree.c. But btree.c is getting too
@ -18,8 +18,37 @@
** a good breakout.
*/
#include "btreeInt.h"
#if SQLITE_THREADSAFE && !defined(SQLITE_OMIT_SHARED_CACHE)
#ifndef SQLITE_OMIT_SHARED_CACHE
#if SQLITE_THREADSAFE
/*
** Obtain the BtShared mutex associated with B-Tree handle p. Also,
** set BtShared.db to the database handle associated with p and the
** p->locked boolean to true.
*/
static void lockBtreeMutex(Btree *p){
assert( p->locked==0 );
assert( sqlite3_mutex_notheld(p->pBt->mutex) );
assert( sqlite3_mutex_held(p->db->mutex) );
sqlite3_mutex_enter(p->pBt->mutex);
p->pBt->db = p->db;
p->locked = 1;
}
/*
** Release the BtShared mutex associated with B-Tree handle p and
** clear the p->locked boolean.
*/
static void unlockBtreeMutex(Btree *p){
assert( p->locked==1 );
assert( sqlite3_mutex_held(p->pBt->mutex) );
assert( sqlite3_mutex_held(p->db->mutex) );
assert( p->db==p->pBt->db );
sqlite3_mutex_leave(p->pBt->mutex);
p->locked = 0;
}
/*
** Enter a mutex on the given BTree object.
@ -57,6 +86,10 @@ void sqlite3BtreeEnter(Btree *p){
/* We should already hold a lock on the database connection */
assert( sqlite3_mutex_held(p->db->mutex) );
/* Unless the database is sharable and unlocked, then BtShared.db
** should already be set correctly. */
assert( (p->locked==0 && p->sharable) || p->pBt->db==p->db );
if( !p->sharable ) return;
p->wantToLock++;
if( p->locked ) return;
@ -66,6 +99,7 @@ void sqlite3BtreeEnter(Btree *p){
** procedure that follows. Just be sure not to block.
*/
if( sqlite3_mutex_try(p->pBt->mutex)==SQLITE_OK ){
p->pBt->db = p->db;
p->locked = 1;
return;
}
@ -80,16 +114,13 @@ void sqlite3BtreeEnter(Btree *p){
assert( pLater->pNext==0 || pLater->pNext->pBt>pLater->pBt );
assert( !pLater->locked || pLater->wantToLock>0 );
if( pLater->locked ){
sqlite3_mutex_leave(pLater->pBt->mutex);
pLater->locked = 0;
unlockBtreeMutex(pLater);
}
}
sqlite3_mutex_enter(p->pBt->mutex);
p->locked = 1;
lockBtreeMutex(p);
for(pLater=p->pNext; pLater; pLater=pLater->pNext){
if( pLater->wantToLock ){
sqlite3_mutex_enter(pLater->pBt->mutex);
pLater->locked = 1;
lockBtreeMutex(pLater);
}
}
}
@ -102,25 +133,25 @@ void sqlite3BtreeLeave(Btree *p){
assert( p->wantToLock>0 );
p->wantToLock--;
if( p->wantToLock==0 ){
assert( p->locked );
sqlite3_mutex_leave(p->pBt->mutex);
p->locked = 0;
unlockBtreeMutex(p);
}
}
}
#ifndef NDEBUG
/*
** Return true if the BtShared mutex is held on the btree.
**
** This routine makes no determination one why or another if the
** database connection mutex is held.
** Return true if the BtShared mutex is held on the btree, or if the
** B-Tree is not marked as sharable.
**
** This routine is used only from within assert() statements.
*/
int sqlite3BtreeHoldsMutex(Btree *p){
return (p->sharable==0 ||
(p->locked && p->wantToLock && sqlite3_mutex_held(p->pBt->mutex)));
assert( p->sharable==0 || p->locked==0 || p->wantToLock>0 );
assert( p->sharable==0 || p->locked==0 || p->db==p->pBt->db );
assert( p->sharable==0 || p->locked==0 || sqlite3_mutex_held(p->pBt->mutex) );
assert( p->sharable==0 || p->locked==0 || sqlite3_mutex_held(p->db->mutex) );
return (p->sharable==0 || p->locked);
}
#endif
@ -160,6 +191,7 @@ void sqlite3BtreeEnterAll(sqlite3 *db){
assert( sqlite3_mutex_held(db->mutex) );
for(i=0; i<db->nDb; i++){
p = db->aDb[i].pBt;
assert( !p || (p->locked==0 && p->sharable) || p->pBt->db==p->db );
if( p && p->sharable ){
p->wantToLock++;
if( !p->locked ){
@ -168,13 +200,11 @@ void sqlite3BtreeEnterAll(sqlite3 *db){
while( p->locked && p->pNext ) p = p->pNext;
for(pLater = p->pNext; pLater; pLater=pLater->pNext){
if( pLater->locked ){
sqlite3_mutex_leave(pLater->pBt->mutex);
pLater->locked = 0;
unlockBtreeMutex(pLater);
}
}
while( p ){
sqlite3_mutex_enter(p->pBt->mutex);
p->locked++;
lockBtreeMutex(p);
p = p->pNext;
}
}
@ -191,9 +221,7 @@ void sqlite3BtreeLeaveAll(sqlite3 *db){
assert( p->wantToLock>0 );
p->wantToLock--;
if( p->wantToLock==0 ){
assert( p->locked );
sqlite3_mutex_leave(p->pBt->mutex);
p->locked = 0;
unlockBtreeMutex(p);
}
}
}
@ -282,8 +310,7 @@ void sqlite3BtreeMutexArrayEnter(BtreeMutexArray *pArray){
p->wantToLock++;
if( !p->locked && p->sharable ){
sqlite3_mutex_enter(p->pBt->mutex);
p->locked = 1;
lockBtreeMutex(p);
}
}
}
@ -305,11 +332,23 @@ void sqlite3BtreeMutexArrayLeave(BtreeMutexArray *pArray){
p->wantToLock--;
if( p->wantToLock==0 && p->locked ){
sqlite3_mutex_leave(p->pBt->mutex);
p->locked = 0;
unlockBtreeMutex(p);
}
}
}
#endif /* SQLITE_THREADSAFE && !SQLITE_OMIT_SHARED_CACHE */
#else
void sqlite3BtreeEnter(Btree *p){
p->pBt->db = p->db;
}
void sqlite3BtreeEnterAll(sqlite3 *db){
int i;
for(i=0; i<db->nDb; i++){
Btree *p = db->aDb[i].pBt;
if( p ){
p->pBt->db = p->db;
}
}
}
#endif /* if SQLITE_THREADSAFE */
#endif /* ifndef SQLITE_OMIT_SHARED_CACHE */

File diff suppressed because it is too large Load Diff

View File

@ -13,7 +13,7 @@
** subsystem. See comments in the source code for a detailed description
** of what each interface routine does.
**
** @(#) $Id: btree.h,v 1.108 2009/02/03 16:51:25 danielk1977 Exp $
** @(#) $Id: btree.h,v 1.113 2009/04/10 12:55:17 danielk1977 Exp $
*/
#ifndef _BTREE_H_
#define _BTREE_H_
@ -80,7 +80,7 @@ int sqlite3BtreeClose(Btree*);
int sqlite3BtreeSetCacheSize(Btree*,int);
int sqlite3BtreeSetSafetyLevel(Btree*,int,int);
int sqlite3BtreeSyncDisabled(Btree*);
int sqlite3BtreeSetPageSize(Btree*,int,int);
int sqlite3BtreeSetPageSize(Btree*,int,int,int);
int sqlite3BtreeGetPageSize(Btree*);
int sqlite3BtreeMaxPageCount(Btree*,int);
int sqlite3BtreeGetReserve(Btree*);
@ -91,12 +91,9 @@ int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster);
int sqlite3BtreeCommitPhaseTwo(Btree*);
int sqlite3BtreeCommit(Btree*);
int sqlite3BtreeRollback(Btree*);
int sqlite3BtreeBeginStmt(Btree*);
int sqlite3BtreeCommitStmt(Btree*);
int sqlite3BtreeRollbackStmt(Btree*);
int sqlite3BtreeBeginStmt(Btree*,int);
int sqlite3BtreeCreateTable(Btree*, int*, int flags);
int sqlite3BtreeIsInTrans(Btree*);
int sqlite3BtreeIsInStmt(Btree*);
int sqlite3BtreeIsInReadTrans(Btree*);
int sqlite3BtreeIsInBackup(Btree*);
void *sqlite3BtreeSchema(Btree *, int, void(*)(void *));
@ -165,6 +162,8 @@ const void *sqlite3BtreeKeyFetch(BtCursor*, int *pAmt);
const void *sqlite3BtreeDataFetch(BtCursor*, int *pAmt);
int sqlite3BtreeDataSize(BtCursor*, u32 *pSize);
int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*);
void sqlite3BtreeSetCachedRowid(BtCursor*, sqlite3_int64);
sqlite3_int64 sqlite3BtreeGetCachedRowid(BtCursor*);
char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*);
struct Pager *sqlite3BtreePager(Btree*);
@ -173,6 +172,10 @@ int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*);
void sqlite3BtreeCacheOverflow(BtCursor *);
void sqlite3BtreeClearCursor(BtCursor *);
#ifndef SQLITE_OMIT_BTREECOUNT
int sqlite3BtreeCount(BtCursor *, i64 *);
#endif
#ifdef SQLITE_TEST
int sqlite3BtreeCursorInfo(BtCursor*, int*, int);
void sqlite3BtreeCursorList(Btree*);
@ -183,42 +186,39 @@ void sqlite3BtreeCursorList(Btree*);
** use mutexes to access the BtShared structures. So make the
** Enter and Leave procedures no-ops.
*/
#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE
#ifndef SQLITE_OMIT_SHARED_CACHE
void sqlite3BtreeEnter(Btree*);
void sqlite3BtreeLeave(Btree*);
#ifndef NDEBUG
/* This routine is used inside assert() statements only. */
int sqlite3BtreeHoldsMutex(Btree*);
void sqlite3BtreeEnterAll(sqlite3*);
#else
# define sqlite3BtreeEnter(X)
# define sqlite3BtreeEnterAll(X)
#endif
#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE
void sqlite3BtreeLeave(Btree*);
void sqlite3BtreeEnterCursor(BtCursor*);
void sqlite3BtreeLeaveCursor(BtCursor*);
void sqlite3BtreeEnterAll(sqlite3*);
void sqlite3BtreeLeaveAll(sqlite3*);
#ifndef NDEBUG
/* This routine is used inside assert() statements only. */
int sqlite3BtreeHoldsAllMutexes(sqlite3*);
#endif
void sqlite3BtreeMutexArrayEnter(BtreeMutexArray*);
void sqlite3BtreeMutexArrayLeave(BtreeMutexArray*);
void sqlite3BtreeMutexArrayInsert(BtreeMutexArray*, Btree*);
#else
# define sqlite3BtreeEnter(X)
# define sqlite3BtreeLeave(X)
#ifndef NDEBUG
/* This routine is used inside assert() statements only. */
# define sqlite3BtreeHoldsMutex(X) 1
/* These routines are used inside assert() statements only. */
int sqlite3BtreeHoldsMutex(Btree*);
int sqlite3BtreeHoldsAllMutexes(sqlite3*);
#endif
#else
# define sqlite3BtreeLeave(X)
# define sqlite3BtreeEnterCursor(X)
# define sqlite3BtreeLeaveCursor(X)
# define sqlite3BtreeEnterAll(X)
# define sqlite3BtreeLeaveAll(X)
#ifndef NDEBUG
/* This routine is used inside assert() statements only. */
# define sqlite3BtreeHoldsAllMutexes(X) 1
#endif
# define sqlite3BtreeMutexArrayEnter(X)
# define sqlite3BtreeMutexArrayLeave(X)
# define sqlite3BtreeMutexArrayInsert(X,Y)
# define sqlite3BtreeHoldsMutex(X) 1
# define sqlite3BtreeHoldsAllMutexes(X) 1
#endif

View File

@ -9,7 +9,7 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
** $Id: btreeInt.h,v 1.42 2009/02/03 16:51:25 danielk1977 Exp $
** $Id: btreeInt.h,v 1.46 2009/03/20 14:18:52 danielk1977 Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
@ -205,11 +205,6 @@
*/
#include "sqliteInt.h"
/* Round up a number to the next larger multiple of 8. This is used
** to force 8-byte alignment on 64-bit architectures.
*/
#define ROUND8(x) ((x+7)&~7)
/* The following value is the maximum cell size assuming a maximum page
** size give above.
@ -356,13 +351,30 @@ struct Btree {
** may not be modified once it is initially set as long as nRef>0.
** The pSchema field may be set once under BtShared.mutex and
** thereafter is unchanged as long as nRef>0.
**
** isPending:
**
** If a BtShared client fails to obtain a write-lock on a database
** table (because there exists one or more read-locks on the table),
** the shared-cache enters 'pending-lock' state and isPending is
** set to true.
**
** The shared-cache leaves the 'pending lock' state when either of
** the following occur:
**
** 1) The current writer (BtShared.pWriter) concludes its transaction, OR
** 2) The number of locks held by other connections drops to zero.
**
** while in the 'pending-lock' state, no connection may start a new
** transaction.
**
** This feature is included to help prevent writer-starvation.
*/
struct BtShared {
Pager *pPager; /* The page cache */
sqlite3 *db; /* Database connection currently using this Btree */
BtCursor *pCursor; /* A list of all open cursors */
MemPage *pPage1; /* First page of the database */
u8 inStmt; /* True if we are in a statement subtransaction */
u8 readOnly; /* True if the underlying file is readonly */
u8 pageSizeFixed; /* True if the page size can no longer be changed */
#ifndef SQLITE_OMIT_AUTOVACUUM
@ -385,7 +397,9 @@ struct BtShared {
int nRef; /* Number of references to this structure */
BtShared *pNext; /* Next on a list of sharable BtShared structs */
BtLock *pLock; /* List of locks held on this shared-btree struct */
Btree *pExclusive; /* Btree with an EXCLUSIVE lock on the whole db */
Btree *pWriter; /* Btree with currently open write transaction */
u8 isExclusive; /* True if pWriter has an EXCLUSIVE lock on the db */
u8 isPending; /* If waiting for read-locks to clear */
#endif
u8 *pTmpSpace; /* BtShared.pageSize bytes of space for tmp use */
};
@ -438,6 +452,7 @@ struct BtCursor {
BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */
struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
Pgno pgnoRoot; /* The root page of this tree */
sqlite3_int64 cachedRowid; /* Next rowid cache. 0 means not valid */
CellInfo info; /* A parse of the cell we are pointing at */
u8 wrFlag; /* True if writable */
u8 atLast; /* Cursor pointing to the last entry */

View File

@ -22,7 +22,7 @@
** COMMIT
** ROLLBACK
**
** $Id: build.c,v 1.518 2009/02/13 03:43:32 drh Exp $
** $Id: build.c,v 1.528 2009/04/08 13:51:51 drh Exp $
*/
#include "sqliteInt.h"
@ -178,19 +178,6 @@ void sqlite3FinishCoding(Parse *pParse){
codeTableLocks(pParse);
sqlite3VdbeAddOp2(v, OP_Goto, 0, pParse->cookieGoto);
}
#ifndef SQLITE_OMIT_TRACE
if( !db->init.busy ){
/* Change the P4 argument of the first opcode (which will always be
** an OP_Trace) to be the complete text of the current SQL statement.
*/
VdbeOp *pOp = sqlite3VdbeGetOp(v, 0);
if( pOp && pOp->opcode==OP_Trace ){
sqlite3VdbeChangeP4(v, 0, pParse->zSql,
(int)(pParse->zTail - pParse->zSql));
}
}
#endif /* SQLITE_OMIT_TRACE */
}
@ -202,8 +189,8 @@ void sqlite3FinishCoding(Parse *pParse){
sqlite3VdbeTrace(v, trace);
#endif
assert( pParse->disableColCache==0 ); /* Disables and re-enables match */
sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem+3,
pParse->nTab+3, pParse->explain);
sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem,
pParse->nTab, pParse->explain);
pParse->rc = SQLITE_DONE;
pParse->colNamesSet = 0;
}else if( pParse->rc==SQLITE_OK ){
@ -352,7 +339,7 @@ Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const char *zDb){
** Reclaim the memory used by an index
*/
static void freeIndex(Index *p){
sqlite3 *db = p->pTable->db;
sqlite3 *db = p->pTable->dbMem;
sqlite3DbFree(db, p->zColAff);
sqlite3DbFree(db, p);
}
@ -480,7 +467,7 @@ void sqlite3CommitInternalChanges(sqlite3 *db){
static void sqliteResetColumnNames(Table *pTable){
int i;
Column *pCol;
sqlite3 *db = pTable->db;
sqlite3 *db = pTable->dbMem;
assert( pTable!=0 );
if( (pCol = pTable->aCol)!=0 ){
for(i=0; i<pTable->nCol; i++, pCol++){
@ -511,7 +498,7 @@ void sqlite3DeleteTable(Table *pTable){
sqlite3 *db;
if( pTable==0 ) return;
db = pTable->db;
db = pTable->dbMem;
/* Do not delete the table until the reference count reaches zero. */
pTable->nRef--;
@ -616,8 +603,11 @@ char *sqlite3NameFromToken(sqlite3 *db, Token *pName){
void sqlite3OpenMasterTable(Parse *p, int iDb){
Vdbe *v = sqlite3GetVdbe(p);
sqlite3TableLock(p, iDb, MASTER_ROOT, 1, SCHEMA_TABLE(iDb));
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, 5);/* sqlite_master has 5 columns */
sqlite3VdbeAddOp3(v, OP_OpenWrite, 0, MASTER_ROOT, iDb);
sqlite3VdbeChangeP4(v, -1, (char *)5, P4_INT32); /* 5 column table */
if( p->nTab==0 ){
p->nTab = 1;
}
}
/*
@ -846,7 +836,7 @@ void sqlite3StartTable(
pTable->iPKey = -1;
pTable->pSchema = db->aDb[iDb].pSchema;
pTable->nRef = 1;
pTable->db = db;
pTable->dbMem = db->lookaside.bEnabled ? db : 0;
if( pParse->pNewTable ) sqlite3DeleteTable(pParse->pNewTable);
pParse->pNewTable = pTable;
@ -901,9 +891,10 @@ void sqlite3StartTable(
** The record created does not contain anything yet. It will be replaced
** by the real entry in code generated at sqlite3EndTable().
**
** The rowid for the new entry is left on the top of the stack.
** The rowid value is needed by the code that sqlite3EndTable will
** generate.
** The rowid for the new entry is left in register pParse->regRowid.
** The root page number of the new table is left in reg pParse->regRoot.
** The rowid and root page number values are needed by the code that
** sqlite3EndTable will generate.
*/
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
if( isView || isVirtual ){
@ -1116,12 +1107,12 @@ void sqlite3AddDefaultValue(Parse *pParse, Expr *pExpr){
sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant",
pCol->zName);
}else{
Expr *pCopy;
/* A copy of pExpr is used instead of the original, as pExpr contains
** tokens that point to volatile memory. The 'span' of the expression
** is required by pragma table_info.
*/
sqlite3ExprDelete(db, pCol->pDflt);
pCol->pDflt = pCopy = sqlite3ExprDup(db, pExpr);
if( pCopy ){
sqlite3TokenCopy(db, &pCopy->span, &pExpr->span);
}
pCol->pDflt = sqlite3ExprDup(db, pExpr, EXPRDUP_REDUCE|EXPRDUP_SPAN);
}
}
sqlite3ExprDelete(db, pExpr);
@ -1217,7 +1208,7 @@ void sqlite3AddCheckConstraint(
** to malloced space and not the (ephemeral) text of the CREATE TABLE
** statement */
pTab->pCheck = sqlite3ExprAnd(db, pTab->pCheck,
sqlite3ExprDup(db, pCheckExpr));
sqlite3ExprDup(db, pCheckExpr, 0));
}
#endif
sqlite3ExprDelete(db, pCheckExpr);
@ -1340,18 +1331,100 @@ static int identLength(const char *z){
}
/*
** Write an identifier onto the end of the given string. Add
** quote characters as needed.
** This function is a wrapper around sqlite3GetToken() used by
** isValidDimension(). This function differs from sqlite3GetToken() in
** that:
**
** * Whitespace is ignored, and
** * The output variable *peToken is set to 0 if the end of the
** nul-terminated input string is reached.
*/
static void identPut(char *z, int *pIdx, char *zSignedIdent){
static int getTokenNoSpace(unsigned char *z, int *peToken){
int n = 0;
while( sqlite3Isspace(z[n]) ) n++;
if( !z[n] ){
*peToken = 0;
return 0;
}
return n + sqlite3GetToken(&z[n], peToken);
}
/*
** Parameter z points to a nul-terminated string. Return true if, when
** whitespace is ignored, the contents of this string matches one of
** the following patterns:
**
** ""
** "(number)"
** "(number,number)"
*/
static int isValidDimension(unsigned char *z){
int eToken;
int n = 0;
n += getTokenNoSpace(&z[n], &eToken);
if( eToken ){
if( eToken!=TK_LP ) return 0;
n += getTokenNoSpace(&z[n], &eToken);
if( eToken==TK_PLUS || eToken==TK_MINUS ){
n += getTokenNoSpace(&z[n], &eToken);
}
if( eToken!=TK_INTEGER && eToken!=TK_FLOAT ) return 0;
n += getTokenNoSpace(&z[n], &eToken);
if( eToken==TK_COMMA ){
n += getTokenNoSpace(&z[n], &eToken);
if( eToken==TK_PLUS || eToken==TK_MINUS ){
n += getTokenNoSpace(&z[n], &eToken);
}
if( eToken!=TK_INTEGER && eToken!=TK_FLOAT ) return 0;
n += getTokenNoSpace(&z[n], &eToken);
}
if( eToken!=TK_RP ) return 0;
getTokenNoSpace(&z[n], &eToken);
}
if( eToken ) return 0;
return 1;
}
/*
** The first parameter is a pointer to an output buffer. The second
** parameter is a pointer to an integer that contains the offset at
** which to write into the output buffer. This function copies the
** nul-terminated string pointed to by the third parameter, zSignedIdent,
** to the specified offset in the buffer and updates *pIdx to refer
** to the first byte after the last byte written before returning.
**
** If the string zSignedIdent consists entirely of alpha-numeric
** characters, does not begin with a digit and is not an SQL keyword,
** then it is copied to the output buffer exactly as it is. Otherwise,
** it is quoted using double-quotes.
*/
static void identPut(char *z, int *pIdx, char *zSignedIdent, int isTypename){
unsigned char *zIdent = (unsigned char*)zSignedIdent;
int i, j, needQuote;
i = *pIdx;
for(j=0; zIdent[j]; j++){
if( !sqlite3Isalnum(zIdent[j]) && zIdent[j]!='_' ) break;
}
needQuote = zIdent[j]!=0 || sqlite3Isdigit(zIdent[0])
|| sqlite3KeywordCode(zIdent, j)!=TK_ID;
needQuote = sqlite3Isdigit(zIdent[0]) || sqlite3KeywordCode(zIdent, j)!=TK_ID;
if( !needQuote ){
if( isTypename ){
/* If this is a type-name, allow a little more flexibility. In SQLite,
** a type-name is specified as:
**
** ids [ids] [(number [, number])]
**
** where "ids" is either a quoted string or a simple identifier (in the
** above notation, [] means optional). It is a bit tricky to check
** for all cases, but it is good to avoid unnecessarily quoting common
** typenames like VARCHAR(10).
*/
needQuote = !isValidDimension(&zIdent[j]);
}else{
needQuote = zIdent[j];
}
}
if( needQuote ) z[i++] = '"';
for(j=0; zIdent[j]; j++){
z[i++] = zIdent[j];
@ -1377,7 +1450,7 @@ static char *createTableStmt(sqlite3 *db, Table *p){
n += identLength(pCol->zName);
z = pCol->zType;
if( z ){
n += (sqlite3Strlen30(z) + 1);
n += identLength(z);
}
}
n += identLength(p->zName);
@ -1398,18 +1471,17 @@ static char *createTableStmt(sqlite3 *db, Table *p){
}
sqlite3_snprintf(n, zStmt, "CREATE TABLE ");
k = sqlite3Strlen30(zStmt);
identPut(zStmt, &k, p->zName);
identPut(zStmt, &k, p->zName, 0);
zStmt[k++] = '(';
for(pCol=p->aCol, i=0; i<p->nCol; i++, pCol++){
sqlite3_snprintf(n-k, &zStmt[k], zSep);
k += sqlite3Strlen30(&zStmt[k]);
zSep = zSep2;
identPut(zStmt, &k, pCol->zName);
identPut(zStmt, &k, pCol->zName, 0);
if( (z = pCol->zType)!=0 ){
zStmt[k++] = ' ';
assert( (int)(sqlite3Strlen30(z)+k+1)<=n );
sqlite3_snprintf(n-k, &zStmt[k], "%s", z);
k += sqlite3Strlen30(z);
identPut(zStmt, &k, z, 1);
}
}
sqlite3_snprintf(n-k, &zStmt[k], "%s", zEnd);
@ -1489,8 +1561,7 @@ void sqlite3EndTable(
}
/* If not initializing, then create a record for the new table
** in the SQLITE_MASTER table of the database. The record number
** for the new table entry should already be on the stack.
** in the SQLITE_MASTER table of the database.
**
** If this is a TEMPORARY table, write the entry into the auxiliary
** file instead of into the main database file.
@ -1507,9 +1578,8 @@ void sqlite3EndTable(
sqlite3VdbeAddOp1(v, OP_Close, 0);
/* Create the rootpage for the new table and push it onto the stack.
** A view has no rootpage, so just push a zero onto the stack for
** views. Initialize zType at the same time.
/*
** Initialize zType for the new view or table.
*/
if( p->pSelect==0 ){
/* A regular table */
@ -1525,7 +1595,7 @@ void sqlite3EndTable(
/* If this is a CREATE TABLE xx AS SELECT ..., execute the SELECT
** statement to populate the new table. The root-page number for the
** new table is on the top of the vdbe stack.
** new table is in register pParse->regRoot.
**
** Once the SELECT has been coded by sqlite3Select(), it is in a
** suitable state to query for the column names and types to be used
@ -1540,7 +1610,7 @@ void sqlite3EndTable(
SelectDest dest;
Table *pSelTab;
assert(pParse->nTab==0);
assert(pParse->nTab==1);
sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, pParse->regRoot, iDb);
sqlite3VdbeChangeP5(v, 1);
pParse->nTab = 2;
@ -1571,9 +1641,7 @@ void sqlite3EndTable(
/* A slot for the record has already been allocated in the
** SQLITE_MASTER table. We just need to update that slot with all
** the information we've collected. The rowid for the preallocated
** slot is the 2nd item on the stack. The top of the stack is the
** root page for the new table (or a 0 if this is a view).
** the information we've collected.
*/
sqlite3NestedParse(pParse,
"UPDATE %Q.%s "
@ -1701,7 +1769,7 @@ void sqlite3CreateView(
** allocated rather than point to the input string - which means that
** they will persist after the current sqlite3_exec() call returns.
*/
p->pSelect = sqlite3SelectDup(db, pSelect);
p->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
sqlite3SelectDelete(db, pSelect);
if( db->mallocFailed ){
return;
@ -1783,11 +1851,13 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
** statement that defines the view.
*/
assert( pTable->pSelect );
pSel = sqlite3SelectDup(db, pTable->pSelect);
pSel = sqlite3SelectDup(db, pTable->pSelect, 0);
if( pSel ){
u8 enableLookaside = db->lookaside.bEnabled;
n = pParse->nTab;
sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
pTable->nCol = -1;
db->lookaside.bEnabled = 0;
#ifndef SQLITE_OMIT_AUTHORIZATION
xAuth = db->xAuth;
db->xAuth = 0;
@ -1796,6 +1866,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
#else
pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
#endif
db->lookaside.bEnabled = enableLookaside;
pParse->nTab = n;
if( pSelTab ){
assert( pTable->aCol==0 );
@ -1892,8 +1963,8 @@ static void destroyRootPage(Parse *pParse, int iTable, int iDb){
** location iTable. The following code modifies the sqlite_master table to
** reflect this.
**
** The "#%d" in the SQL is a special constant that means whatever value
** is on the top of the stack. See sqlite3RegisterExpr().
** The "#NNN" in the SQL is a special constant that means whatever value
** is in register NNN. See sqlite3RegisterExpr().
*/
sqlite3NestedParse(pParse,
"UPDATE %Q.%s SET rootpage=%d WHERE #%d AND rootpage=#%d",
@ -2068,7 +2139,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
** is generated to remove entries from sqlite_master and/or
** sqlite_temp_master if required.
*/
pTrigger = pTab->pTrigger;
pTrigger = sqlite3TriggerList(pParse, pTab);
while( pTrigger ){
assert( pTrigger->pSchema==pTab->pSchema ||
pTrigger->pSchema==db->aDb[1].pSchema );
@ -2277,8 +2348,8 @@ void sqlite3DeferForeignKey(Parse *pParse, int isDeferred){
*/
static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
Table *pTab = pIndex->pTable; /* The table that is indexed */
int iTab = pParse->nTab; /* Btree cursor used for pTab */
int iIdx = pParse->nTab+1; /* Btree cursor used for pIndex */
int iTab = pParse->nTab++; /* Btree cursor used for pTab */
int iIdx = pParse->nTab++; /* Btree cursor used for pIndex */
int addr1; /* Address of top of loop */
int tnum; /* Root page of index */
Vdbe *v; /* Generate code into this virtual machine */
@ -2773,7 +2844,8 @@ void sqlite3CreateIndex(
/* Clean up before exiting */
exit_create_index:
if( pIndex ){
freeIndex(pIndex);
sqlite3_free(pIndex->zColAff);
sqlite3DbFree(db, pIndex);
}
sqlite3ExprListDelete(db, pList);
sqlite3SrcListDelete(db, pTblName);

View File

@ -13,7 +13,7 @@
** This file contains functions used to access the internal hash tables
** of user defined functions and collation sequences.
**
** $Id: callback.c,v 1.35 2009/01/31 22:28:49 drh Exp $
** $Id: callback.c,v 1.37 2009/03/24 15:08:10 drh Exp $
*/
#include "sqliteInt.h"
@ -175,7 +175,7 @@ static CollSeq *findCollSeqEntry(
pColl[0].zName[nName] = 0;
pDel = sqlite3HashInsert(&db->aCollSeq, pColl[0].zName, nName, pColl);
/* If a malloc() failure occured in sqlite3HashInsert(), it will
/* If a malloc() failure occurred in sqlite3HashInsert(), it will
** return the pColl pointer to be deleted (because it wasn't added
** to the hash table).
*/
@ -423,6 +423,7 @@ void sqlite3SchemaFree(void *p){
sqlite3HashInit(&pSchema->tblHash, 0);
for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
Table *pTab = sqliteHashData(pElem);
assert( pTab->dbMem==0 );
sqlite3DeleteTable(pTab);
}
sqlite3HashClear(&temp1);

View File

@ -16,7 +16,7 @@
** sqlite3RegisterDateTimeFunctions() found at the bottom of the file.
** All other code has file scope.
**
** $Id: date.c,v 1.103 2009/02/04 03:59:25 shane Exp $
** $Id: date.c,v 1.105 2009/04/03 12:04:37 drh Exp $
**
** SQLite processes all times and dates as Julian Day numbers. The
** dates and times are stored as the number of days since noon
@ -953,8 +953,8 @@ static void strftimeFunc(
case 'm': sqlite3_snprintf(3, &z[j],"%02d",x.M); j+=2; break;
case 'M': sqlite3_snprintf(3, &z[j],"%02d",x.m); j+=2; break;
case 's': {
sqlite3_snprintf(30,&z[j],"%d",
(int)(x.iJD/1000.0 - 210866760000.0));
sqlite3_snprintf(30,&z[j],"%lld",
(i64)(x.iJD/1000 - 21086676*(i64)10000));
j += sqlite3Strlen30(&z[j]);
break;
}

View File

@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** in order to generate code for DELETE FROM statements.
**
** $Id: delete.c,v 1.191 2008/12/23 23:56:22 drh Exp $
** $Id: delete.c,v 1.198 2009/03/05 03:48:07 shane Exp $
*/
#include "sqliteInt.h"
@ -77,8 +77,8 @@ void sqlite3OpenTable(
v = sqlite3GetVdbe(p);
assert( opcode==OP_OpenWrite || opcode==OP_OpenRead );
sqlite3TableLock(p, iDb, pTab->tnum, (opcode==OP_OpenWrite)?1:0, pTab->zName);
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, pTab->nCol);
sqlite3VdbeAddOp3(v, opcode, iCur, pTab->tnum, iDb);
sqlite3VdbeChangeP4(v, -1, SQLITE_INT_TO_PTR(pTab->nCol), P4_INT32);
VdbeComment((v, "%s", pTab->zName));
}
@ -99,12 +99,12 @@ void sqlite3MaterializeView(
Select *pDup;
sqlite3 *db = pParse->db;
pDup = sqlite3SelectDup(db, pView->pSelect);
pDup = sqlite3SelectDup(db, pView->pSelect, 0);
if( pWhere ){
SrcList *pFrom;
Token viewName;
pWhere = sqlite3ExprDup(db, pWhere);
pWhere = sqlite3ExprDup(db, pWhere, 0);
viewName.z = (u8*)pView->zName;
viewName.n = (unsigned int)sqlite3Strlen30((const char*)viewName.z);
pFrom = sqlite3SrcListAppendFromTerm(pParse, 0, 0, 0, &viewName, pDup, 0,0);
@ -174,14 +174,15 @@ Expr *sqlite3LimitWhere(
/* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree
** and the SELECT subtree. */
pSelectSrc = sqlite3SrcListDup(pParse->db, pSrc);
pSelectSrc = sqlite3SrcListDup(pParse->db, pSrc, 0);
if( pSelectSrc == 0 ) {
sqlite3ExprListDelete(pParse->db, pEList);
goto limit_where_cleanup_2;
}
/* generate the SELECT expression tree. */
pSelect = sqlite3SelectNew(pParse,pEList,pSelectSrc,pWhere,0,0,pOrderBy,0,pLimit,pOffset);
pSelect = sqlite3SelectNew(pParse,pEList,pSelectSrc,pWhere,0,0,
pOrderBy,0,pLimit,pOffset);
if( pSelect == 0 ) return 0;
/* now generate the new WHERE rowid IN clause for the DELETE/UDPATE */
@ -190,7 +191,8 @@ Expr *sqlite3LimitWhere(
pInClause = sqlite3PExpr(pParse, TK_IN, pWhereRowid, 0, 0);
if( pInClause == 0 ) goto limit_where_cleanup_1;
pInClause->pSelect = pSelect;
pInClause->x.pSelect = pSelect;
pInClause->flags |= EP_xIsSelect;
sqlite3ExprSetHeight(pParse, pInClause);
return pInClause;
@ -238,7 +240,7 @@ void sqlite3DeleteFrom(
#ifndef SQLITE_OMIT_TRIGGER
int isView; /* True if attempting to delete from a view */
int triggers_exist = 0; /* True if any triggers exist */
Trigger *pTrigger; /* List of table triggers, if required */
#endif
int iBeginAfterTrigger = 0; /* Address of after trigger program */
int iEndAfterTrigger = 0; /* Exit of after trigger program */
@ -265,10 +267,10 @@ void sqlite3DeleteFrom(
** deleted from is a view
*/
#ifndef SQLITE_OMIT_TRIGGER
triggers_exist = sqlite3TriggersExist(pTab, TK_DELETE, 0);
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
isView = pTab->pSelect!=0;
#else
# define triggers_exist 0
# define pTrigger 0
# define isView 0
#endif
#ifdef SQLITE_OMIT_VIEW
@ -276,7 +278,7 @@ void sqlite3DeleteFrom(
# define isView 0
#endif
if( sqlite3IsReadOnly(pParse, pTab, triggers_exist) ){
if( sqlite3IsReadOnly(pParse, pTab, (pTrigger?1:0)) ){
goto delete_from_cleanup;
}
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
@ -287,7 +289,7 @@ void sqlite3DeleteFrom(
if( rcauth==SQLITE_DENY ){
goto delete_from_cleanup;
}
assert(!isView || triggers_exist);
assert(!isView || pTrigger);
/* If pTab is really a view, make sure it has been initialized.
*/
@ -297,7 +299,7 @@ void sqlite3DeleteFrom(
/* Allocate a cursor used to store the old.* data for a trigger.
*/
if( triggers_exist ){
if( pTrigger ){
oldIdx = pParse->nTab++;
}
@ -322,21 +324,21 @@ void sqlite3DeleteFrom(
goto delete_from_cleanup;
}
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
sqlite3BeginWriteOperation(pParse, triggers_exist, iDb);
sqlite3BeginWriteOperation(pParse, (pTrigger?1:0), iDb);
if( triggers_exist ){
if( pTrigger ){
int orconf = ((pParse->trigStack)?pParse->trigStack->orconf:OE_Default);
int iGoto = sqlite3VdbeAddOp0(v, OP_Goto);
addr = sqlite3VdbeMakeLabel(v);
iBeginBeforeTrigger = sqlite3VdbeCurrentAddr(v);
(void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TRIGGER_BEFORE, pTab,
-1, oldIdx, orconf, addr, &old_col_mask, 0);
(void)sqlite3CodeRowTrigger(pParse, pTrigger, TK_DELETE, 0,
TRIGGER_BEFORE, pTab, -1, oldIdx, orconf, addr, &old_col_mask, 0);
iEndBeforeTrigger = sqlite3VdbeAddOp0(v, OP_Goto);
iBeginAfterTrigger = sqlite3VdbeCurrentAddr(v);
(void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TRIGGER_AFTER, pTab, -1,
oldIdx, orconf, addr, &old_col_mask, 0);
(void)sqlite3CodeRowTrigger(pParse, pTrigger, TK_DELETE, 0,
TRIGGER_AFTER, pTab, -1, oldIdx, orconf, addr, &old_col_mask, 0);
iEndAfterTrigger = sqlite3VdbeAddOp0(v, OP_Goto);
sqlite3VdbeJumpHere(v, iGoto);
@ -373,7 +375,7 @@ void sqlite3DeleteFrom(
** It is easier just to erase the whole table. Note, however, that
** this means that the row change count will be incorrect.
*/
if( rcauth==SQLITE_OK && pWhere==0 && !triggers_exist && !IsVirtual(pTab) ){
if( rcauth==SQLITE_OK && pWhere==0 && !pTrigger && !IsVirtual(pTab) ){
assert( !isView );
sqlite3VdbeAddOp3(v, OP_Clear, pTab->tnum, iDb, memCnt);
if( !pParse->nested ){
@ -405,9 +407,8 @@ void sqlite3DeleteFrom(
/* Open the pseudo-table used to store OLD if there are triggers.
*/
if( triggers_exist ){
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, pTab->nCol);
sqlite3VdbeAddOp1(v, OP_OpenPseudo, oldIdx);
if( pTrigger ){
sqlite3VdbeAddOp3(v, OP_OpenPseudo, oldIdx, 0, pTab->nCol);
}
/* Delete every item whose key was written to the list during the
@ -426,12 +427,12 @@ void sqlite3DeleteFrom(
/* This is the beginning of the delete loop. If a trigger encounters
** an IGNORE constraint, it jumps back to here.
*/
if( triggers_exist ){
if( pTrigger ){
sqlite3VdbeResolveLabel(v, addr);
}
addr = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, end, iRowid);
if( triggers_exist ){
if( pTrigger ){
int iData = ++pParse->nMem; /* For storing row data of OLD table */
/* If the record is no longer present in the table, jump to the
@ -469,7 +470,7 @@ void sqlite3DeleteFrom(
/* If there are row triggers, close all cursors then invoke
** the AFTER triggers
*/
if( triggers_exist ){
if( pTrigger ){
/* Jump back and run the AFTER triggers */
sqlite3VdbeAddOp2(v, OP_Goto, 0, iBeginAfterTrigger);
sqlite3VdbeJumpHere(v, iEndAfterTrigger);

View File

@ -12,7 +12,7 @@
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
** $Id: expr.c,v 1.411 2009/02/04 03:59:25 shane Exp $
** $Id: expr.c,v 1.426 2009/04/08 13:51:51 drh Exp $
*/
#include "sqliteInt.h"
@ -35,7 +35,8 @@
char sqlite3ExprAffinity(Expr *pExpr){
int op = pExpr->op;
if( op==TK_SELECT ){
return sqlite3ExprAffinity(pExpr->pSelect->pEList->a[0].pExpr);
assert( pExpr->flags&EP_xIsSelect );
return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
}
#ifndef SQLITE_OMIT_CAST
if( op==TK_CAST ){
@ -155,11 +156,9 @@ static char comparisonAffinity(Expr *pExpr){
aff = sqlite3ExprAffinity(pExpr->pLeft);
if( pExpr->pRight ){
aff = sqlite3CompareAffinity(pExpr->pRight, aff);
}
else if( pExpr->pSelect ){
aff = sqlite3CompareAffinity(pExpr->pSelect->pEList->a[0].pExpr, aff);
}
else if( !aff ){
}else if( ExprHasProperty(pExpr, EP_xIsSelect) ){
aff = sqlite3CompareAffinity(pExpr->x.pSelect->pEList->a[0].pExpr, aff);
}else if( !aff ){
aff = SQLITE_AFF_NONE;
}
return aff;
@ -345,8 +344,11 @@ static void exprSetHeight(Expr *p){
int nHeight = 0;
heightOfExpr(p->pLeft, &nHeight);
heightOfExpr(p->pRight, &nHeight);
heightOfExprList(p->pList, &nHeight);
heightOfSelect(p->pSelect, &nHeight);
if( ExprHasProperty(p, EP_xIsSelect) ){
heightOfSelect(p->x.pSelect, &nHeight);
}else{
heightOfExprList(p->x.pList, &nHeight);
}
p->nHeight = nHeight + 1;
}
@ -402,8 +404,24 @@ Expr *sqlite3Expr(
pNew->iAgg = -1;
pNew->span.z = (u8*)"";
if( pToken ){
int c;
assert( pToken->dyn==0 );
pNew->span = pNew->token = *pToken;
pNew->span = *pToken;
/* The pToken->z value is read-only. But the new expression
** node created here might be passed to sqlite3DequoteExpr() which
** will attempt to modify pNew->token.z. Hence, if the token
** is quoted, make a copy now so that DequoteExpr() will change
** the copy rather than the original text.
*/
if( pToken->n>=2
&& ((c = pToken->z[0])=='\'' || c=='"' || c=='[' || c=='`') ){
sqlite3TokenCopy(db, &pNew->token, pToken);
}else{
pNew->token = *pToken;
pNew->flags |= EP_Dequoted;
VVA_ONLY( pNew->vvaFlags |= EVVA_ReadOnlyToken; )
}
}else if( pLeft ){
if( pRight ){
if( pRight->span.dyn==0 && pLeft->span.dyn==0 ){
@ -492,7 +510,10 @@ void sqlite3ExprSpan(Expr *pExpr, Token *pLeft, Token *pRight){
assert( pLeft!=0 );
if( pExpr ){
pExpr->span.z = pLeft->z;
pExpr->span.n = pRight->n + (pRight->z - pLeft->z);
/* The following assert() may fail when this is called
** via sqlite3PExpr()/sqlite3Expr() from addWhereTerm(). */
/* assert(pRight->z >= pLeft->z); */
pExpr->span.n = pRight->n + (unsigned)(pRight->z - pLeft->z);
}
}
@ -506,15 +527,15 @@ Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token *pToken){
assert( pToken );
pNew = sqlite3DbMallocZero(db, sizeof(Expr) );
if( pNew==0 ){
sqlite3ExprListDelete(db, pList); /* Avoid leaking memory when malloc fails */
sqlite3ExprListDelete(db, pList); /* Avoid memory leak when malloc fails */
return 0;
}
pNew->op = TK_FUNCTION;
pNew->pList = pList;
pNew->x.pList = pList;
assert( !ExprHasProperty(pNew, EP_xIsSelect) );
assert( pToken->dyn==0 );
pNew->token = *pToken;
pNew->span = pNew->token;
pNew->span = *pToken;
sqlite3TokenCopy(db, &pNew->token, pToken);
sqlite3ExprSetHeight(pParse, pNew);
return pNew;
}
@ -607,12 +628,25 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
** Substructure is deleted.
*/
void sqlite3ExprClear(sqlite3 *db, Expr *p){
if( p->span.dyn ) sqlite3DbFree(db, (char*)p->span.z);
if( p->token.dyn ) sqlite3DbFree(db, (char*)p->token.z);
sqlite3ExprDelete(db, p->pLeft);
sqlite3ExprDelete(db, p->pRight);
sqlite3ExprListDelete(db, p->pList);
sqlite3SelectDelete(db, p->pSelect);
if( !ExprHasAnyProperty(p, EP_TokenOnly|EP_SpanToken) ){
if( p->span.dyn ) sqlite3DbFree(db, (char*)p->span.z);
if( ExprHasProperty(p, EP_Reduced) ){
/* Subtrees are part of the same memory allocation when EP_Reduced set */
if( p->pLeft ) sqlite3ExprClear(db, p->pLeft);
if( p->pRight ) sqlite3ExprClear(db, p->pRight);
}else{
/* Subtrees are separate allocations when EP_Reduced is clear */
sqlite3ExprDelete(db, p->pLeft);
sqlite3ExprDelete(db, p->pRight);
}
/* x.pSelect and x.pList are always separately allocated */
if( ExprHasProperty(p, EP_xIsSelect) ){
sqlite3SelectDelete(db, p->x.pSelect);
}else{
sqlite3ExprListDelete(db, p->x.pList);
}
}
}
/*
@ -628,15 +662,192 @@ void sqlite3ExprDelete(sqlite3 *db, Expr *p){
** The Expr.token field might be a string literal that is quoted.
** If so, remove the quotation marks.
*/
void sqlite3DequoteExpr(sqlite3 *db, Expr *p){
if( ExprHasAnyProperty(p, EP_Dequoted) ){
return;
void sqlite3DequoteExpr(Expr *p){
if( !ExprHasAnyProperty(p, EP_Dequoted) ){
ExprSetProperty(p, EP_Dequoted);
assert( (p->vvaFlags & EVVA_ReadOnlyToken)==0 );
sqlite3Dequote((char*)p->token.z);
}
ExprSetProperty(p, EP_Dequoted);
if( p->token.dyn==0 ){
sqlite3TokenCopy(db, &p->token, &p->token);
}
/*
** Return the number of bytes allocated for the expression structure
** passed as the first argument. This is always one of EXPR_FULLSIZE,
** EXPR_REDUCEDSIZE or EXPR_TOKENONLYSIZE.
*/
static int exprStructSize(Expr *p){
if( ExprHasProperty(p, EP_TokenOnly) ) return EXPR_TOKENONLYSIZE;
if( ExprHasProperty(p, EP_SpanToken) ) return EXPR_SPANTOKENSIZE;
if( ExprHasProperty(p, EP_Reduced) ) return EXPR_REDUCEDSIZE;
return EXPR_FULLSIZE;
}
/*
** sqlite3ExprDup() has been called to create a copy of expression p with
** the EXPRDUP_XXX flags passed as the second argument. This function
** returns the space required for the copy of the Expr structure only.
** This is always one of EXPR_FULLSIZE, EXPR_REDUCEDSIZE or EXPR_TOKENONLYSIZE.
*/
static int dupedExprStructSize(Expr *p, int flags){
int nSize;
if( 0==(flags&EXPRDUP_REDUCE) ){
nSize = EXPR_FULLSIZE;
}else if( p->pLeft || p->pRight || p->pColl || p->x.pList ){
nSize = EXPR_REDUCEDSIZE;
}else if( flags&EXPRDUP_SPAN ){
nSize = EXPR_SPANTOKENSIZE;
}else{
nSize = EXPR_TOKENONLYSIZE;
}
sqlite3Dequote((char*)p->token.z);
return nSize;
}
/*
** sqlite3ExprDup() has been called to create a copy of expression p with
** the EXPRDUP_XXX passed as the second argument. This function returns
** the space in bytes required to store the copy of the Expr structure
** and the copies of the Expr.token.z and Expr.span.z (if applicable)
** string buffers.
*/
static int dupedExprNodeSize(Expr *p, int flags){
int nByte = dupedExprStructSize(p, flags) + (p->token.z ? p->token.n + 1 : 0);
if( (flags&EXPRDUP_SPAN)!=0
&& (p->token.z!=p->span.z || p->token.n!=p->span.n)
){
nByte += p->span.n;
}
return ROUND8(nByte);
}
/*
** Return the number of bytes required to create a duplicate of the
** expression passed as the first argument. The second argument is a
** mask containing EXPRDUP_XXX flags.
**
** The value returned includes space to create a copy of the Expr struct
** itself and the buffer referred to by Expr.token, if any. If the
** EXPRDUP_SPAN flag is set, then space to create a copy of the buffer
** refered to by Expr.span is also included.
**
** If the EXPRDUP_REDUCE flag is set, then the return value includes
** space to duplicate all Expr nodes in the tree formed by Expr.pLeft
** and Expr.pRight variables (but not for any structures pointed to or
** descended from the Expr.x.pList or Expr.x.pSelect variables).
*/
static int dupedExprSize(Expr *p, int flags){
int nByte = 0;
if( p ){
nByte = dupedExprNodeSize(p, flags);
if( flags&EXPRDUP_REDUCE ){
int f = flags&(~EXPRDUP_SPAN);
nByte += dupedExprSize(p->pLeft, f) + dupedExprSize(p->pRight, f);
}
}
return nByte;
}
/*
** This function is similar to sqlite3ExprDup(), except that if pzBuffer
** is not NULL then *pzBuffer is assumed to point to a buffer large enough
** to store the copy of expression p, the copies of p->token and p->span
** (if applicable), and the copies of the p->pLeft and p->pRight expressions,
** if any. Before returning, *pzBuffer is set to the first byte passed the
** portion of the buffer copied into by this function.
*/
static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){
Expr *pNew = 0; /* Value to return */
if( p ){
const int isRequireSpan = (flags&EXPRDUP_SPAN);
const int isReduced = (flags&EXPRDUP_REDUCE);
u8 *zAlloc;
assert( pzBuffer==0 || isReduced );
/* Figure out where to write the new Expr structure. */
if( pzBuffer ){
zAlloc = *pzBuffer;
}else{
zAlloc = sqlite3DbMallocRaw(db, dupedExprSize(p, flags));
}
pNew = (Expr *)zAlloc;
if( pNew ){
/* Set nNewSize to the size allocated for the structure pointed to
** by pNew. This is either EXPR_FULLSIZE, EXPR_REDUCEDSIZE or
** EXPR_TOKENONLYSIZE. nToken is set to the number of bytes consumed
** by the copy of the p->token.z string (if any).
*/
const int nNewSize = dupedExprStructSize(p, flags);
const int nToken = (p->token.z ? p->token.n + 1 : 0);
if( isReduced ){
assert( ExprHasProperty(p, EP_Reduced)==0 );
memcpy(zAlloc, p, nNewSize);
}else{
int nSize = exprStructSize(p);
memcpy(zAlloc, p, nSize);
memset(&zAlloc[nSize], 0, EXPR_FULLSIZE-nSize);
}
/* Set the EP_Reduced and EP_TokenOnly flags appropriately. */
pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_SpanToken);
switch( nNewSize ){
case EXPR_REDUCEDSIZE: pNew->flags |= EP_Reduced; break;
case EXPR_TOKENONLYSIZE: pNew->flags |= EP_TokenOnly; break;
case EXPR_SPANTOKENSIZE: pNew->flags |= EP_SpanToken; break;
}
/* Copy the p->token string, if any. */
if( nToken ){
unsigned char *zToken = &zAlloc[nNewSize];
memcpy(zToken, p->token.z, nToken-1);
zToken[nToken-1] = '\0';
pNew->token.dyn = 0;
pNew->token.z = zToken;
}
if( 0==((p->flags|pNew->flags) & EP_TokenOnly) ){
/* Fill in the pNew->span token, if required. */
if( isRequireSpan ){
if( p->token.z!=p->span.z || p->token.n!=p->span.n ){
pNew->span.z = &zAlloc[nNewSize+nToken];
memcpy((char *)pNew->span.z, p->span.z, p->span.n);
pNew->span.dyn = 0;
}else{
pNew->span.z = pNew->token.z;
pNew->span.n = pNew->token.n;
}
}else{
pNew->span.z = 0;
pNew->span.n = 0;
}
}
if( 0==((p->flags|pNew->flags) & (EP_TokenOnly|EP_SpanToken)) ){
/* Fill in the pNew->x.pSelect or pNew->x.pList member. */
if( ExprHasProperty(p, EP_xIsSelect) ){
pNew->x.pSelect = sqlite3SelectDup(db, p->x.pSelect, isReduced);
}else{
pNew->x.pList = sqlite3ExprListDup(db, p->x.pList, isReduced);
}
}
/* Fill in pNew->pLeft and pNew->pRight. */
if( ExprHasAnyProperty(pNew, EP_Reduced|EP_TokenOnly|EP_SpanToken) ){
zAlloc += dupedExprNodeSize(p, flags);
if( ExprHasProperty(pNew, EP_Reduced) ){
pNew->pLeft = exprDup(db, p->pLeft, EXPRDUP_REDUCE, &zAlloc);
pNew->pRight = exprDup(db, p->pRight, EXPRDUP_REDUCE, &zAlloc);
}
if( pzBuffer ){
*pzBuffer = zAlloc;
}
}else if( !ExprHasAnyProperty(p, EP_TokenOnly|EP_SpanToken) ){
pNew->pLeft = sqlite3ExprDup(db, p->pLeft, 0);
pNew->pRight = sqlite3ExprDup(db, p->pRight, 0);
}
}
}
return pNew;
}
/*
@ -650,27 +861,21 @@ void sqlite3DequoteExpr(sqlite3 *db, Expr *p){
** by subsequent calls to sqlite*ListAppend() routines.
**
** Any tables that the SrcList might point to are not duplicated.
**
** The flags parameter contains a combination of the EXPRDUP_XXX flags. If
** the EXPRDUP_SPAN flag is set in the argument parameter, then the
** Expr.span field of the input expression is copied. If EXPRDUP_SPAN is
** clear, then the Expr.span field of the returned expression structure
** is zeroed.
**
** If the EXPRDUP_REDUCE flag is set, then the structure returned is a
** truncated version of the usual Expr structure that will be stored as
** part of the in-memory representation of the database schema.
*/
Expr *sqlite3ExprDup(sqlite3 *db, Expr *p){
Expr *pNew;
if( p==0 ) return 0;
pNew = sqlite3DbMallocRaw(db, sizeof(*p) );
if( pNew==0 ) return 0;
memcpy(pNew, p, sizeof(*pNew));
if( p->token.z!=0 ){
pNew->token.z = (u8*)sqlite3DbStrNDup(db, (char*)p->token.z, p->token.n);
pNew->token.dyn = 1;
}else{
assert( pNew->token.z==0 );
}
pNew->span.z = 0;
pNew->pLeft = sqlite3ExprDup(db, p->pLeft);
pNew->pRight = sqlite3ExprDup(db, p->pRight);
pNew->pList = sqlite3ExprListDup(db, p->pList);
pNew->pSelect = sqlite3SelectDup(db, p->pSelect);
return pNew;
Expr *sqlite3ExprDup(sqlite3 *db, Expr *p, int flags){
return exprDup(db, p, flags, 0);
}
void sqlite3TokenCopy(sqlite3 *db, Token *pTo, Token *pFrom){
void sqlite3TokenCopy(sqlite3 *db, Token *pTo, const Token *pFrom){
if( pTo->dyn ) sqlite3DbFree(db, (char*)pTo->z);
if( pFrom->z ){
pTo->n = pFrom->n;
@ -680,7 +885,7 @@ void sqlite3TokenCopy(sqlite3 *db, Token *pTo, Token *pFrom){
pTo->z = 0;
}
}
ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p){
ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){
ExprList *pNew;
struct ExprList_item *pItem, *pOldItem;
int i;
@ -696,17 +901,9 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p){
}
pOldItem = p->a;
for(i=0; i<p->nExpr; i++, pItem++, pOldItem++){
Expr *pNewExpr, *pOldExpr;
pItem->pExpr = pNewExpr = sqlite3ExprDup(db, pOldExpr = pOldItem->pExpr);
if( pOldExpr->span.z!=0 && pNewExpr ){
/* Always make a copy of the span for top-level expressions in the
** expression list. The logic in SELECT processing that determines
** the names of columns in the result set needs this information */
sqlite3TokenCopy(db, &pNewExpr->span, &pOldExpr->span);
}
assert( pNewExpr==0 || pNewExpr->span.z!=0
|| pOldExpr->span.z==0
|| db->mallocFailed );
Expr *pNewExpr;
Expr *pOldExpr = pOldItem->pExpr;
pItem->pExpr = pNewExpr = sqlite3ExprDup(db, pOldExpr, flags);
pItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
pItem->sortOrder = pOldItem->sortOrder;
pItem->done = 0;
@ -724,7 +921,7 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p){
*/
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) \
|| !defined(SQLITE_OMIT_SUBQUERY)
SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p){
SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){
SrcList *pNew;
int i;
int nByte;
@ -750,8 +947,8 @@ SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p){
if( pTab ){
pTab->nRef++;
}
pNewItem->pSelect = sqlite3SelectDup(db, pOldItem->pSelect);
pNewItem->pOn = sqlite3ExprDup(db, pOldItem->pOn);
pNewItem->pSelect = sqlite3SelectDup(db, pOldItem->pSelect, flags);
pNewItem->pOn = sqlite3ExprDup(db, pOldItem->pOn, flags);
pNewItem->pUsing = sqlite3IdListDup(db, pOldItem->pUsing);
pNewItem->colUsed = pOldItem->colUsed;
}
@ -777,21 +974,24 @@ IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){
}
return pNew;
}
Select *sqlite3SelectDup(sqlite3 *db, Select *p){
Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
Select *pNew;
if( p==0 ) return 0;
pNew = sqlite3DbMallocRaw(db, sizeof(*p) );
if( pNew==0 ) return 0;
pNew->pEList = sqlite3ExprListDup(db, p->pEList);
pNew->pSrc = sqlite3SrcListDup(db, p->pSrc);
pNew->pWhere = sqlite3ExprDup(db, p->pWhere);
pNew->pGroupBy = sqlite3ExprListDup(db, p->pGroupBy);
pNew->pHaving = sqlite3ExprDup(db, p->pHaving);
pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy);
/* Always make a copy of the span for top-level expressions in the
** expression list. The logic in SELECT processing that determines
** the names of columns in the result set needs this information */
pNew->pEList = sqlite3ExprListDup(db, p->pEList, flags|EXPRDUP_SPAN);
pNew->pSrc = sqlite3SrcListDup(db, p->pSrc, flags);
pNew->pWhere = sqlite3ExprDup(db, p->pWhere, flags);
pNew->pGroupBy = sqlite3ExprListDup(db, p->pGroupBy, flags);
pNew->pHaving = sqlite3ExprDup(db, p->pHaving, flags);
pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, flags);
pNew->op = p->op;
pNew->pPrior = sqlite3SelectDup(db, p->pPrior);
pNew->pLimit = sqlite3ExprDup(db, p->pLimit);
pNew->pOffset = sqlite3ExprDup(db, p->pOffset);
pNew->pPrior = sqlite3SelectDup(db, p->pPrior, flags);
pNew->pLimit = sqlite3ExprDup(db, p->pLimit, flags);
pNew->pOffset = sqlite3ExprDup(db, p->pOffset, flags);
pNew->iLimit = 0;
pNew->iOffset = 0;
pNew->selFlags = p->selFlags & ~SF_UsesEphemeral;
@ -802,7 +1002,7 @@ Select *sqlite3SelectDup(sqlite3 *db, Select *p){
return pNew;
}
#else
Select *sqlite3SelectDup(sqlite3 *db, Select *p){
Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
assert( p==0 );
return 0;
}
@ -1143,13 +1343,19 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
** If this is the case, it may be possible to use an existing table
** or index instead of generating an epheremal table.
*/
p = pX->pSelect;
p = (ExprHasProperty(pX, EP_xIsSelect) ? pX->x.pSelect : 0);
if( isCandidateForInOpt(p) ){
sqlite3 *db = pParse->db;
Index *pIdx;
Expr *pExpr = p->pEList->a[0].pExpr;
int iCol = pExpr->iColumn;
Vdbe *v = sqlite3GetVdbe(pParse);
sqlite3 *db = pParse->db; /* Database connection */
Expr *pExpr = p->pEList->a[0].pExpr; /* Expression <column> */
int iCol = pExpr->iColumn; /* Index of column <column> */
Vdbe *v = sqlite3GetVdbe(pParse); /* Virtual machine being coded */
Table *pTab = p->pSrc->a[0].pTab; /* Table <table>. */
int iDb; /* Database idx for pTab */
/* Code an OP_VerifyCookie and OP_TableLock for <table>. */
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
sqlite3CodeVerifySchema(pParse, iDb);
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
/* This function is only called from two places. In both cases the vdbe
** has already been allocated. So assume sqlite3GetVdbe() is always
@ -1159,8 +1365,6 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
if( iCol<0 ){
int iMem = ++pParse->nMem;
int iAddr;
Table *pTab = p->pSrc->a[0].pTab;
int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
sqlite3VdbeUsesBtree(v, iDb);
iAddr = sqlite3VdbeAddOp1(v, OP_If, iMem);
@ -1171,17 +1375,17 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
sqlite3VdbeJumpHere(v, iAddr);
}else{
Index *pIdx; /* Iterator variable */
/* The collation sequence used by the comparison. If an index is to
** be used in place of a temp-table, it must be ordered according
** to this collation sequence.
*/
** to this collation sequence. */
CollSeq *pReq = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pExpr);
/* Check that the affinity that will be used to perform the
** comparison is the same as the affinity of the column. If
** it is not, it is not possible to use any index.
*/
Table *pTab = p->pSrc->a[0].pTab;
char aff = comparisonAffinity(pX);
int affinity_ok = (pTab->aCol[iCol].affinity==aff||aff==SQLITE_AFF_NONE);
@ -1190,7 +1394,6 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
&& (pReq==sqlite3FindCollSeq(db, ENC(db), pIdx->azColl[0], -1, 0))
&& (!mustBeUnique || (pIdx->nColumn==1 && pIdx->onError!=OE_None))
){
int iDb;
int iMem = ++pParse->nMem;
int iAddr;
char *pKey;
@ -1202,7 +1405,6 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
iAddr = sqlite3VdbeAddOp1(v, OP_If, iMem);
sqlite3VdbeAddOp2(v, OP_Integer, 1, iMem);
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, pIdx->nColumn);
sqlite3VdbeAddOp4(v, OP_OpenRead, iTab, pIdx->tnum, iDb,
pKey,P4_KEYINFO_HANDOFF);
VdbeComment((v, "%s", pIdx->zName));
@ -1222,7 +1424,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
eType = IN_INDEX_EPH;
if( prNotFound ){
*prNotFound = rMayHaveNull = ++pParse->nMem;
}else if( pX->pLeft->iColumn<0 && pX->pSelect==0 ){
}else if( pX->pLeft->iColumn<0 && !ExprHasAnyProperty(pX, EP_xIsSelect) ){
eType = IN_INDEX_ROWID;
}
sqlite3CodeSubselect(pParse, pX, rMayHaveNull, eType==IN_INDEX_ROWID);
@ -1311,7 +1513,7 @@ void sqlite3CodeSubselect(
memset(&keyInfo, 0, sizeof(keyInfo));
keyInfo.nField = 1;
if( pExpr->pSelect ){
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
/* Case 1: expr IN (SELECT ...)
**
** Generate code to write the results of the select into the temporary
@ -1324,15 +1526,15 @@ void sqlite3CodeSubselect(
sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
dest.affinity = (u8)affinity;
assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
if( sqlite3Select(pParse, pExpr->pSelect, &dest) ){
if( sqlite3Select(pParse, pExpr->x.pSelect, &dest) ){
return;
}
pEList = pExpr->pSelect->pEList;
pEList = pExpr->x.pSelect->pEList;
if( pEList && pEList->nExpr>0 ){
keyInfo.aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft,
pEList->a[0].pExpr);
}
}else if( pExpr->pList ){
}else if( pExpr->x.pList ){
/* Case 2: expr IN (exprlist)
**
** For each expression, build an index key from the evaluation and
@ -1341,7 +1543,7 @@ void sqlite3CodeSubselect(
** a column, use numeric affinity.
*/
int i;
ExprList *pList = pExpr->pList;
ExprList *pList = pExpr->x.pList;
struct ExprList_item *pItem;
int r1, r2, r3;
@ -1401,7 +1603,8 @@ void sqlite3CodeSubselect(
Select *pSel;
SelectDest dest;
pSel = pExpr->pSelect;
assert( ExprHasProperty(pExpr, EP_xIsSelect) );
pSel = pExpr->x.pSelect;
sqlite3SelectDestInit(&dest, 0, ++pParse->nMem);
if( pExpr->op==TK_SELECT ){
dest.eDest = SRT_Mem;
@ -1795,7 +1998,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
break;
}
case TK_STRING: {
sqlite3DequoteExpr(db, pExpr);
sqlite3DequoteExpr(pExpr);
sqlite3VdbeAddOp4(v,OP_String8, 0, target, 0,
(char*)pExpr->token.z, pExpr->token.n);
break;
@ -1821,9 +2024,26 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
}
#endif
case TK_VARIABLE: {
sqlite3VdbeAddOp2(v, OP_Variable, pExpr->iTable, target);
if( pExpr->token.n>1 ){
sqlite3VdbeChangeP4(v, -1, (char*)pExpr->token.z, pExpr->token.n);
int iPrior;
VdbeOp *pOp;
if( pExpr->token.n<=1
&& (iPrior = sqlite3VdbeCurrentAddr(v)-1)>=0
&& (pOp = sqlite3VdbeGetOp(v, iPrior))->opcode==OP_Variable
&& pOp->p1+pOp->p3==pExpr->iTable
&& pOp->p2+pOp->p3==target
&& pOp->p4.z==0
){
/* If the previous instruction was a copy of the previous unnamed
** parameter into the previous register, then simply increment the
** repeat count on the prior instruction rather than making a new
** instruction.
*/
pOp->p3++;
}else{
sqlite3VdbeAddOp3(v, OP_Variable, pExpr->iTable, target, 1);
if( pExpr->token.n>1 ){
sqlite3VdbeChangeP4(v, -1, (char*)pExpr->token.z, pExpr->token.n);
}
}
break;
}
@ -1985,28 +2205,34 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
}
case TK_CONST_FUNC:
case TK_FUNCTION: {
ExprList *pList = pExpr->pList;
int nExpr = pList ? pList->nExpr : 0;
FuncDef *pDef;
int nId;
const char *zId;
int constMask = 0;
int i;
u8 enc = ENC(db);
CollSeq *pColl = 0;
ExprList *pFarg; /* List of function arguments */
int nFarg; /* Number of function arguments */
FuncDef *pDef; /* The function definition object */
int nId; /* Length of the function name in bytes */
const char *zId; /* The function name */
int constMask = 0; /* Mask of function arguments that are constant */
int i; /* Loop counter */
u8 enc = ENC(db); /* The text encoding used by this database */
CollSeq *pColl = 0; /* A collating sequence */
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
testcase( op==TK_CONST_FUNC );
testcase( op==TK_FUNCTION );
if( ExprHasAnyProperty(pExpr, EP_TokenOnly|EP_SpanToken) ){
pFarg = 0;
}else{
pFarg = pExpr->x.pList;
}
nFarg = pFarg ? pFarg->nExpr : 0;
zId = (char*)pExpr->token.z;
nId = pExpr->token.n;
pDef = sqlite3FindFunction(db, zId, nId, nExpr, enc, 0);
pDef = sqlite3FindFunction(db, zId, nId, nFarg, enc, 0);
assert( pDef!=0 );
if( pList ){
nExpr = pList->nExpr;
r1 = sqlite3GetTempRange(pParse, nExpr);
sqlite3ExprCodeExprList(pParse, pList, r1, 1);
if( pFarg ){
r1 = sqlite3GetTempRange(pParse, nFarg);
sqlite3ExprCodeExprList(pParse, pFarg, r1, 1);
}else{
nExpr = r1 = 0;
r1 = 0;
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Possibly overload the function if the first argument is
@ -2021,18 +2247,18 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
** "glob(B,A). We want to use the A in "A glob B" to test
** for function overloading. But we use the B term in "glob(B,A)".
*/
if( nExpr>=2 && (pExpr->flags & EP_InfixFunc) ){
pDef = sqlite3VtabOverloadFunction(db, pDef, nExpr, pList->a[1].pExpr);
}else if( nExpr>0 ){
pDef = sqlite3VtabOverloadFunction(db, pDef, nExpr, pList->a[0].pExpr);
if( nFarg>=2 && (pExpr->flags & EP_InfixFunc) ){
pDef = sqlite3VtabOverloadFunction(db, pDef, nFarg, pFarg->a[1].pExpr);
}else if( nFarg>0 ){
pDef = sqlite3VtabOverloadFunction(db, pDef, nFarg, pFarg->a[0].pExpr);
}
#endif
for(i=0; i<nExpr && i<32; i++){
if( sqlite3ExprIsConstant(pList->a[i].pExpr) ){
for(i=0; i<nFarg && i<32; i++){
if( sqlite3ExprIsConstant(pFarg->a[i].pExpr) ){
constMask |= (1<<i);
}
if( (pDef->flags & SQLITE_FUNC_NEEDCOLL)!=0 && !pColl ){
pColl = sqlite3ExprCollSeq(pParse, pList->a[i].pExpr);
pColl = sqlite3ExprCollSeq(pParse, pFarg->a[i].pExpr);
}
}
if( pDef->flags & SQLITE_FUNC_NEEDCOLL ){
@ -2041,11 +2267,11 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
}
sqlite3VdbeAddOp4(v, OP_Function, constMask, r1, target,
(char*)pDef, P4_FUNCDEF);
sqlite3VdbeChangeP5(v, (u8)nExpr);
if( nExpr ){
sqlite3ReleaseTempRange(pParse, r1, nExpr);
sqlite3VdbeChangeP5(v, (u8)nFarg);
if( nFarg ){
sqlite3ReleaseTempRange(pParse, r1, nFarg);
}
sqlite3ExprCacheAffinityChange(pParse, r1, nExpr);
sqlite3ExprCacheAffinityChange(pParse, r1, nFarg);
break;
}
#ifndef SQLITE_OMIT_SUBQUERY
@ -2162,7 +2388,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
*/
case TK_BETWEEN: {
Expr *pLeft = pExpr->pLeft;
struct ExprList_item *pLItem = pExpr->pList->a;
struct ExprList_item *pLItem = pExpr->x.pList->a;
Expr *pRight = pLItem->pExpr;
codeCompareOperands(pParse, pLeft, &r1, &regFree1,
@ -2222,10 +2448,10 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
Expr *pX; /* The X expression */
Expr *pTest = 0; /* X==Ei (form A) or just Ei (form B) */
assert(pExpr->pList);
assert((pExpr->pList->nExpr % 2) == 0);
assert(pExpr->pList->nExpr > 0);
pEList = pExpr->pList;
assert( !ExprHasProperty(pExpr, EP_xIsSelect) && pExpr->x.pList );
assert((pExpr->x.pList->nExpr % 2) == 0);
assert(pExpr->x.pList->nExpr > 0);
pEList = pExpr->x.pList;
aListelem = pEList->a;
nExpr = pEList->nExpr;
endLabel = sqlite3VdbeMakeLabel(v);
@ -2273,15 +2499,15 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
"RAISE() may only be used within a trigger-program");
return 0;
}
if( pExpr->iColumn!=OE_Ignore ){
assert( pExpr->iColumn==OE_Rollback ||
pExpr->iColumn == OE_Abort ||
pExpr->iColumn == OE_Fail );
sqlite3DequoteExpr(db, pExpr);
sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, pExpr->iColumn, 0,
if( pExpr->affinity!=OE_Ignore ){
assert( pExpr->affinity==OE_Rollback ||
pExpr->affinity == OE_Abort ||
pExpr->affinity == OE_Fail );
sqlite3DequoteExpr(pExpr);
sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, pExpr->affinity, 0,
(char*)pExpr->token.z, pExpr->token.n);
} else {
assert( pExpr->iColumn == OE_Ignore );
assert( pExpr->affinity == OE_Ignore );
sqlite3VdbeAddOp2(v, OP_ContextPop, 0, 0);
sqlite3VdbeAddOp2(v, OP_Goto, 0, pParse->trigStack->ignoreJump);
VdbeComment((v, "raise(IGNORE)"));
@ -2438,7 +2664,8 @@ static int evalConstExpr(Walker *pWalker, Expr *pExpr){
** Mark them this way to avoid generated unneeded OP_SCopy
** instructions.
*/
ExprList *pList = pExpr->pList;
ExprList *pList = pExpr->x.pList;
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
if( pList ){
int i = pList->nExpr;
struct ExprList_item *pItem = pList->a;
@ -2614,16 +2841,17 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
Expr compRight;
Expr exprX;
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
exprX = *pExpr->pLeft;
exprAnd.op = TK_AND;
exprAnd.pLeft = &compLeft;
exprAnd.pRight = &compRight;
compLeft.op = TK_GE;
compLeft.pLeft = &exprX;
compLeft.pRight = pExpr->pList->a[0].pExpr;
compLeft.pRight = pExpr->x.pList->a[0].pExpr;
compRight.op = TK_LE;
compRight.pLeft = &exprX;
compRight.pRight = pExpr->pList->a[1].pExpr;
compRight.pRight = pExpr->x.pList->a[1].pExpr;
exprX.iTable = sqlite3ExprCodeTemp(pParse, &exprX, &regFree1);
testcase( regFree1==0 );
exprX.op = TK_REGISTER;
@ -2765,16 +2993,17 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
Expr compRight;
Expr exprX;
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
exprX = *pExpr->pLeft;
exprAnd.op = TK_AND;
exprAnd.pLeft = &compLeft;
exprAnd.pRight = &compRight;
compLeft.op = TK_GE;
compLeft.pLeft = &exprX;
compLeft.pRight = pExpr->pList->a[0].pExpr;
compLeft.pRight = pExpr->x.pList->a[0].pExpr;
compRight.op = TK_LE;
compRight.pLeft = &exprX;
compRight.pRight = pExpr->pList->a[1].pExpr;
compRight.pRight = pExpr->x.pList->a[1].pExpr;
exprX.iTable = sqlite3ExprCodeTemp(pParse, &exprX, &regFree1);
testcase( regFree1==0 );
exprX.op = TK_REGISTER;
@ -2813,22 +3042,25 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
if( pA==0||pB==0 ){
return pB==pA;
}
if( pA->op!=pB->op ) return 0;
if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 0;
if( !sqlite3ExprCompare(pA->pLeft, pB->pLeft) ) return 0;
if( !sqlite3ExprCompare(pA->pRight, pB->pRight) ) return 0;
if( pA->pList ){
if( pB->pList==0 ) return 0;
if( pA->pList->nExpr!=pB->pList->nExpr ) return 0;
for(i=0; i<pA->pList->nExpr; i++){
if( !sqlite3ExprCompare(pA->pList->a[i].pExpr, pB->pList->a[i].pExpr) ){
return 0;
}
}
}else if( pB->pList ){
if( ExprHasProperty(pA, EP_xIsSelect) || ExprHasProperty(pB, EP_xIsSelect) ){
return 0;
}
if( pA->pSelect || pB->pSelect ) return 0;
if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 0;
if( pA->op!=pB->op ) return 0;
if( !sqlite3ExprCompare(pA->pLeft, pB->pLeft) ) return 0;
if( !sqlite3ExprCompare(pA->pRight, pB->pRight) ) return 0;
if( pA->x.pList && pB->x.pList ){
if( pA->x.pList->nExpr!=pB->x.pList->nExpr ) return 0;
for(i=0; i<pA->x.pList->nExpr; i++){
Expr *pExprA = pA->x.pList->a[i].pExpr;
Expr *pExprB = pB->x.pList->a[i].pExpr;
if( !sqlite3ExprCompare(pExprA, pExprB) ) return 0;
}
}else if( pA->x.pList || pB->x.pList ){
return 0;
}
if( pA->iTable!=pB->iTable || pA->iColumn!=pB->iColumn ) return 0;
if( pA->op!=TK_COLUMN && pA->token.z ){
if( pB->token.z==0 ) return 0;
@ -2976,12 +3208,13 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
u8 enc = ENC(pParse->db);
i = addAggInfoFunc(pParse->db, pAggInfo);
if( i>=0 ){
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
pItem = &pAggInfo->aFunc[i];
pItem->pExpr = pExpr;
pItem->iMem = ++pParse->nMem;
pItem->pFunc = sqlite3FindFunction(pParse->db,
(char*)pExpr->token.z, pExpr->token.n,
pExpr->pList ? pExpr->pList->nExpr : 0, enc, 0);
pExpr->x.pList ? pExpr->x.pList->nExpr : 0, enc, 0);
if( pExpr->flags & EP_Distinct ){
pItem->iDistinct = pParse->nTab++;
}else{

View File

@ -16,7 +16,7 @@
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
** All other code has file scope.
**
** $Id: func.c,v 1.222 2009/02/04 03:59:25 shane Exp $
** $Id: func.c,v 1.231 2009/04/08 23:04:14 drh Exp $
*/
#include "sqliteInt.h"
#include <stdlib.h>
@ -266,16 +266,22 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
/*
** Allocate nByte bytes of space using sqlite3_malloc(). If the
** allocation fails, call sqlite3_result_error_nomem() to notify
** the database handle that malloc() has failed.
** the database handle that malloc() has failed and return NULL.
** If nByte is larger than the maximum string or blob length, then
** raise an SQLITE_TOOBIG exception and return NULL.
*/
static void *contextMalloc(sqlite3_context *context, i64 nByte){
char *z;
if( nByte>sqlite3_context_db_handle(context)->aLimit[SQLITE_LIMIT_LENGTH] ){
sqlite3 *db = sqlite3_context_db_handle(context);
assert( nByte>0 );
testcase( nByte==db->aLimit[SQLITE_LIMIT_LENGTH] );
testcase( nByte==db->aLimit[SQLITE_LIMIT_LENGTH]+1 );
if( nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){
sqlite3_result_error_toobig(context);
z = 0;
}else{
z = sqlite3Malloc((int)nByte);
if( !z && nByte>0 ){
if( !z ){
sqlite3_result_error_nomem(context);
}
}
@ -356,8 +362,17 @@ static void randomFunc(
sqlite_int64 r;
UNUSED_PARAMETER2(NotUsed, NotUsed2);
sqlite3_randomness(sizeof(r), &r);
if( (r<<1)==0 ) r = 0; /* Prevent 0x8000.... as the result so that we */
/* can always do abs() of the result */
if( r<0 ){
/* We need to prevent a random number of 0x8000000000000000
** (or -9223372036854775808) since when you do abs() of that
** number of you get the same value back again. To do this
** in a way that is testable, mask the sign bit off of negative
** values, resulting in a positive value. Then take the
** 2s complement of that positive value. The end result can
** therefore be no less than -9223372036854775807.
*/
r = -(r ^ (((sqlite3_int64)1)<<63));
}
sqlite3_result_int64(context, r);
}
@ -444,7 +459,7 @@ struct compareInfo {
** whereas only characters less than 0x80 do in ASCII.
*/
#if defined(SQLITE_EBCDIC)
# define sqlite3Utf8Read(A,B,C) (*(A++))
# define sqlite3Utf8Read(A,C) (*(A++))
# define GlogUpperToLower(A) A = sqlite3UpperToLower[A]
#else
# define GlogUpperToLower(A) if( A<0x80 ){ A = sqlite3UpperToLower[A]; }
@ -501,18 +516,18 @@ static int patternCompare(
u8 noCase = pInfo->noCase;
int prevEscape = 0; /* True if the previous character was 'escape' */
while( (c = sqlite3Utf8Read(zPattern,0,&zPattern))!=0 ){
while( (c = sqlite3Utf8Read(zPattern,&zPattern))!=0 ){
if( !prevEscape && c==matchAll ){
while( (c=sqlite3Utf8Read(zPattern,0,&zPattern)) == matchAll
while( (c=sqlite3Utf8Read(zPattern,&zPattern)) == matchAll
|| c == matchOne ){
if( c==matchOne && sqlite3Utf8Read(zString, 0, &zString)==0 ){
if( c==matchOne && sqlite3Utf8Read(zString, &zString)==0 ){
return 0;
}
}
if( c==0 ){
return 1;
}else if( c==esc ){
c = sqlite3Utf8Read(zPattern, 0, &zPattern);
c = sqlite3Utf8Read(zPattern, &zPattern);
if( c==0 ){
return 0;
}
@ -524,17 +539,17 @@ static int patternCompare(
}
return *zString!=0;
}
while( (c2 = sqlite3Utf8Read(zString,0,&zString))!=0 ){
while( (c2 = sqlite3Utf8Read(zString,&zString))!=0 ){
if( noCase ){
GlogUpperToLower(c2);
GlogUpperToLower(c);
while( c2 != 0 && c2 != c ){
c2 = sqlite3Utf8Read(zString, 0, &zString);
c2 = sqlite3Utf8Read(zString, &zString);
GlogUpperToLower(c2);
}
}else{
while( c2 != 0 && c2 != c ){
c2 = sqlite3Utf8Read(zString, 0, &zString);
c2 = sqlite3Utf8Read(zString, &zString);
}
}
if( c2==0 ) return 0;
@ -542,7 +557,7 @@ static int patternCompare(
}
return 0;
}else if( !prevEscape && c==matchOne ){
if( sqlite3Utf8Read(zString, 0, &zString)==0 ){
if( sqlite3Utf8Read(zString, &zString)==0 ){
return 0;
}
}else if( c==matchSet ){
@ -550,20 +565,20 @@ static int patternCompare(
assert( esc==0 ); /* This only occurs for GLOB, not LIKE */
seen = 0;
invert = 0;
c = sqlite3Utf8Read(zString, 0, &zString);
c = sqlite3Utf8Read(zString, &zString);
if( c==0 ) return 0;
c2 = sqlite3Utf8Read(zPattern, 0, &zPattern);
c2 = sqlite3Utf8Read(zPattern, &zPattern);
if( c2=='^' ){
invert = 1;
c2 = sqlite3Utf8Read(zPattern, 0, &zPattern);
c2 = sqlite3Utf8Read(zPattern, &zPattern);
}
if( c2==']' ){
if( c==']' ) seen = 1;
c2 = sqlite3Utf8Read(zPattern, 0, &zPattern);
c2 = sqlite3Utf8Read(zPattern, &zPattern);
}
while( c2 && c2!=']' ){
if( c2=='-' && zPattern[0]!=']' && zPattern[0]!=0 && prior_c>0 ){
c2 = sqlite3Utf8Read(zPattern, 0, &zPattern);
c2 = sqlite3Utf8Read(zPattern, &zPattern);
if( c>=prior_c && c<=c2 ) seen = 1;
prior_c = 0;
}else{
@ -572,7 +587,7 @@ static int patternCompare(
}
prior_c = c2;
}
c2 = sqlite3Utf8Read(zPattern, 0, &zPattern);
c2 = sqlite3Utf8Read(zPattern, &zPattern);
}
if( c2==0 || (seen ^ invert)==0 ){
return 0;
@ -580,7 +595,7 @@ static int patternCompare(
}else if( esc==c && !prevEscape ){
prevEscape = 1;
}else{
c2 = sqlite3Utf8Read(zString, 0, &zString);
c2 = sqlite3Utf8Read(zString, &zString);
if( noCase ){
GlogUpperToLower(c);
GlogUpperToLower(c2);
@ -623,6 +638,7 @@ static void likeFunc(
){
const unsigned char *zA, *zB;
int escape = 0;
int nPat;
sqlite3 *db = sqlite3_context_db_handle(context);
zB = sqlite3_value_text(argv[0]);
@ -631,8 +647,10 @@ static void likeFunc(
/* Limit the length of the LIKE or GLOB pattern to avoid problems
** of deep recursion and N*N behavior in patternCompare().
*/
if( sqlite3_value_bytes(argv[0]) >
db->aLimit[SQLITE_LIMIT_LIKE_PATTERN_LENGTH] ){
nPat = sqlite3_value_bytes(argv[0]);
testcase( nPat==db->aLimit[SQLITE_LIMIT_LIKE_PATTERN_LENGTH] );
testcase( nPat==db->aLimit[SQLITE_LIMIT_LIKE_PATTERN_LENGTH]+1 );
if( nPat > db->aLimit[SQLITE_LIMIT_LIKE_PATTERN_LENGTH] ){
sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1);
return;
}
@ -649,7 +667,7 @@ static void likeFunc(
"ESCAPE expression must be a single character", -1);
return;
}
escape = sqlite3Utf8Read(zEsc, 0, &zEsc);
escape = sqlite3Utf8Read(zEsc, &zEsc);
}
if( zA && zB ){
struct compareInfo *pInfo = sqlite3_user_data(context);
@ -808,10 +826,13 @@ static void zeroblobFunc(
sqlite3_value **argv
){
i64 n;
sqlite3 *db = sqlite3_context_db_handle(context);
assert( argc==1 );
UNUSED_PARAMETER(argc);
n = sqlite3_value_int64(argv[0]);
if( n>SQLITE_MAX_LENGTH ){
testcase( n==db->aLimit[SQLITE_LIMIT_LENGTH] );
testcase( n==db->aLimit[SQLITE_LIMIT_LENGTH]+1 );
if( n>db->aLimit[SQLITE_LIMIT_LENGTH] ){
sqlite3_result_error_toobig(context);
}else{
sqlite3_result_zeroblob(context, (int)n);
@ -877,7 +898,9 @@ static void replaceFunc(
u8 *zOld;
sqlite3 *db = sqlite3_context_db_handle(context);
nOut += nRep - nPattern;
if( nOut>=db->aLimit[SQLITE_LIMIT_LENGTH] ){
testcase( nOut-1==db->aLimit[SQLITE_LIMIT_LENGTH] );
testcase( nOut-2==db->aLimit[SQLITE_LIMIT_LENGTH] );
if( nOut-1>db->aLimit[SQLITE_LIMIT_LENGTH] ){
sqlite3_result_error_toobig(context);
sqlite3DbFree(db, zOut);
return;
@ -961,7 +984,7 @@ static void trimFunc(
int len = 0;
for(i=0; i<nChar; i++){
len = aLen[i];
if( memcmp(zIn, azChar[i], len)==0 ) break;
if( len<=nIn && memcmp(zIn, azChar[i], len)==0 ) break;
}
if( i>=nChar ) break;
zIn += len;
@ -1155,6 +1178,13 @@ static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv){
if( (argc==0 || SQLITE_NULL!=sqlite3_value_type(argv[0])) && p ){
p->n++;
}
/* The sqlite3_aggregate_count() function is deprecated. But just to make
** sure it still operates correctly, verify that its count agrees with our
** internal count when using count(*) and when the total count can be
** expressed as a 32-bit integer. */
assert( argc==1 || p==0 || p->n>0x7fffffff
|| p->n==sqlite3_aggregate_count(context) );
}
static void countFinalize(sqlite3_context *context){
CountCtx *p;
@ -1203,7 +1233,7 @@ static void minMaxFinalize(sqlite3_context *context){
sqlite3_value *pRes;
pRes = (sqlite3_value *)sqlite3_aggregate_context(context, 0);
if( pRes ){
if( pRes->flags ){
if( ALWAYS(pRes->flags) ){
sqlite3_result_value(context, pRes);
}
sqlite3VdbeMemRelease(pRes);
@ -1288,7 +1318,7 @@ static void setLikeOptFlag(sqlite3 *db, const char *zName, u8 flagVal){
FuncDef *pDef;
pDef = sqlite3FindFunction(db, zName, sqlite3Strlen30(zName),
2, SQLITE_UTF8, 0);
if( pDef ){
if( ALWAYS(pDef) ){
pDef->flags = flagVal;
}
}
@ -1305,9 +1335,9 @@ void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){
}else{
pInfo = (struct compareInfo*)&likeInfoNorm;
}
sqlite3CreateFunc(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0);
sqlite3CreateFunc(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0);
sqlite3CreateFunc(db, "glob", 2, SQLITE_UTF8,
sqlite3CreateFunc(db, "like", 2, SQLITE_ANY, pInfo, likeFunc, 0, 0);
sqlite3CreateFunc(db, "like", 3, SQLITE_ANY, pInfo, likeFunc, 0, 0);
sqlite3CreateFunc(db, "glob", 2, SQLITE_ANY,
(struct compareInfo*)&globInfo, likeFunc, 0,0);
setLikeOptFlag(db, "glob", SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE);
setLikeOptFlag(db, "like",
@ -1323,15 +1353,16 @@ void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){
*/
int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
FuncDef *pDef;
if( pExpr->op!=TK_FUNCTION || !pExpr->pList ){
return 0;
}
if( pExpr->pList->nExpr!=2 ){
if( pExpr->op!=TK_FUNCTION
|| !pExpr->x.pList
|| pExpr->x.pList->nExpr!=2
){
return 0;
}
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
pDef = sqlite3FindFunction(db, (char*)pExpr->token.z, pExpr->token.n, 2,
SQLITE_UTF8, 0);
if( pDef==0 || (pDef->flags & SQLITE_FUNC_LIKE)==0 ){
if( NEVER(pDef==0) || (pDef->flags & SQLITE_FUNC_LIKE)==0 ){
return 0;
}
@ -1412,7 +1443,8 @@ void sqlite3RegisterGlobalFunctions(void){
AGGREGATE(sum, 1, 0, 0, sumStep, sumFinalize ),
AGGREGATE(total, 1, 0, 0, sumStep, totalFinalize ),
AGGREGATE(avg, 1, 0, 0, sumStep, avgFinalize ),
AGGREGATE(count, 0, 0, 0, countStep, countFinalize ),
/* AGGREGATE(count, 0, 0, 0, countStep, countFinalize ), */
{0,SQLITE_UTF8,SQLITE_FUNC_COUNT,0,0,0,countStep,countFinalize,"count",0},
AGGREGATE(count, 1, 0, 0, countStep, countFinalize ),
AGGREGATE(group_concat, 1, 0, 0, groupConcatStep, groupConcatFinalize),
AGGREGATE(group_concat, 2, 0, 0, groupConcatStep, groupConcatFinalize),

View File

@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle INSERT statements in SQLite.
**
** $Id: insert.c,v 1.256 2008/12/10 21:19:57 drh Exp $
** $Id: insert.c,v 1.260 2009/02/28 10:47:42 danielk1977 Exp $
*/
#include "sqliteInt.h"
@ -168,7 +168,7 @@ static int autoIncBegin(
if( pTab->tabFlags & TF_Autoincrement ){
Vdbe *v = pParse->pVdbe;
Db *pDb = &pParse->db->aDb[iDb];
int iCur = pParse->nTab;
int iCur = pParse->nTab++;
int addr; /* Address of the top of the loop */
assert( v );
pParse->nMem++; /* Holds name of table */
@ -217,7 +217,7 @@ static void autoIncEnd(
int memId /* Memory cell holding the maximum rowid */
){
if( pTab->tabFlags & TF_Autoincrement ){
int iCur = pParse->nTab;
int iCur = pParse->nTab++;
Vdbe *v = pParse->pVdbe;
Db *pDb = &pParse->db->aDb[iDb];
int j1;
@ -401,7 +401,8 @@ void sqlite3Insert(
#ifndef SQLITE_OMIT_TRIGGER
int isView; /* True if attempting to insert into a view */
int triggers_exist = 0; /* True if there are FOR EACH ROW triggers */
Trigger *pTrigger; /* List of triggers on pTab, if required */
int tmask; /* Mask of trigger times */
#endif
db = pParse->db;
@ -431,22 +432,24 @@ void sqlite3Insert(
** inserted into is a view
*/
#ifndef SQLITE_OMIT_TRIGGER
triggers_exist = sqlite3TriggersExist(pTab, TK_INSERT, 0);
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_INSERT, 0, &tmask);
isView = pTab->pSelect!=0;
#else
# define triggers_exist 0
# define pTrigger 0
# define tmask 0
# define isView 0
#endif
#ifdef SQLITE_OMIT_VIEW
# undef isView
# define isView 0
#endif
assert( (pTrigger && tmask) || (pTrigger==0 && tmask==0) );
/* Ensure that:
* (a) the table is not read-only,
* (b) that if it is a view then ON INSERT triggers exist
*/
if( sqlite3IsReadOnly(pParse, pTab, triggers_exist) ){
if( sqlite3IsReadOnly(pParse, pTab, tmask) ){
goto insert_cleanup;
}
assert( pTab!=0 );
@ -464,10 +467,10 @@ void sqlite3Insert(
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto insert_cleanup;
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
sqlite3BeginWriteOperation(pParse, pSelect || triggers_exist, iDb);
sqlite3BeginWriteOperation(pParse, pSelect || pTrigger, iDb);
/* if there are row triggers, allocate a temp table for new.* references. */
if( triggers_exist ){
if( pTrigger ){
newIdx = pParse->nTab++;
}
@ -482,7 +485,7 @@ void sqlite3Insert(
** This is the 2nd template.
*/
if( pColumn==0 && xferOptimization(pParse, pTab, pSelect, onError, iDb) ){
assert( !triggers_exist );
assert( !pTrigger );
assert( pList==0 );
goto insert_cleanup;
}
@ -557,7 +560,7 @@ void sqlite3Insert(
** of the tables being read by the SELECT statement. Also use a
** temp table in the case of row triggers.
*/
if( triggers_exist || readsTable(v, addrSelect, iDb, pTab) ){
if( pTrigger || readsTable(v, addrSelect, iDb, pTab) ){
useTempTable = 1;
}
@ -676,9 +679,8 @@ void sqlite3Insert(
/* Open the temp table for FOR EACH ROW triggers
*/
if( triggers_exist ){
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, pTab->nCol);
sqlite3VdbeAddOp2(v, OP_OpenPseudo, newIdx, 0);
if( pTrigger ){
sqlite3VdbeAddOp3(v, OP_OpenPseudo, newIdx, 0, pTab->nCol);
}
/* Initialize the count of rows to be inserted
@ -745,7 +747,7 @@ void sqlite3Insert(
/* Run the BEFORE and INSTEAD OF triggers, if there are any
*/
endOfLoop = sqlite3VdbeMakeLabel(v);
if( triggers_exist & TRIGGER_BEFORE ){
if( tmask & TRIGGER_BEFORE ){
int regTrigRowid;
int regCols;
int regRec;
@ -813,8 +815,8 @@ void sqlite3Insert(
sqlite3ReleaseTempRange(pParse, regCols, pTab->nCol);
/* Fire BEFORE or INSTEAD OF triggers */
if( sqlite3CodeRowTrigger(pParse, TK_INSERT, 0, TRIGGER_BEFORE, pTab,
newIdx, -1, onError, endOfLoop, 0, 0) ){
if( sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_BEFORE,
pTab, newIdx, -1, onError, endOfLoop, 0, 0) ){
goto insert_cleanup;
}
}
@ -936,7 +938,7 @@ void sqlite3Insert(
regIns,
aRegIdx,
0,
(triggers_exist & TRIGGER_AFTER)!=0 ? newIdx : -1,
(tmask&TRIGGER_AFTER) ? newIdx : -1,
appendFlag
);
}
@ -948,10 +950,10 @@ void sqlite3Insert(
sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1);
}
if( triggers_exist ){
if( pTrigger ){
/* Code AFTER triggers */
if( sqlite3CodeRowTrigger(pParse, TK_INSERT, 0, TRIGGER_AFTER, pTab,
newIdx, -1, onError, endOfLoop, 0, 0) ){
if( sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_AFTER,
pTab, newIdx, -1, onError, endOfLoop, 0, 0) ){
goto insert_cleanup;
}
}
@ -1125,7 +1127,6 @@ void sqlite3GenerateConstraintChecks(
if( onError==OE_Replace && pTab->aCol[i].pDflt==0 ){
onError = OE_Abort;
}
j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regData+i);
assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
|| onError==OE_Ignore || onError==OE_Replace );
switch( onError ){
@ -1133,22 +1134,24 @@ void sqlite3GenerateConstraintChecks(
case OE_Abort:
case OE_Fail: {
char *zMsg;
sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_CONSTRAINT, onError);
j1 = sqlite3VdbeAddOp3(v, OP_HaltIfNull,
SQLITE_CONSTRAINT, onError, regData+i);
zMsg = sqlite3MPrintf(pParse->db, "%s.%s may not be NULL",
pTab->zName, pTab->aCol[i].zName);
sqlite3VdbeChangeP4(v, -1, zMsg, P4_DYNAMIC);
break;
}
case OE_Ignore: {
sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
sqlite3VdbeAddOp2(v, OP_IsNull, regData+i, ignoreDest);
break;
}
case OE_Replace: {
j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regData+i);
sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regData+i);
sqlite3VdbeJumpHere(v, j1);
break;
}
}
sqlite3VdbeJumpHere(v, j1);
}
/* Test all CHECK constraints
@ -1530,7 +1533,7 @@ static int xferOptimization(
if( pSelect==0 ){
return 0; /* Must be of the form INSERT INTO ... SELECT ... */
}
if( pDest->pTrigger ){
if( sqlite3TriggerList(pParse, pDest) ){
return 0; /* tab1 must not have triggers */
}
#ifndef SQLITE_OMIT_VIRTUALTABLE

View File

@ -14,7 +14,7 @@
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: legacy.c,v 1.31 2009/01/20 16:53:40 danielk1977 Exp $
** $Id: legacy.c,v 1.32 2009/03/19 18:51:07 danielk1977 Exp $
*/
#include "sqliteInt.h"
@ -101,7 +101,7 @@ int sqlite3_exec(
}
if( xCallback(pArg, nCol, azVals, azCols) ){
rc = SQLITE_ABORT;
sqlite3_finalize(pStmt);
sqlite3VdbeFinalize((Vdbe *)pStmt);
pStmt = 0;
sqlite3Error(db, SQLITE_ABORT, 0);
goto exec_out;
@ -109,7 +109,7 @@ int sqlite3_exec(
}
if( rc!=SQLITE_ROW ){
rc = sqlite3_finalize(pStmt);
rc = sqlite3VdbeFinalize((Vdbe *)pStmt);
pStmt = 0;
if( rc!=SQLITE_SCHEMA ){
nRetry = 0;
@ -125,7 +125,7 @@ int sqlite3_exec(
}
exec_out:
if( pStmt ) sqlite3_finalize(pStmt);
if( pStmt ) sqlite3VdbeFinalize((Vdbe *)pStmt);
sqlite3DbFree(db, azCols);
rc = sqlite3ApiExit(db, rc);

View File

@ -14,7 +14,7 @@
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.528 2009/02/05 16:31:46 drh Exp $
** $Id: main.c,v 1.536 2009/04/09 01:23:49 drh Exp $
*/
#include "sqliteInt.h"
@ -219,6 +219,7 @@ int sqlite3_shutdown(void){
if( sqlite3GlobalConfig.isInit ){
sqlite3_os_end();
}
sqlite3_reset_auto_extension();
sqlite3MallocEnd();
sqlite3MutexEnd();
sqlite3GlobalConfig.isInit = 0;
@ -404,12 +405,12 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
sz = 0;
pStart = 0;
}else if( pBuf==0 ){
sz = (sz + 7)&~7;
sz = ROUND8(sz);
sqlite3BeginBenignMalloc();
pStart = sqlite3Malloc( sz*cnt );
sqlite3EndBenignMalloc();
}else{
sz = sz&~7;
sz = ROUNDDOWN8(sz);
pStart = pBuf;
}
db->lookaside.pStart = pStart;
@ -418,7 +419,7 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
if( pStart ){
int i;
LookasideSlot *p;
assert( sz > sizeof(LookasideSlot*) );
assert( sz > (int)sizeof(LookasideSlot*) );
p = (LookasideSlot*)pStart;
for(i=cnt-1; i>=0; i--){
p->pNext = db->lookaside.pFree;
@ -560,6 +561,7 @@ void sqlite3CloseSavepoints(sqlite3 *db){
sqlite3DbFree(db, pTmp);
}
db->nSavepoint = 0;
db->nStatement = 0;
db->isTransactionSavepoint = 0;
}
@ -629,6 +631,12 @@ int sqlite3_close(sqlite3 *db){
}
}
sqlite3ResetInternalSchema(db, 0);
/* Tell the code in notify.c that the connection no longer holds any
** locks and does not require any further unlock-notify callbacks.
*/
sqlite3ConnectionClosed(db);
assert( db->nDb<=2 );
assert( db->aDb==db->aDbStatic );
for(j=0; j<ArraySize(db->aFunc.a); j++){
@ -1238,15 +1246,15 @@ const char *sqlite3_errmsg(sqlite3 *db){
if( !sqlite3SafetyCheckSickOrOk(db) ){
return sqlite3ErrStr(SQLITE_MISUSE);
}
if( db->mallocFailed ){
return sqlite3ErrStr(SQLITE_NOMEM);
}
sqlite3_mutex_enter(db->mutex);
assert( !db->mallocFailed );
z = (char*)sqlite3_value_text(db->pErr);
assert( !db->mallocFailed );
if( z==0 ){
z = sqlite3ErrStr(db->errCode);
if( db->mallocFailed ){
z = sqlite3ErrStr(SQLITE_NOMEM);
}else{
z = (char*)sqlite3_value_text(db->pErr);
assert( !db->mallocFailed );
if( z==0 ){
z = sqlite3ErrStr(db->errCode);
}
}
sqlite3_mutex_leave(db->mutex);
return z;
@ -1258,46 +1266,42 @@ const char *sqlite3_errmsg(sqlite3 *db){
** error.
*/
const void *sqlite3_errmsg16(sqlite3 *db){
/* Because all the characters in the string are in the unicode
** range 0x00-0xFF, if we pad the big-endian string with a
** zero byte, we can obtain the little-endian string with
** &big_endian[1].
*/
static const char outOfMemBe[] = {
0, 'o', 0, 'u', 0, 't', 0, ' ',
0, 'o', 0, 'f', 0, ' ',
0, 'm', 0, 'e', 0, 'm', 0, 'o', 0, 'r', 0, 'y', 0, 0, 0
static const u16 outOfMem[] = {
'o', 'u', 't', ' ', 'o', 'f', ' ', 'm', 'e', 'm', 'o', 'r', 'y', 0
};
static const char misuseBe [] = {
0, 'l', 0, 'i', 0, 'b', 0, 'r', 0, 'a', 0, 'r', 0, 'y', 0, ' ',
0, 'r', 0, 'o', 0, 'u', 0, 't', 0, 'i', 0, 'n', 0, 'e', 0, ' ',
0, 'c', 0, 'a', 0, 'l', 0, 'l', 0, 'e', 0, 'd', 0, ' ',
0, 'o', 0, 'u', 0, 't', 0, ' ',
0, 'o', 0, 'f', 0, ' ',
0, 's', 0, 'e', 0, 'q', 0, 'u', 0, 'e', 0, 'n', 0, 'c', 0, 'e', 0, 0, 0
static const u16 misuse[] = {
'l', 'i', 'b', 'r', 'a', 'r', 'y', ' ',
'r', 'o', 'u', 't', 'i', 'n', 'e', ' ',
'c', 'a', 'l', 'l', 'e', 'd', ' ',
'o', 'u', 't', ' ',
'o', 'f', ' ',
's', 'e', 'q', 'u', 'e', 'n', 'c', 'e', 0
};
const void *z;
if( !db ){
return (void *)(&outOfMemBe[SQLITE_UTF16NATIVE==SQLITE_UTF16LE?1:0]);
return (void *)outOfMem;
}
if( !sqlite3SafetyCheckSickOrOk(db) ){
return (void *)(&misuseBe[SQLITE_UTF16NATIVE==SQLITE_UTF16LE?1:0]);
return (void *)misuse;
}
sqlite3_mutex_enter(db->mutex);
assert( !db->mallocFailed );
z = sqlite3_value_text16(db->pErr);
if( z==0 ){
sqlite3ValueSetStr(db->pErr, -1, sqlite3ErrStr(db->errCode),
SQLITE_UTF8, SQLITE_STATIC);
if( db->mallocFailed ){
z = (void *)outOfMem;
}else{
z = sqlite3_value_text16(db->pErr);
if( z==0 ){
sqlite3ValueSetStr(db->pErr, -1, sqlite3ErrStr(db->errCode),
SQLITE_UTF8, SQLITE_STATIC);
z = sqlite3_value_text16(db->pErr);
}
/* A malloc() may have failed within the call to sqlite3_value_text16()
** above. If this is the case, then the db->mallocFailed flag needs to
** be cleared before returning. Do this directly, instead of via
** sqlite3ApiExit(), to avoid setting the database handle error message.
*/
db->mallocFailed = 0;
}
/* A malloc() may have failed within the call to sqlite3_value_text16()
** above. If this is the case, then the db->mallocFailed flag needs to
** be cleared before returning. Do this directly, instead of via
** sqlite3ApiExit(), to avoid setting the database handle error message.
*/
db->mallocFailed = 0;
sqlite3_mutex_leave(db->mutex);
return z;
}
@ -1940,7 +1944,6 @@ int sqlite3_table_column_metadata(
(void)sqlite3SafetyOn(db);
sqlite3BtreeEnterAll(db);
rc = sqlite3Init(db, &zErrMsg);
sqlite3BtreeLeaveAll(db);
if( SQLITE_OK!=rc ){
goto error_out;
}
@ -1996,6 +1999,7 @@ int sqlite3_table_column_metadata(
}
error_out:
sqlite3BtreeLeaveAll(db);
(void)sqlite3SafetyOff(db);
/* Whether the function call succeeded or failed, set the output parameters

View File

@ -12,7 +12,7 @@
**
** Memory allocation functions used throughout sqlite.
**
** $Id: malloc.c,v 1.56 2009/02/17 18:37:29 drh Exp $
** $Id: malloc.c,v 1.61 2009/03/24 15:08:10 drh Exp $
*/
#include "sqliteInt.h"
#include <stdarg.h>
@ -121,7 +121,7 @@ int sqlite3MallocInit(void){
if( sqlite3GlobalConfig.pScratch && sqlite3GlobalConfig.szScratch>=100
&& sqlite3GlobalConfig.nScratch>=0 ){
int i;
sqlite3GlobalConfig.szScratch = (sqlite3GlobalConfig.szScratch - 4) & ~7;
sqlite3GlobalConfig.szScratch = ROUNDDOWN8(sqlite3GlobalConfig.szScratch-4);
mem0.aScratchFree = (u32*)&((char*)sqlite3GlobalConfig.pScratch)
[sqlite3GlobalConfig.szScratch*sqlite3GlobalConfig.nScratch];
for(i=0; i<sqlite3GlobalConfig.nScratch; i++){ mem0.aScratchFree[i] = i; }
@ -134,7 +134,7 @@ int sqlite3MallocInit(void){
&& sqlite3GlobalConfig.nPage>=1 ){
int i;
int overhead;
int sz = sqlite3GlobalConfig.szPage & ~7;
int sz = ROUNDDOWN8(sqlite3GlobalConfig.szPage);
int n = sqlite3GlobalConfig.nPage;
overhead = (4*n + sz - 1)/sz;
sqlite3GlobalConfig.nPage -= overhead;
@ -407,95 +407,6 @@ void sqlite3ScratchFree(void *p){
}
}
/*
** Allocate memory to be used by the page cache. Make use of the
** memory buffer provided by SQLITE_CONFIG_PAGECACHE if there is one
** and that memory is of the right size and is not completely
** consumed. Otherwise, failover to sqlite3Malloc().
*/
#if 0
void *sqlite3PageMalloc(int n){
void *p;
assert( n>0 );
assert( (n & (n-1))==0 );
assert( n>=512 && n<=32768 );
if( sqlite3GlobalConfig.szPage<n ){
goto page_overflow;
}else{
sqlite3_mutex_enter(mem0.mutex);
if( mem0.nPageFree==0 ){
sqlite3_mutex_leave(mem0.mutex);
goto page_overflow;
}else{
int i;
i = mem0.aPageFree[--mem0.nPageFree];
sqlite3_mutex_leave(mem0.mutex);
i *= sqlite3GlobalConfig.szPage;
sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, n);
sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, 1);
p = (void*)&((char*)sqlite3GlobalConfig.pPage)[i];
}
}
return p;
page_overflow:
if( sqlite3GlobalConfig.bMemstat ){
sqlite3_mutex_enter(mem0.mutex);
sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, n);
n = mallocWithAlarm(n, &p);
if( p ) sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, n);
sqlite3_mutex_leave(mem0.mutex);
}else{
p = sqlite3GlobalConfig.m.xMalloc(n);
}
return p;
}
void sqlite3PageFree(void *p){
if( p ){
if( sqlite3GlobalConfig.pPage==0
|| p<sqlite3GlobalConfig.pPage
|| p>=(void*)mem0.aPageFree ){
/* In this case, the page allocation was obtained from a regular
** call to sqlite3_mem_methods.xMalloc() (a page-cache-memory
** "overflow"). Free the block with sqlite3_mem_methods.xFree().
*/
if( sqlite3GlobalConfig.bMemstat ){
int iSize = sqlite3MallocSize(p);
sqlite3_mutex_enter(mem0.mutex);
sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, -iSize);
sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, -iSize);
sqlite3GlobalConfig.m.xFree(p);
sqlite3_mutex_leave(mem0.mutex);
}else{
sqlite3GlobalConfig.m.xFree(p);
}
}else{
/* The page allocation was allocated from the sqlite3GlobalConfig.pPage
** buffer. In this case all that is add the index of the page in
** the sqlite3GlobalConfig.pPage array to the set of free indexes stored
** in the mem0.aPageFree[] array.
*/
int i;
i = (u8 *)p - (u8 *)sqlite3GlobalConfig.pPage;
i /= sqlite3GlobalConfig.szPage;
assert( i>=0 && i<sqlite3GlobalConfig.nPage );
sqlite3_mutex_enter(mem0.mutex);
assert( mem0.nPageFree<sqlite3GlobalConfig.nPage );
mem0.aPageFree[mem0.nPageFree++] = i;
sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, -1);
sqlite3_mutex_leave(mem0.mutex);
#if !defined(NDEBUG) && 0
/* Assert that a duplicate was not just inserted into aPageFree[]. */
for(i=0; i<mem0.nPageFree-1; i++){
assert( mem0.aPageFree[i]!=mem0.aPageFree[mem0.nPageFree-1] );
}
#endif
}
}
}
#endif
/*
** TRUE if p is a lookaside memory allocation from db
*/
@ -515,6 +426,7 @@ int sqlite3MallocSize(void *p){
return sqlite3GlobalConfig.m.xSize(p);
}
int sqlite3DbMallocSize(sqlite3 *db, void *p){
assert( db==0 || sqlite3_mutex_held(db->mutex) );
if( p==0 ){
return 0;
}else if( isLookaside(db, p) ){
@ -544,6 +456,7 @@ void sqlite3_free(void *p){
** connection.
*/
void sqlite3DbFree(sqlite3 *db, void *p){
assert( db==0 || sqlite3_mutex_held(db->mutex) );
if( isLookaside(db, p) ){
LookasideSlot *pBuf = (LookasideSlot*)p;
pBuf->pNext = db->lookaside.pFree;
@ -652,6 +565,7 @@ void *sqlite3DbMallocZero(sqlite3 *db, int n){
*/
void *sqlite3DbMallocRaw(sqlite3 *db, int n){
void *p;
assert( db==0 || sqlite3_mutex_held(db->mutex) );
#ifndef SQLITE_OMIT_LOOKASIDE
if( db ){
LookasideSlot *pBuf;
@ -686,6 +600,8 @@ void *sqlite3DbMallocRaw(sqlite3 *db, int n){
*/
void *sqlite3DbRealloc(sqlite3 *db, void *p, int n){
void *pNew = 0;
assert( db!=0 );
assert( sqlite3_mutex_held(db->mutex) );
if( db->mallocFailed==0 ){
if( p==0 ){
return sqlite3DbMallocRaw(db, n);
@ -780,10 +696,10 @@ void sqlite3SetString(char **pz, sqlite3 *db, const char *zFormat, ...){
** sqlite3_realloc.
**
** The returned value is normally a copy of the second argument to this
** function. However, if a malloc() failure has occured since the previous
** function. However, if a malloc() failure has occurred since the previous
** invocation SQLITE_NOMEM is returned instead.
**
** If the first argument, db, is not NULL and a malloc() error has occured,
** If the first argument, db, is not NULL and a malloc() error has occurred,
** then the connection error-code (the value returned by sqlite3_errcode())
** is set to SQLITE_NOMEM.
*/

View File

@ -17,7 +17,7 @@
** This file contains implementations of the low-level memory allocation
** routines specified in the sqlite3_mem_methods object.
**
** $Id: mem1.c,v 1.29 2008/12/10 21:19:57 drh Exp $
** $Id: mem1.c,v 1.30 2009/03/23 04:33:33 danielk1977 Exp $
*/
#include "sqliteInt.h"
@ -39,7 +39,7 @@
static void *sqlite3MemMalloc(int nByte){
sqlite3_int64 *p;
assert( nByte>0 );
nByte = (nByte+7)&~7;
nByte = ROUND8(nByte);
p = malloc( nByte+8 );
if( p ){
p[0] = nByte;
@ -76,7 +76,7 @@ static void sqlite3MemFree(void *pPrior){
static void *sqlite3MemRealloc(void *pPrior, int nByte){
sqlite3_int64 *p = (sqlite3_int64*)pPrior;
assert( pPrior!=0 && nByte>0 );
nByte = (nByte+7)&~7;
nByte = ROUND8(nByte);
p = (sqlite3_int64*)pPrior;
p--;
p = realloc(p, nByte+8 );
@ -103,7 +103,7 @@ static int sqlite3MemSize(void *pPrior){
** Round up a request size to the next valid allocation size.
*/
static int sqlite3MemRoundup(int n){
return (n+7) & ~7;
return ROUND8(n);
}
/*

View File

@ -19,7 +19,7 @@
** This file contains implementations of the low-level memory allocation
** routines specified in the sqlite3_mem_methods object.
**
** $Id: mem2.c,v 1.43 2009/02/05 03:00:06 shane Exp $
** $Id: mem2.c,v 1.45 2009/03/23 04:33:33 danielk1977 Exp $
*/
#include "sqliteInt.h"
@ -128,7 +128,7 @@ static struct {
** Adjust memory usage statistics
*/
static void adjustStats(int iSize, int increment){
int i = ((iSize+7)&~7)/8;
int i = ROUND8(iSize)/8;
if( i>NCSIZE-1 ){
i = NCSIZE - 1;
}
@ -159,7 +159,7 @@ static struct MemBlockHdr *sqlite3MemsysGetHeader(void *pAllocation){
p = (struct MemBlockHdr*)pAllocation;
p--;
assert( p->iForeGuard==(int)FOREGUARD );
nReserve = (p->iSize+7)&~7;
nReserve = ROUND8(p->iSize);
pInt = (int*)pAllocation;
pU8 = (u8*)pAllocation;
assert( pInt[nReserve/sizeof(int)]==(int)REARGUARD );
@ -209,7 +209,7 @@ static void sqlite3MemShutdown(void *NotUsed){
** Round up a request size to the next valid allocation size.
*/
static int sqlite3MemRoundup(int n){
return (n+7) & ~7;
return ROUND8(n);
}
/*
@ -225,7 +225,7 @@ static void *sqlite3MemMalloc(int nByte){
int nReserve;
sqlite3_mutex_enter(mem.mutex);
assert( mem.disallow==0 );
nReserve = (nByte+7)&~7;
nReserve = ROUND8(nByte);
totalSize = nReserve + sizeof(*pHdr) + sizeof(int) +
mem.nBacktrace*sizeof(void*) + mem.nTitle;
p = malloc(totalSize);
@ -248,6 +248,7 @@ static void *sqlite3MemMalloc(int nByte){
void *aAddr[40];
pHdr->nBacktrace = backtrace(aAddr, mem.nBacktrace+1)-1;
memcpy(pBt, &aAddr[1], pHdr->nBacktrace*sizeof(void*));
assert(pBt[0]);
if( mem.xBacktrace ){
mem.xBacktrace(nByte, pHdr->nBacktrace-1, &aAddr[1]);
}
@ -371,7 +372,7 @@ void sqlite3MemdebugSettitle(const char *zTitle){
if( n>=sizeof(mem.zTitle) ) n = sizeof(mem.zTitle)-1;
memcpy(mem.zTitle, zTitle, n);
mem.zTitle[n] = 0;
mem.nTitle = (n+7)&~7;
mem.nTitle = ROUND8(n);
sqlite3_mutex_leave(mem.mutex);
}

View File

@ -14,7 +14,7 @@
** The in-memory rollback journal is used to journal transactions for
** ":memory:" databases and when the journal_mode=MEMORY pragma is used.
**
** @(#) $Id: memjournal.c,v 1.8 2008/12/20 02:14:40 drh Exp $
** @(#) $Id: memjournal.c,v 1.11 2009/04/05 12:22:09 drh Exp $
*/
#include "sqliteInt.h"
@ -25,8 +25,13 @@ typedef struct FileChunk FileChunk;
/* Space to hold the rollback journal is allocated in increments of
** this many bytes.
**
** The size chosen is a little less than a power of two. That way,
** the FileChunk object will have a size that almost exactly fills
** a power-of-two allocation. This mimimizes wasted space in power-of-two
** memory allocators.
*/
#define JOURNAL_CHUNKSIZE 1024
#define JOURNAL_CHUNKSIZE ((int)(1024-sizeof(FileChunk*)))
/* Macro to find the minimum of two numeric values.
*/
@ -63,7 +68,8 @@ struct MemJournal {
};
/*
** Read data from the file.
** Read data from the in-memory journal file. This is the implementation
** of the sqlite3_vfs.xRead method.
*/
static int memjrnlRead(
sqlite3_file *pJfd, /* The journal file from which to read */
@ -77,12 +83,13 @@ static int memjrnlRead(
int iChunkOffset;
FileChunk *pChunk;
/* SQLite never tries to read past the end of a rollback journal file */
assert( iOfst+iAmt<=p->endpoint.iOffset );
if( p->readpoint.iOffset!=iOfst || iOfst==0 ){
sqlite3_int64 iOff = 0;
for(pChunk=p->pFirst;
pChunk && (iOff+JOURNAL_CHUNKSIZE)<=iOfst;
ALWAYS(pChunk) && (iOff+JOURNAL_CHUNKSIZE)<=iOfst;
pChunk=pChunk->pNext
){
iOff += JOURNAL_CHUNKSIZE;
@ -185,11 +192,17 @@ static int memjrnlClose(sqlite3_file *pJfd){
/*
** Sync the file.
**
** Syncing an in-memory journal is a no-op. And, in fact, this routine
** is never called in a working implementation. This implementation
** exists purely as a contingency, in case some malfunction in some other
** part of SQLite causes Sync to be called by mistake.
*/
static int memjrnlSync(sqlite3_file *NotUsed, int NotUsed2){
UNUSED_PARAMETER2(NotUsed, NotUsed2);
return SQLITE_OK;
}
static int memjrnlSync(sqlite3_file *NotUsed, int NotUsed2){ /*NO_TEST*/
UNUSED_PARAMETER2(NotUsed, NotUsed2); /*NO_TEST*/
assert( 0 ); /*NO_TEST*/
return SQLITE_OK; /*NO_TEST*/
} /*NO_TEST*/
/*
** Query the size of the file in bytes.
@ -224,6 +237,7 @@ static struct sqlite3_io_methods MemJournalMethods = {
*/
void sqlite3MemJournalOpen(sqlite3_file *pJfd){
MemJournal *p = (MemJournal *)pJfd;
assert( EIGHT_BYTE_ALIGNMENT(p) );
memset(p, 0, sqlite3MemJournalSize());
p->pMethod = &MemJournalMethods;
}

333
src/notify.c Normal file
View File

@ -0,0 +1,333 @@
/*
** 2009 March 3
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
**
** This file contains the implementation of the sqlite3_unlock_notify()
** API method and its associated functionality.
**
** $Id: notify.c,v 1.4 2009/04/07 22:06:57 drh Exp $
*/
#include "sqliteInt.h"
#include "btreeInt.h"
/* Omit this entire file if SQLITE_ENABLE_UNLOCK_NOTIFY is not defined. */
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
/*
** Public interfaces:
**
** sqlite3ConnectionBlocked()
** sqlite3ConnectionUnlocked()
** sqlite3ConnectionClosed()
** sqlite3_unlock_notify()
*/
#define assertMutexHeld() \
assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)) )
/*
** Head of a linked list of all sqlite3 objects created by this process
** for which either sqlite3.pBlockingConnection or sqlite3.pUnlockConnection
** is not NULL. This variable may only accessed while the STATIC_MASTER
** mutex is held.
*/
static sqlite3 *SQLITE_WSD sqlite3BlockedList = 0;
#ifndef NDEBUG
/*
** This function is a complex assert() that verifies the following
** properties of the blocked connections list:
**
** 1) Each entry in the list has a non-NULL value for either
** pUnlockConnection or pBlockingConnection, or both.
**
** 2) All entries in the list that share a common value for
** xUnlockNotify are grouped together.
**
** 3) If the argument db is not NULL, then none of the entries in the
** blocked connections list have pUnlockConnection or pBlockingConnection
** set to db. This is used when closing connection db.
*/
static void checkListProperties(sqlite3 *db){
sqlite3 *p;
for(p=sqlite3BlockedList; p; p=p->pNextBlocked){
int seen = 0;
sqlite3 *p2;
/* Verify property (1) */
assert( p->pUnlockConnection || p->pBlockingConnection );
/* Verify property (2) */
for(p2=sqlite3BlockedList; p2!=p; p2=p2->pNextBlocked){
if( p2->xUnlockNotify==p->xUnlockNotify ) seen = 1;
assert( p2->xUnlockNotify==p->xUnlockNotify || !seen );
assert( db==0 || p->pUnlockConnection!=db );
assert( db==0 || p->pBlockingConnection!=db );
}
}
}
#else
# define checkListProperties(x)
#endif
/*
** Remove connection db from the blocked connections list. If connection
** db is not currently a part of the list, this function is a no-op.
*/
static void removeFromBlockedList(sqlite3 *db){
sqlite3 **pp;
assertMutexHeld();
for(pp=&sqlite3BlockedList; *pp; pp = &(*pp)->pNextBlocked){
if( *pp==db ){
*pp = (*pp)->pNextBlocked;
break;
}
}
}
/*
** Add connection db to the blocked connections list. It is assumed
** that it is not already a part of the list.
*/
static void addToBlockedList(sqlite3 *db){
sqlite3 **pp;
assertMutexHeld();
for(
pp=&sqlite3BlockedList;
*pp && (*pp)->xUnlockNotify!=db->xUnlockNotify;
pp=&(*pp)->pNextBlocked
);
db->pNextBlocked = *pp;
*pp = db;
}
/*
** Obtain the STATIC_MASTER mutex.
*/
static void enterMutex(void){
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
checkListProperties(0);
}
/*
** Release the STATIC_MASTER mutex.
*/
static void leaveMutex(void){
assertMutexHeld();
checkListProperties(0);
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
}
/*
** Register an unlock-notify callback.
**
** This is called after connection "db" has attempted some operation
** but has received an SQLITE_LOCKED error because another connection
** (call it pOther) in the same process was busy using the same shared
** cache. pOther is found by looking at db->pBlockingConnection.
**
** If there is no blocking connection, the callback is invoked immediately,
** before this routine returns.
**
** If pOther is already blocked on db, then report SQLITE_LOCKED, to indicate
** a deadlock.
**
** Otherwise, make arrangements to invoke xNotify when pOther drops
** its locks.
**
** Each call to this routine overrides any prior callbacks registered
** on the same "db". If xNotify==0 then any prior callbacks are immediately
** cancelled.
*/
int sqlite3_unlock_notify(
sqlite3 *db,
void (*xNotify)(void **, int),
void *pArg
){
int rc = SQLITE_OK;
sqlite3_mutex_enter(db->mutex);
enterMutex();
if( xNotify==0 ){
removeFromBlockedList(db);
db->pUnlockConnection = 0;
db->xUnlockNotify = 0;
db->pUnlockArg = 0;
}else if( 0==db->pBlockingConnection ){
/* The blocking transaction has been concluded. Or there never was a
** blocking transaction. In either case, invoke the notify callback
** immediately.
*/
xNotify(&pArg, 1);
}else{
sqlite3 *p;
for(p=db->pBlockingConnection; p && p!=db; p=p->pUnlockConnection){}
if( p ){
rc = SQLITE_LOCKED; /* Deadlock detected. */
}else{
db->pUnlockConnection = db->pBlockingConnection;
db->xUnlockNotify = xNotify;
db->pUnlockArg = pArg;
removeFromBlockedList(db);
addToBlockedList(db);
}
}
leaveMutex();
assert( !db->mallocFailed );
sqlite3Error(db, rc, (rc?"database is deadlocked":0));
sqlite3_mutex_leave(db->mutex);
return rc;
}
/*
** This function is called while stepping or preparing a statement
** associated with connection db. The operation will return SQLITE_LOCKED
** to the user because it requires a lock that will not be available
** until connection pBlocker concludes its current transaction.
*/
void sqlite3ConnectionBlocked(sqlite3 *db, sqlite3 *pBlocker){
enterMutex();
if( db->pBlockingConnection==0 && db->pUnlockConnection==0 ){
addToBlockedList(db);
}
db->pBlockingConnection = pBlocker;
leaveMutex();
}
/*
** This function is called when
** the transaction opened by database db has just finished. Locks held
** by database connection db have been released.
**
** This function loops through each entry in the blocked connections
** list and does the following:
**
** 1) If the sqlite3.pBlockingConnection member of a list entry is
** set to db, then set pBlockingConnection=0.
**
** 2) If the sqlite3.pUnlockConnection member of a list entry is
** set to db, then invoke the configured unlock-notify callback and
** set pUnlockConnection=0.
**
** 3) If the two steps above mean that pBlockingConnection==0 and
** pUnlockConnection==0, remove the entry from the blocked connections
** list.
*/
void sqlite3ConnectionUnlocked(sqlite3 *db){
void (*xUnlockNotify)(void **, int) = 0; /* Unlock-notify cb to invoke */
int nArg = 0; /* Number of entries in aArg[] */
sqlite3 **pp; /* Iterator variable */
void **aArg; /* Arguments to the unlock callback */
void **aDyn = 0; /* Dynamically allocated space for aArg[] */
void *aStatic[16]; /* Starter space for aArg[]. No malloc required */
aArg = aStatic;
enterMutex(); /* Enter STATIC_MASTER mutex */
/* This loop runs once for each entry in the blocked-connections list. */
for(pp=&sqlite3BlockedList; *pp; /* no-op */ ){
sqlite3 *p = *pp;
/* Step 1. */
if( p->pBlockingConnection==db ){
p->pBlockingConnection = 0;
}
/* Step 2. */
if( p->pUnlockConnection==db ){
assert( p->xUnlockNotify );
if( p->xUnlockNotify!=xUnlockNotify && nArg!=0 ){
xUnlockNotify(aArg, nArg);
nArg = 0;
}
sqlite3BeginBenignMalloc();
assert( aArg==aDyn || (aDyn==0 && aArg==aStatic) );
assert( nArg<=(int)ArraySize(aStatic) || aArg==aDyn );
if( (!aDyn && nArg==(int)ArraySize(aStatic))
|| (aDyn && nArg==(int)(sqlite3DbMallocSize(db, aDyn)/sizeof(void*)))
){
/* The aArg[] array needs to grow. */
void **pNew = (void **)sqlite3Malloc(nArg*sizeof(void *)*2);
if( pNew ){
memcpy(pNew, aArg, nArg*sizeof(void *));
sqlite3_free(aDyn);
aDyn = aArg = pNew;
}else{
/* This occurs when the array of context pointers that need to
** be passed to the unlock-notify callback is larger than the
** aStatic[] array allocated on the stack and the attempt to
** allocate a larger array from the heap has failed.
**
** This is a difficult situation to handle. Returning an error
** code to the caller is insufficient, as even if an error code
** is returned the transaction on connection db will still be
** closed and the unlock-notify callbacks on blocked connections
** will go unissued. This might cause the application to wait
** indefinitely for an unlock-notify callback that will never
** arrive.
**
** Instead, invoke the unlock-notify callback with the context
** array already accumulated. We can then clear the array and
** begin accumulating any further context pointers without
** requiring any dynamic allocation. This is sub-optimal because
** it means that instead of one callback with a large array of
** context pointers the application will receive two or more
** callbacks with smaller arrays of context pointers, which will
** reduce the applications ability to prioritize multiple
** connections. But it is the best that can be done under the
** circumstances.
*/
xUnlockNotify(aArg, nArg);
nArg = 0;
}
}
sqlite3EndBenignMalloc();
aArg[nArg++] = p->pUnlockArg;
xUnlockNotify = p->xUnlockNotify;
p->pUnlockConnection = 0;
p->xUnlockNotify = 0;
p->pUnlockArg = 0;
}
/* Step 3. */
if( p->pBlockingConnection==0 && p->pUnlockConnection==0 ){
/* Remove connection p from the blocked connections list. */
*pp = p->pNextBlocked;
p->pNextBlocked = 0;
}else{
pp = &p->pNextBlocked;
}
}
if( nArg!=0 ){
xUnlockNotify(aArg, nArg);
}
sqlite3_free(aDyn);
leaveMutex(); /* Leave STATIC_MASTER mutex */
}
/*
** This is called when the database connection passed as an argument is
** being closed. The connection is removed from the blocked list.
*/
void sqlite3ConnectionClosed(sqlite3 *db){
sqlite3ConnectionUnlocked(db);
enterMutex();
removeFromBlockedList(db);
checkListProperties(db);
leaveMutex();
}
#endif

View File

@ -13,7 +13,7 @@
** This file contains OS interface code that is common to all
** architectures.
**
** $Id: os.c,v 1.125 2008/12/08 18:19:18 drh Exp $
** $Id: os.c,v 1.126 2009/03/25 14:24:42 drh Exp $
*/
#define _SQLITE_OS_C_ 1
#include "sqliteInt.h"
@ -112,8 +112,11 @@ int sqlite3OsOpen(
int flags,
int *pFlagsOut
){
int rc;
DO_OS_MALLOC_TEST;
return pVfs->xOpen(pVfs, zPath, pFile, flags, pFlagsOut);
rc = pVfs->xOpen(pVfs, zPath, pFile, flags, pFlagsOut);
assert( rc==SQLITE_OK || pFile->pMethods==0 );
return rc;
}
int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
return pVfs->xDelete(pVfs, zPath, dirSync);

View File

@ -17,7 +17,7 @@
** This file should be #included by the os_*.c files only. It is not a
** general purpose header file.
**
** $Id: os_common.h,v 1.37 2008/05/29 20:22:37 shane Exp $
** $Id: os_common.h,v 1.38 2009/02/24 18:40:50 danielk1977 Exp $
*/
#ifndef _OS_COMMON_H_
#define _OS_COMMON_H_
@ -31,15 +31,6 @@
# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead."
#endif
/*
* When testing, this global variable stores the location of the
* pending-byte in the database file.
*/
#ifdef SQLITE_TEST
unsigned int sqlite3_pending_byte = 0x40000000;
#endif
#ifdef SQLITE_DEBUG
int sqlite3OSTrace = 0;
#define OSTRACE1(X) if( sqlite3OSTrace ) sqlite3DebugPrintf(X)

View File

@ -43,7 +43,7 @@
** * Definitions of sqlite3_vfs objects for all locking methods
** plus implementations of sqlite3_os_init() and sqlite3_os_end().
**
** $Id: os_unix.c,v 1.241 2009/02/09 17:34:07 drh Exp $
** $Id: os_unix.c,v 1.250 2009/04/07 05:35:04 chw Exp $
*/
#include "sqliteInt.h"
#if SQLITE_OS_UNIX /* This file is used on unix only */
@ -1454,11 +1454,12 @@ static int unixUnlock(sqlite3_file *id, int locktype){
if( IS_LOCK_ERROR(rc) ){
pFile->lastErrno = tErrno;
}
goto end_unlock;
goto end_unlock;
}
}
if( locktype==NO_LOCK ){
struct unixOpenCnt *pOpen;
int rc2 = SQLITE_OK;
/* Decrement the shared lock counter. Release the lock using an
** OS call only when all threads in this same process have released
@ -1480,8 +1481,8 @@ static int unixUnlock(sqlite3_file *id, int locktype){
if( IS_LOCK_ERROR(rc) ){
pFile->lastErrno = tErrno;
}
pLock->cnt = 1;
goto end_unlock;
pLock->locktype = NO_LOCK;
pFile->locktype = NO_LOCK;
}
}
@ -1489,30 +1490,31 @@ static int unixUnlock(sqlite3_file *id, int locktype){
** count reaches zero, close any other file descriptors whose close
** was deferred because of outstanding locks.
*/
if( rc==SQLITE_OK ){
pOpen = pFile->pOpen;
pOpen->nLock--;
assert( pOpen->nLock>=0 );
if( pOpen->nLock==0 && pOpen->nPending>0 ){
int i;
for(i=0; i<pOpen->nPending; i++){
/* close pending fds, but if closing fails don't free the array
** assign -1 to the successfully closed descriptors and record the
** error. The next attempt to unlock will try again. */
if( pOpen->aPending[i] < 0 ) continue;
if( close(pOpen->aPending[i]) ){
pFile->lastErrno = errno;
rc = SQLITE_IOERR_CLOSE;
}else{
pOpen->aPending[i] = -1;
}
}
if( rc==SQLITE_OK ){
sqlite3_free(pOpen->aPending);
pOpen->nPending = 0;
pOpen->aPending = 0;
pOpen = pFile->pOpen;
pOpen->nLock--;
assert( pOpen->nLock>=0 );
if( pOpen->nLock==0 && pOpen->nPending>0 ){
int i;
for(i=0; i<pOpen->nPending; i++){
/* close pending fds, but if closing fails don't free the array
** assign -1 to the successfully closed descriptors and record the
** error. The next attempt to unlock will try again. */
if( pOpen->aPending[i] < 0 ) continue;
if( close(pOpen->aPending[i]) ){
pFile->lastErrno = errno;
rc2 = SQLITE_IOERR_CLOSE;
}else{
pOpen->aPending[i] = -1;
}
}
if( rc2==SQLITE_OK ){
sqlite3_free(pOpen->aPending);
pOpen->nPending = 0;
pOpen->aPending = 0;
}
}
if( rc==SQLITE_OK ){
rc = rc2;
}
}
@ -2211,8 +2213,8 @@ static int semClose(sqlite3_file *id) {
unixEnterMutex();
releaseLockInfo(pFile->pLock);
releaseOpenCnt(pFile->pOpen);
closeUnixFile(id);
unixLeaveMutex();
closeUnixFile(id);
}
return SQLITE_OK;
}
@ -2824,10 +2826,12 @@ int sqlite3_fullsync_count = 0;
#endif
/*
** Use the fdatasync() API only if the HAVE_FDATASYNC macro is defined.
** Otherwise use fsync() in its place.
** We do not trust systems to provide a working fdatasync(). Some do.
** Others do no. To be safe, we will stick with the (slower) fsync().
** If you know that your system does support fdatasync() correctly,
** then simply compile with -Dfdatasync=fdatasync
*/
#ifndef HAVE_FDATASYNC
#if !defined(fdatasync) && !defined(__linux__)
# define fdatasync fsync
#endif
@ -2853,6 +2857,19 @@ int sqlite3_fullsync_count = 0;
** You are strongly advised *not* to deploy with SQLITE_NO_SYNC
** enabled, however, since with SQLITE_NO_SYNC enabled, an OS crash
** or power failure will likely corrupt the database file.
**
** SQLite sets the dataOnly flag if the size of the file is unchanged.
** The idea behind dataOnly is that it should only write the file content
** to disk, not the inode. We only set dataOnly if the file size is
** unchanged since the file size is part of the inode. However,
** Ted Ts'o tells us that fdatasync() will also write the inode if the
** file size has changed. The only real difference between fdatasync()
** and fsync(), Ted tells us, is that fdatasync() will not flush the
** inode if the mtime or owner or other inode attributes have changed.
** We only care about the file size, not the other file attributes, so
** as far as SQLite is concerned, an fdatasync() is always adequate.
** So, we always use fdatasync() if it is available, regardless of
** the value of the dataOnly flag.
*/
static int full_fsync(int fd, int fullSync, int dataOnly){
int rc;
@ -2869,6 +2886,7 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
UNUSED_PARAMETER(dataOnly);
#else
UNUSED_PARAMETER(fullSync);
UNUSED_PARAMETER(dataOnly);
#endif
/* Record the number of times that we do a normal fsync() and
@ -2902,16 +2920,12 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
if( rc ) rc = fsync(fd);
#else
if( dataOnly ){
rc = fdatasync(fd);
rc = fdatasync(fd);
#if OS_VXWORKS
if( rc==-1 && errno==ENOTSUP ){
rc = fsync(fd);
}
#endif
}else{
if( rc==-1 && errno==ENOTSUP ){
rc = fsync(fd);
}
#endif /* OS_VXWORKS */
#endif /* ifdef SQLITE_NO_SYNC elif HAVE_FULLFSYNC */
if( OS_VXWORKS && rc!= -1 ){
@ -3193,7 +3207,7 @@ IOMETHODS(
dotlockCheckReservedLock /* xCheckReservedLock method */
)
#if SQLITE_ENABLE_LOCKING_STYLE
#if SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS
IOMETHODS(
flockIoFinder, /* Finder function name */
flockIoMethods, /* sqlite3_io_methods object name */
@ -3317,6 +3331,44 @@ static const sqlite3_io_methods *(*const autolockIoFinder)(const char*,int)
#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
#if OS_VXWORKS && SQLITE_ENABLE_LOCKING_STYLE
/*
** This "finder" function attempts to determine the best locking strategy
** for the database file "filePath". It then returns the sqlite3_io_methods
** object that implements that strategy.
**
** This is for VXWorks only.
*/
static const sqlite3_io_methods *autolockIoFinderImpl(
const char *filePath, /* name of the database file */
int fd /* file descriptor open on the database file */
){
struct flock lockInfo;
if( !filePath ){
/* If filePath==NULL that means we are dealing with a transient file
** that does not need to be locked. */
return &nolockIoMethods;
}
/* Test if fcntl() is supported and use POSIX style locks.
** Otherwise fall back to the named semaphore method.
*/
lockInfo.l_len = 1;
lockInfo.l_start = 0;
lockInfo.l_whence = SEEK_SET;
lockInfo.l_type = F_RDLCK;
if( fcntl(fd, F_GETLK, &lockInfo)!=-1 ) {
return &posixIoMethods;
}else{
return &semIoMethods;
}
}
static const sqlite3_io_methods *(*const autolockIoFinder)(const char*,int)
= autolockIoFinderImpl;
#endif /* OS_VXWORKS && SQLITE_ENABLE_LOCKING_STYLE */
/*
** An abstract type for a pointer to a IO method finder function:
*/
@ -3599,7 +3651,7 @@ static int unixOpen(
int flags, /* Input flags to control the opening */
int *pOutFlags /* Output flags returned to SQLite core */
){
int fd = 0; /* File descriptor returned by open() */
int fd = -1; /* File descriptor returned by open() */
int dirfd = -1; /* Directory file descriptor */
int openFlags = 0; /* Flags to pass to open() */
int eType = flags&0xFFFFFF00; /* Type of file to open */
@ -3702,7 +3754,7 @@ static int unixOpen(
}
#endif
assert(fd!=0);
assert( fd>=0 );
if( isOpenDirectory ){
rc = openDirectory(zPath, &dirfd);
if( rc!=SQLITE_OK ){
@ -3984,16 +4036,18 @@ static int unixSleep(sqlite3_vfs *NotUsed, int microseconds){
sp.tv_sec = microseconds / 1000000;
sp.tv_nsec = (microseconds % 1000000) * 1000;
nanosleep(&sp, NULL);
UNUSED_PARAMETER(NotUsed);
return microseconds;
#elif defined(HAVE_USLEEP) && HAVE_USLEEP
usleep(microseconds);
UNUSED_PARAMETER(NotUsed);
return microseconds;
#else
int seconds = (microseconds+999999)/1000000;
sleep(seconds);
UNUSED_PARAMETER(NotUsed);
return seconds*1000000;
#endif
UNUSED_PARAMETER(NotUsed);
}
/*
@ -5045,7 +5099,7 @@ int sqlite3_os_init(void){
** array cannot be const.
*/
static sqlite3_vfs aVfs[] = {
#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
#if SQLITE_ENABLE_LOCKING_STYLE && (OS_VXWORKS || defined(__APPLE__))
UNIXVFS("unix", autolockIoFinder ),
#else
UNIXVFS("unix", posixIoFinder ),
@ -5057,8 +5111,10 @@ int sqlite3_os_init(void){
#endif
#if SQLITE_ENABLE_LOCKING_STYLE
UNIXVFS("unix-posix", posixIoFinder ),
#if !OS_VXWORKS
UNIXVFS("unix-flock", flockIoFinder ),
#endif
#endif
#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
UNIXVFS("unix-afp", afpIoFinder ),
UNIXVFS("unix-proxy", proxyIoFinder ),

View File

@ -12,7 +12,7 @@
**
** This file contains code that is specific to windows.
**
** $Id: os_win.c,v 1.148 2009/02/05 03:16:21 shane Exp $
** $Id: os_win.c,v 1.154 2009/04/09 14:27:07 chw Exp $
*/
#include "sqliteInt.h"
#if SQLITE_OS_WIN /* This file is used for windows only */
@ -75,6 +75,7 @@
*/
#if SQLITE_OS_WINCE
# define AreFileApisANSI() 1
# define GetDiskFreeSpaceW() 0
#endif
/*
@ -101,6 +102,7 @@ struct winFile {
unsigned char locktype; /* Type of lock currently held on this file */
short sharedLockByte; /* Randomly chosen byte used as a shared lock */
DWORD lastErrno; /* The Windows errno from the last I/O error */
DWORD sectorSize; /* Sector size of the device file is on */
#if SQLITE_OS_WINCE
WCHAR *zDeleteOnClose; /* Name of file to delete when closing */
HANDLE hMutex; /* Mutex used to control access to shared lock */
@ -110,6 +112,13 @@ struct winFile {
#endif
};
/*
** Forward prototypes.
*/
static int getSectorSize(
sqlite3_vfs *pVfs,
const char *zRelative /* UTF-8 file name */
);
/*
** The following variable is (normally) set once and never changes
@ -135,7 +144,7 @@ static int sqlite3_os_type = 0;
**
** Here is an interesting observation: Win95, Win98, and WinME lack
** the LockFileEx() API. But we can still statically link against that
** API as long as we don't call it win running Win95/98/ME. A call to
** API as long as we don't call it when running Win95/98/ME. A call to
** this routine is used to determine if the host is Win95/98/ME or
** WinNT/2K/XP so that we will know whether or not we can safely call
** the LockFileEx() API.
@ -610,6 +619,8 @@ static BOOL winceLockFileEx(
static int winClose(sqlite3_file *id){
int rc, cnt = 0;
winFile *pFile = (winFile*)id;
assert( id!=0 );
OSTRACE2("CLOSE %d\n", pFile->h);
do{
rc = CloseHandle(pFile->h);
@ -654,9 +665,10 @@ static int winRead(
LONG upperBits = (LONG)((offset>>32) & 0x7fffffff);
LONG lowerBits = (LONG)(offset & 0xffffffff);
DWORD rc;
DWORD got;
winFile *pFile = (winFile*)id;
DWORD error;
DWORD got;
assert( id!=0 );
SimulateIOError(return SQLITE_IOERR_READ);
OSTRACE3("READ %d lock=%d\n", pFile->h, pFile->locktype);
@ -691,9 +703,10 @@ static int winWrite(
LONG upperBits = (LONG)((offset>>32) & 0x7fffffff);
LONG lowerBits = (LONG)(offset & 0xffffffff);
DWORD rc;
DWORD wrote = 0;
winFile *pFile = (winFile*)id;
DWORD error;
DWORD wrote = 0;
assert( id!=0 );
SimulateIOError(return SQLITE_IOERR_WRITE);
SimulateDiskfullError(return SQLITE_FULL);
@ -723,26 +736,26 @@ static int winWrite(
** Truncate an open file to a specified size
*/
static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
DWORD rc;
LONG upperBits = (LONG)((nByte>>32) & 0x7fffffff);
LONG lowerBits = (LONG)(nByte & 0xffffffff);
DWORD rc;
winFile *pFile = (winFile*)id;
DWORD error = NO_ERROR;
DWORD error;
assert( id!=0 );
OSTRACE3("TRUNCATE %d %lld\n", pFile->h, nByte);
SimulateIOError(return SQLITE_IOERR_TRUNCATE);
rc = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
if( INVALID_SET_FILE_POINTER == rc ){
error = GetLastError();
if( rc==INVALID_SET_FILE_POINTER && (error=GetLastError())!=NO_ERROR ){
pFile->lastErrno = error;
return SQLITE_IOERR_TRUNCATE;
}
if( error == NO_ERROR ){
/* SetEndOfFile will fail if nByte is negative */
if( SetEndOfFile(pFile->h) ){
return SQLITE_OK;
}
error = GetLastError();
/* SetEndOfFile will fail if nByte is negative */
if( !SetEndOfFile(pFile->h) ){
pFile->lastErrno = GetLastError();
return SQLITE_IOERR_TRUNCATE;
}
pFile->lastErrno = error;
return SQLITE_IOERR_TRUNCATE;
return SQLITE_OK;
}
#ifdef SQLITE_TEST
@ -760,6 +773,8 @@ int sqlite3_fullsync_count = 0;
static int winSync(sqlite3_file *id, int flags){
#ifndef SQLITE_NO_SYNC
winFile *pFile = (winFile*)id;
assert( id!=0 );
OSTRACE3("SYNC %d lock=%d\n", pFile->h, pFile->locktype);
#else
UNUSED_PARAMETER(id);
@ -791,9 +806,12 @@ static int winSync(sqlite3_file *id, int flags){
** Determine the current size of a file in bytes
*/
static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){
DWORD upperBits;
DWORD lowerBits;
winFile *pFile = (winFile*)id;
DWORD upperBits, lowerBits;
DWORD error;
assert( id!=0 );
SimulateIOError(return SQLITE_IOERR_FSTAT);
lowerBits = GetFileSize(pFile->h, &upperBits);
if( (lowerBits == INVALID_FILE_SIZE)
@ -897,7 +915,7 @@ static int winLock(sqlite3_file *id, int locktype){
winFile *pFile = (winFile*)id;
DWORD error = NO_ERROR;
assert( pFile!=0 );
assert( id!=0 );
OSTRACE5("LOCK %d %d was %d(%d)\n",
pFile->h, locktype, pFile->locktype, pFile->sharedLockByte);
@ -1015,7 +1033,8 @@ static int winLock(sqlite3_file *id, int locktype){
static int winCheckReservedLock(sqlite3_file *id, int *pResOut){
int rc;
winFile *pFile = (winFile*)id;
assert( pFile!=0 );
assert( id!=0 );
if( pFile->locktype>=RESERVED_LOCK ){
rc = 1;
OSTRACE3("TEST WR-LOCK %d %d (local)\n", pFile->h, rc);
@ -1100,8 +1119,8 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
** same for both.
*/
static int winSectorSize(sqlite3_file *id){
UNUSED_PARAMETER(id);
return SQLITE_DEFAULT_SECTOR_SIZE;
assert( id!=0 );
return (int)(((winFile*)id)->sectorSize);
}
/*
@ -1245,7 +1264,6 @@ static int getLastErrorMsg(int nBuf, char *zBuf){
return 0;
}
/*
** Open a file.
*/
@ -1269,6 +1287,7 @@ static int winOpen(
const char *zUtf8Name = zName; /* Filename in UTF-8 encoding */
char zTmpname[MAX_PATH+1]; /* Buffer used to create temp filename */
assert( id!=0 );
UNUSED_PARAMETER(pVfs);
/* If the second argument to this function is NULL, generate a
@ -1348,7 +1367,7 @@ static int winOpen(
if( h==INVALID_HANDLE_VALUE ){
free(zConverted);
if( flags & SQLITE_OPEN_READWRITE ){
return winOpen(0, zName, id,
return winOpen(pVfs, zName, id,
((flags|SQLITE_OPEN_READONLY)&~SQLITE_OPEN_READWRITE), pOutFlags);
}else{
return SQLITE_CANTOPEN;
@ -1365,6 +1384,7 @@ static int winOpen(
pFile->pMethod = &winIoMethod;
pFile->h = h;
pFile->lastErrno = NO_ERROR;
pFile->sectorSize = getSectorSize(pVfs, zUtf8Name);
#if SQLITE_OS_WINCE
if( (flags & (SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB)) ==
(SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB)
@ -1556,6 +1576,73 @@ static int winFullPathname(
#endif
}
/*
** Get the sector size of the device used to store
** file.
*/
static int getSectorSize(
sqlite3_vfs *pVfs,
const char *zRelative /* UTF-8 file name */
){
DWORD bytesPerSector = SQLITE_DEFAULT_SECTOR_SIZE;
char zFullpath[MAX_PATH+1];
int rc;
DWORD dwRet = 0, dwDummy;
/*
** We need to get the full path name of the file
** to get the drive letter to look up the sector
** size.
*/
rc = winFullPathname(pVfs, zRelative, MAX_PATH, zFullpath);
if( rc == SQLITE_OK )
{
void *zConverted = convertUtf8Filename(zFullpath);
if( zConverted ){
if( isNT() ){
int i;
/* trim path to just drive reference */
WCHAR *p = zConverted;
for(i=0;i<MAX_PATH;i++){
if( p[i] == '\\' ){
i++;
p[i] = '\0';
break;
}
}
dwRet = GetDiskFreeSpaceW((WCHAR*)zConverted,
&dwDummy,
&bytesPerSector,
&dwDummy,
&dwDummy);
#if SQLITE_OS_WINCE==0
}else{
int i;
/* trim path to just drive reference */
CHAR *p = (CHAR *)zConverted;
for(i=0;i<MAX_PATH;i++){
if( p[i] == '\\' ){
i++;
p[i] = '\0';
break;
}
}
dwRet = GetDiskFreeSpaceA((CHAR*)zConverted,
&dwDummy,
&bytesPerSector,
&dwDummy,
&dwDummy);
#endif
}
free(zConverted);
}
if( !dwRet ){
bytesPerSector = SQLITE_DEFAULT_SECTOR_SIZE;
}
}
return (int) bytesPerSector;
}
#ifndef SQLITE_OMIT_LOAD_EXTENSION
/*
** Interfaces for opening a shared library, finding entry points
@ -1677,7 +1764,21 @@ int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
/* FILETIME structure is a 64-bit value representing the number of
100-nanosecond intervals since January 1, 1601 (= JD 2305813.5).
*/
sqlite3_int64 timeW, timeF;
sqlite3_int64 timeW; /* Whole days */
sqlite3_int64 timeF; /* Fractional Days */
/* Number of 100-nanosecond intervals in a single day */
static const sqlite3_int64 ntuPerDay =
10000000*(sqlite3_int64)86400;
/* Number of 100-nanosecond intervals in half of a day */
static const sqlite3_int64 ntuPerHalfDay =
10000000*(sqlite3_int64)43200;
/* 2^32 - to avoid use of LL and warnings in gcc */
static const sqlite3_int64 max32BitValue =
(sqlite3_int64)2000000000 + (sqlite3_int64)2000000000 + (sqlite3_int64)294967296;
#if SQLITE_OS_WINCE
SYSTEMTIME time;
GetSystemTime(&time);
@ -1689,25 +1790,14 @@ int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
GetSystemTimeAsFileTime( &ft );
#endif
UNUSED_PARAMETER(pVfs);
#if defined(_MSC_VER)
timeW = (((sqlite3_int64)ft.dwHighDateTime)*4294967296) + ft.dwLowDateTime;
timeF = timeW % 864000000000; /* fractional days (100-nanoseconds) */
timeW = timeW / 864000000000; /* whole days */
timeW = timeW + 2305813; /* add whole days (from 2305813.5) */
timeF = timeF + 432000000000; /* add half a day (from 2305813.5) */
timeW = timeW + (timeF / 864000000000); /* add whole day if half day made one */
timeF = timeF % 864000000000; /* compute new fractional days */
*prNow = (double)timeW + ((double)timeF / (double)864000000000);
#else
timeW = (((sqlite3_int64)ft.dwHighDateTime)*4294967296LL) + ft.dwLowDateTime;
timeF = timeW % 864000000000LL; /* fractional days (100-nanoseconds) */
timeW = timeW / 864000000000LL; /* whole days */
timeW = timeW + 2305813; /* add whole days (from 2305813.5) */
timeF = timeF + 432000000000LL; /* add half a day (from 2305813.5) */
timeW = timeW + (timeF / 864000000000LL); /* add whole day if half day made one */
timeF = timeF % 864000000000LL; /* compute new fractional days */
*prNow = (double)timeW + ((double)timeF / (double)864000000000LL);
#endif
timeW = (((sqlite3_int64)ft.dwHighDateTime)*max32BitValue) + (sqlite3_int64)ft.dwLowDateTime;
timeF = timeW % ntuPerDay; /* fractional days (100-nanoseconds) */
timeW = timeW / ntuPerDay; /* whole days */
timeW = timeW + 2305813; /* add whole days (from 2305813.5) */
timeF = timeF + ntuPerHalfDay; /* add half a day (from 2305813.5) */
timeW = timeW + (timeF/ntuPerDay); /* add whole day if half day made one */
timeF = timeF % ntuPerDay; /* compute new fractional days */
*prNow = (double)timeW + ((double)timeF / (double)ntuPerDay);
#ifdef SQLITE_TEST
if( sqlite3_current_time ){
*prNow = ((double)sqlite3_current_time + (double)43200) / (double)86400 + (double)2440587;
@ -1723,7 +1813,7 @@ int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
** function, SQLite calls this function with zBuf pointing to
** a buffer of nBuf bytes. The OS layer should populate the
** buffer with a nul-terminated UTF-8 encoded error message
** describing the last IO error to have occured within the calling
** describing the last IO error to have occurred within the calling
** thread.
**
** If the error message is too large for the supplied buffer,

View File

@ -18,7 +18,7 @@
** file simultaneously, or one process from reading the database while
** another is writing.
**
** @(#) $Id: pager.c,v 1.570 2009/02/17 17:56:30 danielk1977 Exp $
** @(#) $Id: pager.c,v 1.580 2009/04/11 16:27:50 drh Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"
@ -99,12 +99,6 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
#define PAGER_EXCLUSIVE 4 /* same as EXCLUSIVE_LOCK */
#define PAGER_SYNCED 5
/*
** This macro rounds values up so that if the value is an address it
** is guaranteed to be an address that is aligned to an 8-byte boundary.
*/
#define FORCE_ALIGNMENT(X) (((X)+7)&~7)
/*
** A macro used for invoking the codec if there is one
*/
@ -762,7 +756,7 @@ static int writeJournalHdr(Pager *pPager){
** A faster alternative is to write 0xFFFFFFFF to the nRec field. When
** reading the journal this value tells SQLite to assume that the
** rest of the journal file contains valid page records. This assumption
** is dangerous, as if a failure occured whilst writing to the journal
** is dangerous, as if a failure occurred whilst writing to the journal
** file it may contain some garbage data. There are two scenarios
** where this risk can be ignored:
**
@ -1143,7 +1137,7 @@ static void pager_unlock(Pager *pPager){
/*
** This function should be called when an IOERR, CORRUPT or FULL error
** may have occured. The first argument is a pointer to the pager
** may have occurred. The first argument is a pointer to the pager
** structure, the second the error-code about to be returned by a pager
** API function. The value returned is a copy of the second argument
** to this function.
@ -1156,7 +1150,7 @@ static void pager_unlock(Pager *pPager){
** A persistent error indicates that the contents of the pager-cache
** cannot be trusted. This state can be cleared by completely discarding
** the contents of the pager-cache. If a transaction was active when
** the persistent error occured, then the rollback journal may need
** the persistent error occurred, then the rollback journal may need
** to be replayed to restore the contents of the database file (as if
** it were a hot-journal).
*/
@ -1505,6 +1499,7 @@ static int pager_playback_one_page(
** Do not attempt to write if database file has never been opened.
*/
pPg = pager_lookup(pPager, pgno);
assert( pPg || !MEMDB );
PAGERTRACE(("PLAYBACK %d page %d hash(%08x) %s\n",
PAGERID(pPager), pgno, pager_datahash(pPager->pageSize, aData),
(isMainJrnl?"main-journal":"sub-journal")
@ -2029,11 +2024,11 @@ static int pager_playback(Pager *pPager, int isHot){
pPager->journalOff = szJ;
break;
}else{
/* If we are unable to rollback, then the database is probably
** going to end up being corrupt. It is corrupt to us, anyhow.
** Perhaps the next process to come along can fix it....
/* If we are unable to rollback, quit and return the error
** code. This will cause the pager to enter the error state
** so that no further harm will be done. Perhaps the next
** process to come along will be able to rollback the database.
*/
rc = SQLITE_CORRUPT_BKPT;
goto end_playback;
}
}
@ -2054,7 +2049,7 @@ end_playback:
);
/* If this playback is happening automatically as a result of an IO or
** malloc error that occured after the change-counter was updated but
** malloc error that occurred after the change-counter was updated but
** before the transaction was committed, then the change-counter
** modification may just have been reverted. If this happens in exclusive
** mode, then subsequent transactions performed by the connection will not
@ -3119,9 +3114,9 @@ int sqlite3PagerOpen(
** source file journal.c).
*/
if( sqlite3JournalSize(pVfs)>sqlite3MemJournalSize() ){
journalFileSize = sqlite3JournalSize(pVfs);
journalFileSize = ROUND8(sqlite3JournalSize(pVfs));
}else{
journalFileSize = sqlite3MemJournalSize();
journalFileSize = ROUND8(sqlite3MemJournalSize());
}
/* Set the output variable to NULL in case an error occurs. */
@ -3177,23 +3172,25 @@ int sqlite3PagerOpen(
** Journal file name (nPathname+8+1 bytes)
*/
pPtr = (u8 *)sqlite3MallocZero(
sizeof(*pPager) + /* Pager structure */
pcacheSize + /* PCache object */
pVfs->szOsFile + /* The main db file */
journalFileSize * 2 + /* The two journal files */
nPathname + 1 + /* zFilename */
nPathname + 8 + 1 /* zJournal */
ROUND8(sizeof(*pPager)) + /* Pager structure */
ROUND8(pcacheSize) + /* PCache object */
ROUND8(pVfs->szOsFile) + /* The main db file */
journalFileSize * 2 + /* The two journal files */
nPathname + 1 + /* zFilename */
nPathname + 8 + 1 /* zJournal */
);
assert( EIGHT_BYTE_ALIGNMENT(journalFileSize) );
if( !pPtr ){
sqlite3_free(zPathname);
return SQLITE_NOMEM;
}
pPager = (Pager*)(pPtr);
pPager->pPCache = (PCache*)(pPtr += sizeof(*pPager));
pPager->fd = (sqlite3_file*)(pPtr += pcacheSize);
pPager->sjfd = (sqlite3_file*)(pPtr += pVfs->szOsFile);
pPager->pPCache = (PCache*)(pPtr += ROUND8(sizeof(*pPager)));
pPager->fd = (sqlite3_file*)(pPtr += ROUND8(pcacheSize));
pPager->sjfd = (sqlite3_file*)(pPtr += ROUND8(pVfs->szOsFile));
pPager->jfd = (sqlite3_file*)(pPtr += journalFileSize);
pPager->zFilename = (char*)(pPtr += journalFileSize);
assert( EIGHT_BYTE_ALIGNMENT(pPager->jfd) );
/* Fill in the Pager.zFilename and Pager.zJournal buffers, if required. */
if( zPathname ){
@ -3268,7 +3265,7 @@ int sqlite3PagerOpen(
testcase( rc!=SQLITE_OK );
}
/* If an error occured in either of the blocks above, free the
/* If an error occurred in either of the blocks above, free the
** Pager structure and close the file.
*/
if( rc!=SQLITE_OK ){
@ -3279,7 +3276,7 @@ int sqlite3PagerOpen(
}
/* Initialize the PCache object. */
nExtra = FORCE_ALIGNMENT(nExtra);
nExtra = ROUND8(nExtra);
sqlite3PcacheOpen(szPageDflt, nExtra, !memDb,
!memDb?pagerStress:0, (void *)pPager, pPager->pPCache);
@ -3335,11 +3332,12 @@ int sqlite3PagerOpen(
** PAGER_SHARED state. It tests if there is a hot journal present in
** the file-system for the given pager. A hot journal is one that
** needs to be played back. According to this function, a hot-journal
** file exists if the following three criteria are met:
** file exists if the following criteria are met:
**
** * The journal file exists in the file system, and
** * No process holds a RESERVED or greater lock on the database file, and
** * The database file itself is greater than 0 bytes in size.
** * The database file itself is greater than 0 bytes in size, and
** * The first byte of the journal file exists and is not 0x00.
**
** If the current size of the database file is 0 but a journal file
** exists, that is probably an old journal left over from a prior
@ -3347,14 +3345,12 @@ int sqlite3PagerOpen(
** just deleted using OsDelete, *pExists is set to 0 and SQLITE_OK
** is returned.
**
** This routine does not open the journal file to examine its
** content. Hence, the journal might contain the name of a master
** journal file that has been deleted, and hence not be hot. Or
** the header of the journal might be zeroed out. This routine
** does not discover these cases of a non-hot journal - if the
** journal file exists and is not empty this routine assumes it
** is hot. The pager_playback() routine will discover that the
** journal file is not really hot and will no-op.
** This routine does not check if there is a master journal filename
** at the end of the file. If there is, and that master journal file
** does not exist, then the journal file is not really hot. In this
** case this routine will return a false-positive. The pager_playback()
** routine will discover that the journal file is not really hot and
** will not roll it back.
**
** If a hot-journal file is found to exist, *pExists is set to 1 and
** SQLITE_OK returned. If no hot-journal file is present, *pExists is
@ -3365,29 +3361,52 @@ int sqlite3PagerOpen(
static int hasHotJournal(Pager *pPager, int *pExists){
sqlite3_vfs * const pVfs = pPager->pVfs;
int rc; /* Return code */
int exists = 0; /* True if a journal file is present */
int locked = 0; /* True if some process holds a RESERVED lock */
int exists; /* True if a journal file is present */
assert( pPager!=0 );
assert( pPager->useJournal );
assert( isOpen(pPager->fd) );
assert( !isOpen(pPager->jfd) );
*pExists = 0;
rc = sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &exists);
if( rc==SQLITE_OK && exists ){
int locked; /* True if some process holds a RESERVED lock */
rc = sqlite3OsCheckReservedLock(pPager->fd, &locked);
if( rc==SQLITE_OK && !locked ){
int nPage;
/* Check the size of the database file. If it consists of 0 pages,
** then delete the journal file. See the header comment above for
** the reasoning here.
*/
rc = sqlite3PagerPagecount(pPager, &nPage);
if( rc==SQLITE_OK ){
if( nPage==0 ){
sqlite3OsDelete(pVfs, pPager->zJournal, 0);
if( nPage==0 ){
rc = sqlite3OsDelete(pVfs, pPager->zJournal, 0);
}else{
*pExists = 1;
/* The journal file exists and no other connection has a reserved
** or greater lock on the database file. Now check that there is
** at least one non-zero bytes at the start of the journal file.
** If there is, then we consider this journal to be hot. If not,
** it can be ignored.
*/
int f = SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL;
rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &f);
if( rc==SQLITE_OK ){
u8 first = 0;
rc = sqlite3OsRead(pPager->jfd, (void *)&first, 1, 0);
if( rc==SQLITE_IOERR_SHORT_READ ){
rc = SQLITE_OK;
}
sqlite3OsClose(pPager->jfd);
*pExists = (first!=0);
}
}
}
}
}
return rc;
}
@ -3413,10 +3432,13 @@ static int readDbPage(PgHdr *pPg){
if( !isOpen(pPager->fd) ){
assert( pPager->tempFile );
memset(pPg->pData, 0, pPager->pageSize);
return SQLITE_IOERR_SHORT_READ;
return SQLITE_OK;
}
iOffset = (pgno-1)*(i64)pPager->pageSize;
rc = sqlite3OsRead(pPager->fd, pPg->pData, pPager->pageSize, iOffset);
if( rc==SQLITE_IOERR_SHORT_READ ){
rc = SQLITE_OK;
}
if( pgno==1 ){
u8 *dbFileVers = &((u8*)pPg->pData)[24];
memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers));
@ -3800,7 +3822,7 @@ int sqlite3PagerAcquire(
}else{
assert( pPg->pPager==pPager );
rc = readDbPage(pPg);
if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){
if( rc!=SQLITE_OK ){
pagerDropPage(pPg);
return rc;
}
@ -3933,7 +3955,7 @@ static int pager_open_journal(Pager *pPager){
sqlite3MemJournalOpen(pPager->jfd);
}else{
const int flags = /* VFS flags to open journal file */
SQLITE_OPEN_READWRITE|SQLITE_OPEN_EXCLUSIVE|SQLITE_OPEN_CREATE|
SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|
(pPager->tempFile ?
(SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL):
(SQLITE_OPEN_MAIN_JOURNAL)
@ -4135,7 +4157,7 @@ static int pager_write(PgHdr *pPg){
pPager->needSync = 1;
}
/* An error has occured writing to the journal file. The
/* An error has occurred writing to the journal file. The
** transaction will be rolled back by the layer above.
*/
if( rc!=SQLITE_OK ){
@ -4851,7 +4873,7 @@ int sqlite3PagerOpenSavepoint(Pager *pPager, int nSavepoint){
** Parameter op is always either SAVEPOINT_ROLLBACK or SAVEPOINT_RELEASE.
** If it is SAVEPOINT_RELEASE, then release and destroy the savepoint with
** index iSavepoint. If it is SAVEPOINT_ROLLBACK, then rollback all changes
** that have occured since the specified savepoint was created.
** that have occurred since the specified savepoint was created.
**
** The savepoint to rollback or release is identified by parameter
** iSavepoint. A value of 0 means to operate on the outermost savepoint
@ -4997,6 +5019,7 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){
PgHdr *pPgOld; /* The page being overwritten. */
Pgno needSyncPgno = 0; /* Old value of pPg->pgno, if sync is required */
int rc; /* Return code */
Pgno origPgno; /* The original page number */
assert( pPg->nRef>0 );
@ -5053,13 +5076,11 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){
assert( !pPgOld || pPgOld->nRef==1 );
if( pPgOld ){
pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC);
}
sqlite3PcacheMove(pPg, pgno);
if( pPgOld ){
sqlite3PcacheDrop(pPgOld);
}
origPgno = pPg->pgno;
sqlite3PcacheMove(pPg, pgno);
sqlite3PcacheMakeDirty(pPg);
pPager->dbModified = 1;
@ -5097,6 +5118,19 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){
sqlite3PagerUnref(pPgHdr);
}
/*
** For an in-memory database, make sure the original page continues
** to exist, in case the transaction needs to roll back. We allocate
** the page now, instead of at rollback, because we can better deal
** with an out-of-memory error now. Ticket #3761.
*/
if( MEMDB ){
DbPage *pNew;
rc = sqlite3PagerAcquire(pPager, origPgno, &pNew, 1);
if( rc!=SQLITE_OK ) return rc;
sqlite3PagerUnref(pNew);
}
return SQLITE_OK;
}
#endif
@ -5151,30 +5185,33 @@ int sqlite3PagerLockingMode(Pager *pPager, int eMode){
** PAGER_JOURNALMODE_MEMORY
**
** If the parameter is not _QUERY, then the journal-mode is set to the
** value specified.
** value specified. Except, an in-memory database can only have its
** journal mode set to _OFF or _MEMORY. Attempts to change the journal
** mode of an in-memory database to something other than _OFF or _MEMORY
** are silently ignored.
**
** The returned indicate the current (possibly updated) journal-mode.
*/
int sqlite3PagerJournalMode(Pager *pPager, int eMode){
if( !MEMDB ){
assert( eMode==PAGER_JOURNALMODE_QUERY
|| eMode==PAGER_JOURNALMODE_DELETE
|| eMode==PAGER_JOURNALMODE_TRUNCATE
|| eMode==PAGER_JOURNALMODE_PERSIST
|| eMode==PAGER_JOURNALMODE_OFF
|| eMode==PAGER_JOURNALMODE_MEMORY );
assert( PAGER_JOURNALMODE_QUERY<0 );
if( eMode>=0 ){
pPager->journalMode = (u8)eMode;
}else{
assert( eMode==PAGER_JOURNALMODE_QUERY );
}
assert( eMode==PAGER_JOURNALMODE_QUERY
|| eMode==PAGER_JOURNALMODE_DELETE
|| eMode==PAGER_JOURNALMODE_TRUNCATE
|| eMode==PAGER_JOURNALMODE_PERSIST
|| eMode==PAGER_JOURNALMODE_OFF
|| eMode==PAGER_JOURNALMODE_MEMORY );
assert( PAGER_JOURNALMODE_QUERY<0 );
if( eMode>=0 && (!MEMDB || eMode==PAGER_JOURNALMODE_MEMORY
|| eMode==PAGER_JOURNALMODE_OFF) ){
pPager->journalMode = (u8)eMode;
}
return (int)pPager->journalMode;
}
/*
** Get/set the size-limit used for persistent journal files.
**
** Setting the size limit to -1 means no limit is enforced.
** An attempt to set a limit smaller than -1 is a no-op.
*/
i64 sqlite3PagerJournalSizeLimit(Pager *pPager, i64 iLimit){
if( iLimit>=-1 ){

View File

@ -14,7 +14,7 @@
** the parser. Lemon will also generate a header file containing
** numeric codes for all of the tokens.
**
** @(#) $Id: parse.y,v 1.268 2009/01/29 19:27:47 drh Exp $
** @(#) $Id: parse.y,v 1.274 2009/04/06 14:16:43 drh Exp $
*/
// All token codes are small integers with #defines that begin with "TK_"
@ -133,9 +133,13 @@ cmd ::= ROLLBACK trans_opt TO savepoint_opt nm(X). {
///////////////////// The CREATE TABLE statement ////////////////////////////
//
cmd ::= create_table create_table_args.
create_table ::= CREATE temp(T) TABLE ifnotexists(E) nm(Y) dbnm(Z). {
create_table ::= createkw temp(T) TABLE ifnotexists(E) nm(Y) dbnm(Z). {
sqlite3StartTable(pParse,&Y,&Z,T,0,0,E);
}
createkw(A) ::= CREATE(X). {
pParse->db->lookaside.bEnabled = 0;
A = X;
}
%type ifnotexists {int}
ifnotexists(A) ::= . {A = 0;}
ifnotexists(A) ::= IF NOT EXISTS. {A = 1;}
@ -174,6 +178,7 @@ columnid(A) ::= nm(X). {
//
%type id {Token}
id(A) ::= ID(X). {A = X;}
id(A) ::= INDEXED(X). {A = X;}
// The following directive causes tokens ABORT, AFTER, ASC, etc. to
// fallback to ID if they will not parse as their original value.
@ -224,7 +229,7 @@ ids(A) ::= ID|STRING(X). {A = X;}
// The name of a column or table can be any of the following:
//
%type nm {Token}
nm(A) ::= ID(X). {A = X;}
nm(A) ::= id(X). {A = X;}
nm(A) ::= STRING(X). {A = X;}
nm(A) ::= JOIN_KW(X). {A = X;}
@ -364,7 +369,7 @@ ifexists(A) ::= . {A = 0;}
///////////////////// The CREATE VIEW statement /////////////////////////////
//
%ifndef SQLITE_OMIT_VIEW
cmd ::= CREATE(X) temp(T) VIEW ifnotexists(E) nm(Y) dbnm(Z) AS select(S). {
cmd ::= createkw(X) temp(T) VIEW ifnotexists(E) nm(Y) dbnm(Z) AS select(S). {
sqlite3CreateView(pParse, &X, &Y, &Z, S, T, E);
}
cmd ::= DROP VIEW ifexists(E) fullname(X). {
@ -697,7 +702,7 @@ inscollist(A) ::= nm(Y).
expr(A) ::= term(X). {A = X;}
expr(A) ::= LP(B) expr(X) RP(E). {A = X; sqlite3ExprSpan(A,&B,&E); }
term(A) ::= NULL(X). {A = sqlite3PExpr(pParse, @X, 0, 0, &X);}
expr(A) ::= ID(X). {A = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);}
expr(A) ::= id(X). {A = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);}
expr(A) ::= JOIN_KW(X). {A = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);}
expr(A) ::= nm(X) DOT nm(Y). {
Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);
@ -824,7 +829,7 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
pList = sqlite3ExprListAppend(pParse,pList, Y, 0);
A = sqlite3PExpr(pParse, TK_BETWEEN, W, 0, 0);
if( A ){
A->pList = pList;
A->x.pList = pList;
}else{
sqlite3ExprListDelete(pParse->db, pList);
}
@ -838,7 +843,7 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
expr(A) ::= expr(X) in_op(N) LP exprlist(Y) RP(E). [IN] {
A = sqlite3PExpr(pParse, TK_IN, X, 0, 0);
if( A ){
A->pList = Y;
A->x.pList = Y;
sqlite3ExprSetHeight(pParse, A);
}else{
sqlite3ExprListDelete(pParse->db, Y);
@ -849,7 +854,8 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
expr(A) ::= LP(B) select(X) RP(E). {
A = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0);
if( A ){
A->pSelect = X;
A->x.pSelect = X;
ExprSetProperty(A, EP_xIsSelect);
sqlite3ExprSetHeight(pParse, A);
}else{
sqlite3SelectDelete(pParse->db, X);
@ -859,7 +865,8 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
expr(A) ::= expr(X) in_op(N) LP select(Y) RP(E). [IN] {
A = sqlite3PExpr(pParse, TK_IN, X, 0, 0);
if( A ){
A->pSelect = Y;
A->x.pSelect = Y;
ExprSetProperty(A, EP_xIsSelect);
sqlite3ExprSetHeight(pParse, A);
}else{
sqlite3SelectDelete(pParse->db, Y);
@ -871,7 +878,8 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&Y,&Z);
A = sqlite3PExpr(pParse, TK_IN, X, 0, 0);
if( A ){
A->pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0);
A->x.pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0);
ExprSetProperty(A, EP_xIsSelect);
sqlite3ExprSetHeight(pParse, A);
}else{
sqlite3SrcListDelete(pParse->db, pSrc);
@ -882,7 +890,8 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
expr(A) ::= EXISTS(B) LP select(Y) RP(E). {
Expr *p = A = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0);
if( p ){
p->pSelect = Y;
p->x.pSelect = Y;
ExprSetProperty(A, EP_xIsSelect);
sqlite3ExprSpan(p,&B,&E);
sqlite3ExprSetHeight(pParse, A);
}else{
@ -895,7 +904,7 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). {
A = sqlite3PExpr(pParse, TK_CASE, X, Z, 0);
if( A ){
A->pList = Y;
A->x.pList = Y;
sqlite3ExprSetHeight(pParse, A);
}else{
sqlite3ExprListDelete(pParse->db, Y);
@ -936,7 +945,7 @@ nexprlist(A) ::= expr(Y).
///////////////////////////// The CREATE INDEX command ///////////////////////
//
cmd ::= CREATE(S) uniqueflag(U) INDEX ifnotexists(NE) nm(X) dbnm(D)
cmd ::= createkw(S) uniqueflag(U) INDEX ifnotexists(NE) nm(X) dbnm(D)
ON nm(Y) LP idxlist(Z) RP(E). {
sqlite3CreateIndex(pParse, &X, &D,
sqlite3SrcListAppend(pParse->db,0,&Y,0), Z, U,
@ -997,16 +1006,19 @@ cmd ::= VACUUM nm. {sqlite3Vacuum(pParse);}
//
%ifndef SQLITE_OMIT_PARSER
%ifndef SQLITE_OMIT_PRAGMA
cmd ::= PRAGMA nm(X) dbnm(Z) EQ nmnum(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
cmd ::= PRAGMA nm(X) dbnm(Z) EQ ON(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
cmd ::= PRAGMA nm(X) dbnm(Z) EQ DELETE(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
cmd ::= PRAGMA nm(X) dbnm(Z) EQ minus_num(Y). {
sqlite3Pragma(pParse,&X,&Z,&Y,1);
}
cmd ::= PRAGMA nm(X) dbnm(Z). {sqlite3Pragma(pParse,&X,&Z,0,0);}
cmd ::= PRAGMA nm(X) dbnm(Z) EQ nmnum(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
cmd ::= PRAGMA nm(X) dbnm(Z) LP nmnum(Y) RP. {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
cmd ::= PRAGMA nm(X) dbnm(Z). {sqlite3Pragma(pParse,&X,&Z,0,0);}
cmd ::= PRAGMA nm(X) dbnm(Z) EQ minus_num(Y).
{sqlite3Pragma(pParse,&X,&Z,&Y,1);}
cmd ::= PRAGMA nm(X) dbnm(Z) LP minus_num(Y) RP.
{sqlite3Pragma(pParse,&X,&Z,&Y,1);}
nmnum(A) ::= plus_num(X). {A = X;}
nmnum(A) ::= nm(X). {A = X;}
nmnum(A) ::= ON(X). {A = X;}
nmnum(A) ::= DELETE(X). {A = X;}
nmnum(A) ::= DEFAULT(X). {A = X;}
%endif SQLITE_OMIT_PRAGMA
%endif SQLITE_OMIT_PARSER
plus_num(A) ::= plus_opt number(X). {A = X;}
@ -1019,7 +1031,7 @@ plus_opt ::= .
%ifndef SQLITE_OMIT_TRIGGER
cmd ::= CREATE trigger_decl(A) BEGIN trigger_cmd_list(S) END(Z). {
cmd ::= createkw trigger_decl(A) BEGIN trigger_cmd_list(S) END(Z). {
Token all;
all.z = A.z;
all.n = (int)(Z.z - A.z) + Z.n;
@ -1100,14 +1112,14 @@ trigger_cmd(A) ::= select(X). {A = sqlite3TriggerSelectStep(pParse->db, X); }
expr(A) ::= RAISE(X) LP IGNORE RP(Y). {
A = sqlite3PExpr(pParse, TK_RAISE, 0, 0, 0);
if( A ){
A->iColumn = OE_Ignore;
A->affinity = OE_Ignore;
sqlite3ExprSpan(A, &X, &Y);
}
}
expr(A) ::= RAISE(X) LP raisetype(T) COMMA nm(Z) RP(Y). {
A = sqlite3PExpr(pParse, TK_RAISE, 0, 0, &Z);
if( A ) {
A->iColumn = T;
A->affinity = (char)T;
sqlite3ExprSpan(A, &X, &Y);
}
}
@ -1165,6 +1177,7 @@ cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column(Y). {
sqlite3AlterFinishAddColumn(pParse, &Y);
}
add_column_fullname ::= fullname(X). {
pParse->db->lookaside.bEnabled = 0;
sqlite3AlterBeginAddColumn(pParse, X);
}
kwcolumn_opt ::= .
@ -1175,7 +1188,7 @@ kwcolumn_opt ::= COLUMNKW.
%ifndef SQLITE_OMIT_VIRTUALTABLE
cmd ::= create_vtab. {sqlite3VtabFinishParse(pParse,0);}
cmd ::= create_vtab LP vtabarglist RP(X). {sqlite3VtabFinishParse(pParse,&X);}
create_vtab ::= CREATE VIRTUAL TABLE nm(X) dbnm(Y) USING nm(Z). {
create_vtab ::= createkw VIRTUAL TABLE nm(X) dbnm(Y) USING nm(Z). {
sqlite3VtabBeginParse(pParse, &X, &Y, &Z);
}
vtabarglist ::= vtabarg.

View File

@ -11,7 +11,7 @@
*************************************************************************
** This file implements that page cache.
**
** @(#) $Id: pcache.c,v 1.43 2009/01/23 16:45:01 danielk1977 Exp $
** @(#) $Id: pcache.c,v 1.44 2009/03/31 01:32:18 drh Exp $
*/
#include "sqliteInt.h"
@ -336,11 +336,9 @@ void sqlite3PcacheDrop(PgHdr *p){
** make it so.
*/
void sqlite3PcacheMakeDirty(PgHdr *p){
PCache *pCache;
p->flags &= ~PGHDR_DONT_WRITE;
assert( p->nRef>0 );
if( 0==(p->flags & PGHDR_DIRTY) ){
pCache = p->pCache;
p->flags |= PGHDR_DIRTY;
pcacheAddToDirtyList( p);
}

View File

@ -16,7 +16,7 @@
** If the default page cache implementation is overriden, then neither of
** these two features are available.
**
** @(#) $Id: pcache1.c,v 1.8 2009/01/23 16:45:01 danielk1977 Exp $
** @(#) $Id: pcache1.c,v 1.10 2009/03/23 04:33:33 danielk1977 Exp $
*/
#include "sqliteInt.h"
@ -129,7 +129,7 @@ static SQLITE_WSD struct PCacheGlobal {
*/
void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
PgFreeslot *p;
sz &= ~7;
sz = ROUNDDOWN8(sz);
pcache1.szSlot = sz;
pcache1.pStart = pBuf;
pcache1.pFree = 0;
@ -516,7 +516,7 @@ static void *pcache1Fetch(sqlite3_pcache *p, unsigned int iKey, int createFlag){
nPinned = pCache->nPage - pCache->nRecyclable;
if( createFlag==1 && pCache->bPurgeable && (
nPinned>=(pcache1.nMaxPage+pCache->nMin-pcache1.nMinPage)
|| nPinned>=(pCache->nMax)
|| nPinned>=(pCache->nMax * 9 / 10)
)){
goto fetch_out;
}

View File

@ -11,7 +11,7 @@
*************************************************************************
** This file contains code used to implement the PRAGMA command.
**
** $Id: pragma.c,v 1.202 2009/01/20 16:53:41 danielk1977 Exp $
** $Id: pragma.c,v 1.209 2009/04/07 22:05:43 drh Exp $
*/
#include "sqliteInt.h"
@ -144,14 +144,16 @@ static int changeTempStorage(Parse *pParse, const char *zStorageType){
/*
** Generate code to return a single integer value.
*/
static void returnSingleInt(Parse *pParse, const char *zLabel, int value){
static void returnSingleInt(Parse *pParse, const char *zLabel, i64 value){
Vdbe *v = sqlite3GetVdbe(pParse);
int mem = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Integer, value, mem);
if( pParse->explain==0 ){
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLabel, SQLITE_STATIC);
i64 *pI64 = sqlite3DbMallocRaw(pParse->db, sizeof(value));
if( pI64 ){
memcpy(pI64, &value, sizeof(value));
}
sqlite3VdbeAddOp4(v, OP_Int64, 0, mem, 0, (char*)pI64, P4_INT64);
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLabel, SQLITE_STATIC);
sqlite3VdbeAddOp2(v, OP_ResultRow, mem, 1);
}
@ -172,6 +174,7 @@ static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
{ "empty_result_callbacks", SQLITE_NullCallback },
{ "legacy_file_format", SQLITE_LegacyFileFmt },
{ "fullfsync", SQLITE_FullFSync },
{ "reverse_unordered_selects", SQLITE_ReverseOrder },
#ifdef SQLITE_DEBUG
{ "sql_trace", SQLITE_SqlTrace },
{ "vdbe_listing", SQLITE_VdbeListing },
@ -368,7 +371,7 @@ void sqlite3Pragma(
** buffer that the pager module resizes using sqlite3_realloc().
*/
db->nextPagesize = atoi(zRight);
if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, -1) ){
if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, -1, 0) ){
db->mallocFailed = 1;
}
}
@ -530,14 +533,11 @@ void sqlite3Pragma(
Pager *pPager = sqlite3BtreePager(pDb->pBt);
i64 iLimit = -2;
if( zRight ){
int iLimit32 = atoi(zRight);
if( iLimit32<-1 ){
iLimit32 = -1;
}
iLimit = iLimit32;
sqlite3Atoi64(zRight, &iLimit);
if( iLimit<-1 ) iLimit = -1;
}
iLimit = sqlite3PagerJournalSizeLimit(pPager, iLimit);
returnSingleInt(pParse, "journal_size_limit", (int)iLimit);
returnSingleInt(pParse, "journal_size_limit", iLimit);
}else
#endif /* SQLITE_OMIT_PAGER_PRAGMAS */
@ -831,7 +831,6 @@ void sqlite3Pragma(
sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "pk", SQLITE_STATIC);
sqlite3ViewGetColumnNames(pParse, pTab);
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
const Token *pDflt;
if( IsHiddenColumn(pCol) ){
nHidden++;
continue;
@ -842,9 +841,9 @@ void sqlite3Pragma(
pCol->zType ? pCol->zType : "", 0);
sqlite3VdbeAddOp2(v, OP_Integer, (pCol->notNull ? 1 : 0), 4);
if( pCol->pDflt ){
pDflt = &pCol->pDflt->span;
assert( pDflt->z );
sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, (char*)pDflt->z, pDflt->n);
const Token *p = &pCol->pDflt->span;
assert( p->z );
sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, (char*)p->z, p->n);
}else{
sqlite3VdbeAddOp2(v, OP_Null, 0, 5);
}
@ -1079,7 +1078,6 @@ void sqlite3Pragma(
cnt++;
}
}
if( cnt==0 ) continue;
/* Make sure sufficient number of registers have been allocated */
if( pParse->nMem < cnt+4 ){
@ -1152,7 +1150,6 @@ void sqlite3Pragma(
{ OP_Concat, 3, 2, 2},
{ OP_ResultRow, 2, 1, 0},
};
if( pIdx->tnum==0 ) continue;
addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1);
sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
sqlite3VdbeJumpHere(v, addr);

View File

@ -13,7 +13,7 @@
** interface, and routines that contribute to loading the database schema
** from disk.
**
** $Id: prepare.c,v 1.105 2009/01/20 16:53:41 danielk1977 Exp $
** $Id: prepare.c,v 1.116 2009/04/02 18:32:27 drh Exp $
*/
#include "sqliteInt.h"
@ -77,21 +77,17 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
*/
char *zErr;
int rc;
u8 lookasideEnabled;
assert( db->init.busy );
db->init.iDb = iDb;
db->init.newTnum = atoi(argv[1]);
lookasideEnabled = db->lookaside.bEnabled;
db->lookaside.bEnabled = 0;
rc = sqlite3_exec(db, argv[2], 0, 0, &zErr);
db->init.iDb = 0;
db->lookaside.bEnabled = lookasideEnabled;
assert( rc!=SQLITE_OK || zErr==0 );
if( SQLITE_OK!=rc ){
pData->rc = rc;
if( rc==SQLITE_NOMEM ){
db->mallocFailed = 1;
}else if( rc!=SQLITE_INTERRUPT ){
}else if( rc!=SQLITE_INTERRUPT && (rc&0xff)!=SQLITE_LOCKED ){
corruptSchema(pData, argv[0], zErr);
}
sqlite3DbFree(db, zErr);
@ -351,10 +347,10 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
}
if( rc==SQLITE_OK || (db->flags&SQLITE_RecoveryMode)){
/* Black magic: If the SQLITE_RecoveryMode flag is set, then consider
** the schema loaded, even if errors occured. In this situation the
** the schema loaded, even if errors occurred. In this situation the
** current sqlite3_prepare() operation will fail, but the following one
** will attempt to compile the supplied statement against whatever subset
** of the schema was loaded before the error occured. The primary
** of the schema was loaded before the error occurred. The primary
** purpose of this is to allow access to the sqlite_master table
** even when its contents have been corrupted.
*/
@ -532,26 +528,45 @@ static int sqlite3Prepare(
int rc = SQLITE_OK;
int i;
assert( ppStmt );
*ppStmt = 0;
if( sqlite3SafetyOn(db) ){
return SQLITE_MISUSE;
}
if( sqlite3SafetyOn(db) ) return SQLITE_MISUSE;
assert( ppStmt && *ppStmt==0 );
assert( !db->mallocFailed );
assert( sqlite3_mutex_held(db->mutex) );
/* If any attached database schemas are locked, do not proceed with
** compilation. Instead return SQLITE_LOCKED immediately.
/* Check to verify that it is possible to get a read lock on all
** database schemas. The inability to get a read lock indicates that
** some other database connection is holding a write-lock, which in
** turn means that the other connection has made uncommitted changes
** to the schema.
**
** Were we to proceed and prepare the statement against the uncommitted
** schema changes and if those schema changes are subsequently rolled
** back and different changes are made in their place, then when this
** prepared statement goes to run the schema cookie would fail to detect
** the schema change. Disaster would follow.
**
** This thread is currently holding mutexes on all Btrees (because
** of the sqlite3BtreeEnterAll() in sqlite3LockAndPrepare()) so it
** is not possible for another thread to start a new schema change
** while this routine is running. Hence, we do not need to hold
** locks on the schema, we just need to make sure nobody else is
** holding them.
**
** Note that setting READ_UNCOMMITTED overrides most lock detection,
** but it does *not* override schema lock detection, so this all still
** works even if READ_UNCOMMITTED is set.
*/
for(i=0; i<db->nDb; i++) {
Btree *pBt = db->aDb[i].pBt;
if( pBt ){
assert( sqlite3BtreeHoldsMutex(pBt) );
rc = sqlite3BtreeSchemaLocked(pBt);
if( rc ){
const char *zDb = db->aDb[i].zName;
sqlite3Error(db, SQLITE_LOCKED, "database schema is locked: %s", zDb);
sqlite3Error(db, rc, "database schema is locked: %s", zDb);
(void)sqlite3SafetyOff(db);
return sqlite3ApiExit(db, SQLITE_LOCKED);
testcase( db->flags & SQLITE_ReadUncommitted );
return sqlite3ApiExit(db, rc);
}
}
}
@ -621,11 +636,13 @@ static int sqlite3Prepare(
rc = SQLITE_MISUSE;
}
if( saveSqlFlag ){
sqlite3VdbeSetSql(sParse.pVdbe, zSql, (int)(sParse.zTail - zSql));
assert( db->init.busy==0 || saveSqlFlag==0 );
if( db->init.busy==0 ){
Vdbe *pVdbe = sParse.pVdbe;
sqlite3VdbeSetSql(pVdbe, zSql, (int)(sParse.zTail-zSql), saveSqlFlag);
}
if( rc!=SQLITE_OK || db->mallocFailed ){
sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe);
if( sParse.pVdbe && (rc!=SQLITE_OK || db->mallocFailed) ){
sqlite3VdbeFinalize(sParse.pVdbe);
assert(!(*ppStmt));
}else{
*ppStmt = (sqlite3_stmt*)sParse.pVdbe;
@ -651,6 +668,8 @@ static int sqlite3LockAndPrepare(
const char **pzTail /* OUT: End of parsed string */
){
int rc;
assert( ppStmt!=0 );
*ppStmt = 0;
if( !sqlite3SafetyCheckOk(db) ){
return SQLITE_MISUSE;
}
@ -664,8 +683,11 @@ static int sqlite3LockAndPrepare(
/*
** Rerun the compilation of a statement after a schema change.
** Return true if the statement was recompiled successfully.
** Return false if there is an error of some kind.
**
** If the statement is successfully recompiled, return SQLITE_OK. Otherwise,
** if the statement cannot be recompiled because another connection has
** locked the sqlite3_master table, return SQLITE_LOCKED. If any other error
** occurs, return SQLITE_SCHEMA.
*/
int sqlite3Reprepare(Vdbe *p){
int rc;
@ -684,7 +706,7 @@ int sqlite3Reprepare(Vdbe *p){
db->mallocFailed = 1;
}
assert( pNew==0 );
return 0;
return (rc==SQLITE_LOCKED) ? SQLITE_LOCKED : SQLITE_SCHEMA;
}else{
assert( pNew!=0 );
}
@ -692,7 +714,7 @@ int sqlite3Reprepare(Vdbe *p){
sqlite3TransferBindings(pNew, (sqlite3_stmt*)p);
sqlite3VdbeResetStepResult((Vdbe*)pNew);
sqlite3VdbeFinalize((Vdbe*)pNew);
return 1;
return SQLITE_OK;
}
@ -750,6 +772,8 @@ static int sqlite3Prepare16(
const char *zTail8 = 0;
int rc = SQLITE_OK;
assert( ppStmt );
*ppStmt = 0;
if( !sqlite3SafetyCheckOk(db) ){
return SQLITE_MISUSE;
}

View File

@ -5,7 +5,7 @@
** an historical reference. Most of the "enhancements" have been backed
** out so that the functionality is now the same as standard printf().
**
** $Id: printf.c,v 1.99 2008/12/10 19:26:24 drh Exp $
** $Id: printf.c,v 1.102 2009/04/08 16:10:04 drh Exp $
**
**************************************************************************
**
@ -77,6 +77,8 @@
#define etSQLESCAPE3 15 /* %w -> Strings with '\"' doubled */
#define etORDINAL 16 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */
#define etINVALID 0 /* Any unrecognized conversion type */
/*
** An "etByte" is an 8-bit unsigned value.
@ -133,6 +135,9 @@ static const et_info fmtinfo[] = {
{ 'n', 0, 0, etSIZE, 0, 0 },
{ '%', 0, 0, etPERCENT, 0, 0 },
{ 'p', 16, 0, etPOINTER, 0, 1 },
/* All the rest have the FLAG_INTERN bit set and are thus for internal
** use only */
{ 'T', 0, 2, etTOKEN, 0, 0 },
{ 'S', 0, 2, etSRCLIST, 0, 0 },
{ 'r', 10, 3, etORDINAL, 0, 0 },
@ -335,7 +340,8 @@ void sqlite3VXPrintf(
flag_long = flag_longlong = 0;
}
/* Fetch the info entry for the field */
infop = 0;
infop = &fmtinfo[0];
xtype = etINVALID;
for(idx=0; idx<ArraySize(fmtinfo); idx++){
if( c==fmtinfo[idx].fmttype ){
infop = &fmtinfo[idx];
@ -348,9 +354,6 @@ void sqlite3VXPrintf(
}
}
zExtra = 0;
if( infop==0 ){
return;
}
/* Limit the precision to prevent overflowing buf[] during conversion */
@ -688,6 +691,10 @@ void sqlite3VXPrintf(
length = width = 0;
break;
}
default: {
assert( xtype==etINVALID );
return;
}
}/* End switch over the format type */
/*
** The text of the conversion is pointed to by "bufpt" and is
@ -721,13 +728,16 @@ void sqlite3VXPrintf(
** Append N bytes of text from z to the StrAccum object.
*/
void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
assert( z!=0 || N==0 );
if( p->tooBig | p->mallocFailed ){
testcase(p->tooBig);
testcase(p->mallocFailed);
return;
}
if( N<0 ){
N = sqlite3Strlen30(z);
}
if( N==0 || z==0 ){
if( N==0 || NEVER(z==0) ){
return;
}
if( p->nChar+N >= p->nAlloc ){
@ -816,12 +826,13 @@ char *sqlite3VMPrintf(sqlite3 *db, const char *zFormat, va_list ap){
char *z;
char zBase[SQLITE_PRINT_BUF_SIZE];
StrAccum acc;
assert( db!=0 );
sqlite3StrAccumInit(&acc, zBase, sizeof(zBase),
db ? db->aLimit[SQLITE_LIMIT_LENGTH] : SQLITE_MAX_LENGTH);
db->aLimit[SQLITE_LIMIT_LENGTH]);
acc.db = db;
sqlite3VXPrintf(&acc, 1, zFormat, ap);
z = sqlite3StrAccumFinish(&acc);
if( acc.mallocFailed && db ){
if( acc.mallocFailed ){
db->mallocFailed = 1;
}
return z;

View File

@ -14,7 +14,7 @@
** resolve all identifiers by associating them with a particular
** table and column.
**
** $Id: resolve.c,v 1.15 2008/12/10 19:26:24 drh Exp $
** $Id: resolve.c,v 1.20 2009/03/05 04:23:47 shane Exp $
*/
#include "sqliteInt.h"
#include <stdlib.h>
@ -63,8 +63,9 @@ static void resolveAlias(
assert( pOrig!=0 );
assert( pOrig->flags & EP_Resolved );
db = pParse->db;
pDup = sqlite3ExprDup(db, pOrig);
pDup = sqlite3ExprDup(db, pOrig, 0);
if( pDup==0 ) return;
sqlite3TokenCopy(db, &pDup->token, &pOrig->token);
if( pDup->op!=TK_COLUMN && zType[0]!='G' ){
pDup = sqlite3PExpr(pParse, TK_AS, pDup, 0, 0);
if( pDup==0 ) return;
@ -129,6 +130,7 @@ static int lookupName(
NameContext *pTopNC = pNC; /* First namecontext in the list */
Schema *pSchema = 0; /* Schema of the expression */
assert( pNC ); /* the name context cannot be NULL. */
assert( pColumnToken && pColumnToken->z ); /* The Z in X.Y.Z cannot be NULL */
/* Dequote and zero-terminate the names */
@ -282,8 +284,8 @@ static int lookupName(
if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){
Expr *pOrig;
assert( pExpr->pLeft==0 && pExpr->pRight==0 );
assert( pExpr->pList==0 );
assert( pExpr->pSelect==0 );
assert( pExpr->x.pList==0 );
assert( pExpr->x.pSelect==0 );
pOrig = pEList->a[j].pExpr;
if( !pNC->allowAgg && ExprHasProperty(pOrig, EP_Agg) ){
sqlite3ErrorMsg(pParse, "misuse of aliased aggregate %s", zAs);
@ -474,8 +476,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
*/
case TK_CONST_FUNC:
case TK_FUNCTION: {
ExprList *pList = pExpr->pList; /* The argument list */
int n = pList ? pList->nExpr : 0; /* Number of arguments */
ExprList *pList = pExpr->x.pList; /* The argument list */
int n = pList ? pList->nExpr : 0; /* Number of arguments */
int no_such_func = 0; /* True if no such function exists */
int wrong_num_args = 0; /* True if wrong number of arguments */
int is_agg = 0; /* True if is an aggregate function */
@ -485,6 +487,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
FuncDef *pDef; /* Information about the function */
u8 enc = ENC(pParse->db); /* The database encoding */
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
zId = (char*)pExpr->token.z;
nId = pExpr->token.n;
pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0);
@ -541,14 +544,14 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
case TK_EXISTS:
#endif
case TK_IN: {
if( pExpr->pSelect ){
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
int nRef = pNC->nRef;
#ifndef SQLITE_OMIT_CHECK
if( pNC->isCheck ){
sqlite3ErrorMsg(pParse,"subqueries prohibited in CHECK constraints");
}
#endif
sqlite3WalkSelect(pWalker, pExpr->pSelect);
sqlite3WalkSelect(pWalker, pExpr->x.pSelect);
assert( pNC->nRef>=nRef );
if( nRef!=pNC->nRef ){
ExprSetProperty(pExpr, EP_VarSelect);
@ -736,7 +739,7 @@ static int resolveCompoundOrderBy(
}else{
iCol = resolveAsName(pParse, pEList, pE);
if( iCol==0 ){
pDup = sqlite3ExprDup(db, pE);
pDup = sqlite3ExprDup(db, pE, 0);
if( !db->mallocFailed ){
assert(pDup);
iCol = resolveOrderByTermToExprList(pParse, pSelect, pDup);

View File

@ -25,7 +25,7 @@
** Big chunks of rowid/next-ptr pairs are allocated at a time, to
** reduce the malloc overhead.
**
** $Id: rowset.c,v 1.3 2009/01/13 20:14:16 drh Exp $
** $Id: rowset.c,v 1.4 2009/04/01 19:35:55 drh Exp $
*/
#include "sqliteInt.h"
@ -120,7 +120,7 @@ void sqlite3RowSetClear(RowSet *p){
void sqlite3RowSetInsert(RowSet *p, i64 rowid){
struct RowSetEntry *pEntry;
struct RowSetEntry *pLast;
if( p==0 ) return; /* Must have been a malloc failure */
assert( p!=0 );
if( p->nFresh==0 ){
struct RowSetChunk *pNew;
pNew = sqlite3DbMallocRaw(p->db, sizeof(*pNew));

View File

@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle SELECT statements in SQLite.
**
** $Id: select.c,v 1.499 2009/02/09 13:19:28 drh Exp $
** $Id: select.c,v 1.507 2009/04/02 16:59:47 drh Exp $
*/
#include "sqliteInt.h"
@ -800,8 +800,7 @@ static void generateSortTail(
iTab = pOrderBy->iECursor;
if( eDest==SRT_Output || eDest==SRT_Coroutine ){
pseudoTab = pParse->nTab++;
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, nColumn);
sqlite3VdbeAddOp2(v, OP_OpenPseudo, pseudoTab, eDest==SRT_Output);
sqlite3VdbeAddOp3(v, OP_OpenPseudo, pseudoTab, eDest==SRT_Output, nColumn);
}
addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak);
codeOffset(v, p, addrContinue);
@ -987,8 +986,9 @@ static const char *columnType(
** statement.
*/
NameContext sNC;
Select *pS = pExpr->pSelect;
Select *pS = pExpr->x.pSelect;
Expr *p = pS->pEList->a[0].pExpr;
assert( ExprHasProperty(pExpr, EP_xIsSelect) );
sNC.pSrcList = pS->pSrc;
sNC.pNext = pNC;
sNC.pParse = pNC->pParse;
@ -1229,7 +1229,7 @@ static int selectColumnsFromExprList(
** The column list has only names, not types or collations. This
** routine goes through and adds the types and collations.
**
** This routine requires that all indentifiers in the SELECT
** This routine requires that all identifiers in the SELECT
** statement be resolved.
*/
static void selectAddColumnTypeAndCollation(
@ -1284,7 +1284,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
if( pTab==0 ){
return 0;
}
pTab->db = db;
pTab->dbMem = db->lookaside.bEnabled ? db : 0;
pTab->nRef = 1;
pTab->zName = 0;
selectColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol);
@ -2141,7 +2141,7 @@ static int multiSelectOrderBy(
/* Reattach the ORDER BY clause to the query.
*/
p->pOrderBy = pOrderBy;
pPrior->pOrderBy = sqlite3ExprListDup(pParse->db, pOrderBy);
pPrior->pOrderBy = sqlite3ExprListDup(pParse->db, pOrderBy, 0);
/* Allocate a range of temporary registers and the KeyInfo needed
** for the logic that removes duplicate result rows when the
@ -2392,23 +2392,26 @@ static void substExpr(
}else{
Expr *pNew;
assert( pEList!=0 && pExpr->iColumn<pEList->nExpr );
assert( pExpr->pLeft==0 && pExpr->pRight==0 && pExpr->pList==0 );
assert( pExpr->pLeft==0 && pExpr->pRight==0 );
pNew = pEList->a[pExpr->iColumn].pExpr;
assert( pNew!=0 );
pExpr->op = pNew->op;
assert( pExpr->pLeft==0 );
pExpr->pLeft = sqlite3ExprDup(db, pNew->pLeft);
pExpr->pLeft = sqlite3ExprDup(db, pNew->pLeft, 0);
assert( pExpr->pRight==0 );
pExpr->pRight = sqlite3ExprDup(db, pNew->pRight);
assert( pExpr->pList==0 );
pExpr->pList = sqlite3ExprListDup(db, pNew->pList);
pExpr->pRight = sqlite3ExprDup(db, pNew->pRight, 0);
pExpr->iTable = pNew->iTable;
pExpr->pTab = pNew->pTab;
pExpr->iColumn = pNew->iColumn;
pExpr->iAgg = pNew->iAgg;
sqlite3TokenCopy(db, &pExpr->token, &pNew->token);
sqlite3TokenCopy(db, &pExpr->span, &pNew->span);
pExpr->pSelect = sqlite3SelectDup(db, pNew->pSelect);
assert( pExpr->x.pList==0 && pExpr->x.pSelect==0 );
if( ExprHasProperty(pNew, EP_xIsSelect) ){
pExpr->x.pSelect = sqlite3SelectDup(db, pNew->x.pSelect, 0);
}else{
pExpr->x.pList = sqlite3ExprListDup(db, pNew->x.pList, 0);
}
pExpr->flags = pNew->flags;
pExpr->pAggInfo = pNew->pAggInfo;
pNew->pAggInfo = 0;
@ -2416,8 +2419,11 @@ static void substExpr(
}else{
substExpr(db, pExpr->pLeft, iTable, pEList);
substExpr(db, pExpr->pRight, iTable, pEList);
substSelect(db, pExpr->pSelect, iTable, pEList);
substExprList(db, pExpr->pList, iTable, pEList);
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
substSelect(db, pExpr->x.pSelect, iTable, pEList);
}else{
substExprList(db, pExpr->x.pList, iTable, pEList);
}
}
}
static void substExprList(
@ -2549,6 +2555,12 @@ static void substSelect(
** (19) The subquery does not use LIMIT or the outer query does not
** have a WHERE clause.
**
** (20) If the sub-query is a compound select, then it must not use
** an ORDER BY clause. Ticket #3773. We could relax this constraint
** somewhat by saying that the terms of the ORDER BY clause must
** appear as unmodified result columns in the outer query. But
** have other optimizations in mind to deal with that case.
**
** In this routine, the "p" parameter is a pointer to the outer query.
** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query
** uses aggregates and subqueryIsAgg is true if the subquery uses aggregates.
@ -2659,6 +2671,9 @@ static int flattenSubquery(
** queries.
*/
if( pSub->pPrior ){
if( pSub->pOrderBy ){
return 0; /* Restriction 20 */
}
if( isAgg || (p->selFlags & SF_Distinct)!=0 || pSrc->nSrc!=1 ){
return 0;
}
@ -2729,7 +2744,7 @@ static int flattenSubquery(
p->pSrc = 0;
p->pPrior = 0;
p->pLimit = 0;
pNew = sqlite3SelectDup(db, p);
pNew = sqlite3SelectDup(db, p, 0);
p->pLimit = pLimit;
p->pOrderBy = pOrderBy;
p->pSrc = pSrc;
@ -2873,7 +2888,7 @@ static int flattenSubquery(
substExprList(db, pParent->pOrderBy, iParent, pSub->pEList);
}
if( pSub->pWhere ){
pWhere = sqlite3ExprDup(db, pSub->pWhere);
pWhere = sqlite3ExprDup(db, pSub->pWhere, 0);
}else{
pWhere = 0;
}
@ -2883,9 +2898,9 @@ static int flattenSubquery(
pParent->pWhere = pWhere;
substExpr(db, pParent->pHaving, iParent, pSub->pEList);
pParent->pHaving = sqlite3ExprAnd(db, pParent->pHaving,
sqlite3ExprDup(db, pSub->pHaving));
sqlite3ExprDup(db, pSub->pHaving, 0));
assert( pParent->pGroupBy==0 );
pParent->pGroupBy = sqlite3ExprListDup(db, pSub->pGroupBy);
pParent->pGroupBy = sqlite3ExprListDup(db, pSub->pGroupBy, 0);
}else{
substExpr(db, pParent->pWhere, iParent, pSub->pEList);
pParent->pWhere = sqlite3ExprAnd(db, pParent->pWhere, pWhere);
@ -2934,7 +2949,8 @@ static u8 minMaxQuery(Select *p){
if( pEList->nExpr!=1 ) return WHERE_ORDERBY_NORMAL;
pExpr = pEList->a[0].pExpr;
pEList = pExpr->pList;
if( ExprHasProperty(pExpr, EP_xIsSelect) ) return 0;
pEList = pExpr->x.pList;
if( pExpr->op!=TK_AGG_FUNCTION || pEList==0 || pEList->nExpr!=1 ) return 0;
if( pEList->a[0].pExpr->op!=TK_AGG_COLUMN ) return WHERE_ORDERBY_NORMAL;
if( pExpr->token.n!=3 ) return WHERE_ORDERBY_NORMAL;
@ -2946,6 +2962,40 @@ static u8 minMaxQuery(Select *p){
return WHERE_ORDERBY_NORMAL;
}
/*
** The select statement passed as the first argument is an aggregate query.
** The second argment is the associated aggregate-info object. This
** function tests if the SELECT is of the form:
**
** SELECT count(*) FROM <tbl>
**
** where table is a database table, not a sub-select or view. If the query
** does match this pattern, then a pointer to the Table object representing
** <tbl> is returned. Otherwise, 0 is returned.
*/
static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){
Table *pTab;
Expr *pExpr;
assert( !p->pGroupBy );
if( p->pWhere || p->pEList->nExpr!=1
|| p->pSrc->nSrc!=1 || p->pSrc->a[0].pSelect
){
return 0;
}
pTab = p->pSrc->a[0].pTab;
pExpr = p->pEList->a[0].pExpr;
assert( pTab && !pTab->pSelect && pExpr );
if( IsVirtual(pTab) ) return 0;
if( pExpr->op!=TK_AGG_FUNCTION ) return 0;
if( (pAggInfo->aFunc[0].pFunc->flags&SQLITE_FUNC_COUNT)==0 ) return 0;
if( pExpr->flags&EP_Distinct ) return 0;
return pTab;
}
/*
** If the source-list item passed as an argument was augmented with an
** INDEXED BY clause, then try to locate the specified index. If there
@ -3039,7 +3089,7 @@ static int selectExpander(Walker *pWalker, Select *p){
sqlite3WalkSelect(pWalker, pSel);
pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
if( pTab==0 ) return WRC_Abort;
pTab->db = db;
pTab->dbMem = db->lookaside.bEnabled ? db : 0;
pTab->nRef = 1;
pTab->zName = sqlite3MPrintf(db, "sqlite_subquery_%p_", (void*)pTab);
while( pSel->pPrior ){ pSel = pSel->pPrior; }
@ -3065,7 +3115,7 @@ static int selectExpander(Walker *pWalker, Select *p){
** in the inner view.
*/
if( pFrom->pSelect==0 ){
pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect);
pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0);
sqlite3WalkSelect(pWalker, pFrom->pSelect);
}
}
@ -3364,12 +3414,13 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
sqlite3VdbeAddOp2(v, OP_Null, 0, pFunc->iMem);
if( pFunc->iDistinct>=0 ){
Expr *pE = pFunc->pExpr;
if( pE->pList==0 || pE->pList->nExpr!=1 ){
assert( !ExprHasProperty(pE, EP_xIsSelect) );
if( pE->x.pList==0 || pE->x.pList->nExpr!=1 ){
sqlite3ErrorMsg(pParse, "DISTINCT aggregates must have exactly one "
"argument");
pFunc->iDistinct = -1;
}else{
KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->pList);
KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->x.pList);
sqlite3VdbeAddOp4(v, OP_OpenEphemeral, pFunc->iDistinct, 0, 0,
(char*)pKeyInfo, P4_KEYINFO_HANDOFF);
}
@ -3386,7 +3437,8 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){
int i;
struct AggInfo_func *pF;
for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
ExprList *pList = pF->pExpr->pList;
ExprList *pList = pF->pExpr->x.pList;
assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) );
sqlite3VdbeAddOp4(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0, 0,
(void*)pF->pFunc, P4_FUNCDEF);
}
@ -3407,7 +3459,8 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
int nArg;
int addrNext = 0;
int regAgg;
ExprList *pList = pF->pExpr->pList;
ExprList *pList = pF->pExpr->x.pList;
assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) );
if( pList ){
nArg = pList->nExpr;
regAgg = sqlite3GetTempRange(pParse, nArg);
@ -3657,7 +3710,7 @@ int sqlite3Select(
** GROUP BY might use an index, DISTINCT never does.
*/
if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct && !p->pGroupBy ){
p->pGroupBy = sqlite3ExprListDup(db, p->pEList);
p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0);
pGroupBy = p->pGroupBy;
p->selFlags &= ~SF_Distinct;
isDistinct = 0;
@ -3780,7 +3833,8 @@ int sqlite3Select(
}
sAggInfo.nAccumulator = sAggInfo.nColumn;
for(i=0; i<sAggInfo.nFunc; i++){
sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->pList);
assert( !ExprHasProperty(sAggInfo.aFunc[i].pExpr, EP_xIsSelect) );
sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->x.pList);
}
if( db->mallocFailed ) goto select_end;
@ -3987,68 +4041,127 @@ int sqlite3Select(
} /* endif pGroupBy */
else {
ExprList *pMinMax = 0;
ExprList *pDel = 0;
u8 flag;
#ifndef SQLITE_OMIT_BTREECOUNT
Table *pTab;
if( (pTab = isSimpleCount(p, &sAggInfo))!=0 ){
/* If isSimpleCount() returns a pointer to a Table structure, then
** the SQL statement is of the form:
**
** SELECT count(*) FROM <tbl>
**
** where the Table structure returned represents table <tbl>.
**
** This statement is so common that it is optimized specially. The
** OP_Count instruction is executed either on the intkey table that
** contains the data for table <tbl> or on one of its indexes. It
** is better to execute the op on an index, as indexes are almost
** always spread across less pages than their corresponding tables.
*/
const int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
const int iCsr = pParse->nTab++; /* Cursor to scan b-tree */
Index *pIdx; /* Iterator variable */
KeyInfo *pKeyInfo = 0; /* Keyinfo for scanned index */
Index *pBest = 0; /* Best index found so far */
int iRoot = pTab->tnum; /* Root page of scanned b-tree */
/* Check if the query is of one of the following forms:
**
** SELECT min(x) FROM ...
** SELECT max(x) FROM ...
**
** If it is, then ask the code in where.c to attempt to sort results
** as if there was an "ORDER ON x" or "ORDER ON x DESC" clause.
** If where.c is able to produce results sorted in this order, then
** add vdbe code to break out of the processing loop after the
** first iteration (since the first iteration of the loop is
** guaranteed to operate on the row with the minimum or maximum
** value of x, the only row required).
**
** A special flag must be passed to sqlite3WhereBegin() to slightly
** modify behaviour as follows:
**
** + If the query is a "SELECT min(x)", then the loop coded by
** where.c should not iterate over any values with a NULL value
** for x.
**
** + The optimizer code in where.c (the thing that decides which
** index or indices to use) should place a different priority on
** satisfying the 'ORDER BY' clause than it does in other cases.
** Refer to code and comments in where.c for details.
*/
flag = minMaxQuery(p);
if( flag ){
pDel = pMinMax = sqlite3ExprListDup(db, p->pEList->a[0].pExpr->pList);
if( pMinMax && !db->mallocFailed ){
pMinMax->a[0].sortOrder = flag!=WHERE_ORDERBY_MIN ?1:0;
pMinMax->a[0].pExpr->op = TK_COLUMN;
sqlite3CodeVerifySchema(pParse, iDb);
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
/* Search for the index that has the least amount of columns. If
** there is such an index, and it has less columns than the table
** does, then we can assume that it consumes less space on disk and
** will therefore be cheaper to scan to determine the query result.
** In this case set iRoot to the root page number of the index b-tree
** and pKeyInfo to the KeyInfo structure required to navigate the
** index.
**
** In practice the KeyInfo structure will not be used. It is only
** passed to keep OP_OpenRead happy.
*/
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
if( !pBest || pIdx->nColumn<pBest->nColumn ){
pBest = pIdx;
}
}
if( pBest && pBest->nColumn<pTab->nCol ){
iRoot = pBest->tnum;
pKeyInfo = sqlite3IndexKeyinfo(pParse, pBest);
}
/* Open a read-only cursor, execute the OP_Count, close the cursor. */
sqlite3VdbeAddOp3(v, OP_OpenRead, iCsr, iRoot, iDb);
if( pKeyInfo ){
sqlite3VdbeChangeP4(v, -1, (char *)pKeyInfo, P4_KEYINFO_HANDOFF);
}
sqlite3VdbeAddOp2(v, OP_Count, iCsr, sAggInfo.aFunc[0].iMem);
sqlite3VdbeAddOp1(v, OP_Close, iCsr);
}else
#endif /* SQLITE_OMIT_BTREECOUNT */
{
/* Check if the query is of one of the following forms:
**
** SELECT min(x) FROM ...
** SELECT max(x) FROM ...
**
** If it is, then ask the code in where.c to attempt to sort results
** as if there was an "ORDER ON x" or "ORDER ON x DESC" clause.
** If where.c is able to produce results sorted in this order, then
** add vdbe code to break out of the processing loop after the
** first iteration (since the first iteration of the loop is
** guaranteed to operate on the row with the minimum or maximum
** value of x, the only row required).
**
** A special flag must be passed to sqlite3WhereBegin() to slightly
** modify behaviour as follows:
**
** + If the query is a "SELECT min(x)", then the loop coded by
** where.c should not iterate over any values with a NULL value
** for x.
**
** + The optimizer code in where.c (the thing that decides which
** index or indices to use) should place a different priority on
** satisfying the 'ORDER BY' clause than it does in other cases.
** Refer to code and comments in where.c for details.
*/
ExprList *pMinMax = 0;
u8 flag = minMaxQuery(p);
if( flag ){
assert( !ExprHasProperty(p->pEList->a[0].pExpr, EP_xIsSelect) );
pMinMax = sqlite3ExprListDup(db, p->pEList->a[0].pExpr->x.pList,0);
pDel = pMinMax;
if( pMinMax && !db->mallocFailed ){
pMinMax->a[0].sortOrder = flag!=WHERE_ORDERBY_MIN ?1:0;
pMinMax->a[0].pExpr->op = TK_COLUMN;
}
}
/* This case runs if the aggregate has no GROUP BY clause. The
** processing is much simpler since there is only a single row
** of output.
*/
resetAccumulator(pParse, &sAggInfo);
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pMinMax, flag, 0);
if( pWInfo==0 ){
sqlite3ExprListDelete(db, pDel);
goto select_end;
}
updateAccumulator(pParse, &sAggInfo);
if( !pMinMax && flag ){
sqlite3VdbeAddOp2(v, OP_Goto, 0, pWInfo->iBreak);
VdbeComment((v, "%s() by index",
(flag==WHERE_ORDERBY_MIN?"min":"max")));
}
sqlite3WhereEnd(pWInfo);
finalizeAggFunctions(pParse, &sAggInfo);
}
/* This case runs if the aggregate has no GROUP BY clause. The
** processing is much simpler since there is only a single row
** of output.
*/
resetAccumulator(pParse, &sAggInfo);
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pMinMax, flag, 0);
if( pWInfo==0 ){
sqlite3ExprListDelete(db, pDel);
goto select_end;
}
updateAccumulator(pParse, &sAggInfo);
if( !pMinMax && flag ){
sqlite3VdbeAddOp2(v, OP_Goto, 0, pWInfo->iBreak);
VdbeComment((v, "%s() by index",(flag==WHERE_ORDERBY_MIN?"min":"max")));
}
sqlite3WhereEnd(pWInfo);
finalizeAggFunctions(pParse, &sAggInfo);
pOrderBy = 0;
if( pHaving ){
sqlite3ExprIfFalse(pParse, pHaving, addrEnd, SQLITE_JUMPIFNULL);
}
selectInnerLoop(pParse, p, p->pEList, 0, 0, 0, -1,
pDest, addrEnd, addrEnd);
sqlite3ExprListDelete(db, pDel);
}
sqlite3VdbeResolveLabel(v, addrEnd);

View File

@ -12,7 +12,7 @@
** This file contains code to implement the "sqlite" command line
** utility for accessing SQLite databases.
**
** $Id: shell.c,v 1.201 2009/02/04 22:46:47 drh Exp $
** $Id: shell.c,v 1.207 2009/03/16 10:59:44 drh Exp $
*/
#if defined(_WIN32) || defined(WIN32)
/* This needs to come before any includes for MSVC compiler */
@ -120,6 +120,861 @@ static void endTimer(void){
*/
#define UNUSED_PARAMETER(x) (void)(x)
/**************************************************************************
***************************************************************************
** Begin genfkey logic.
*/
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined SQLITE_OMIT_SUBQUERY
#define GENFKEY_ERROR 1
#define GENFKEY_DROPTRIGGER 2
#define GENFKEY_CREATETRIGGER 3
static int genfkey_create_triggers(sqlite3 *, const char *, void *,
int (*)(void *, int, const char *)
);
struct GenfkeyCb {
void *pCtx;
int eType;
int (*xData)(void *, int, const char *);
};
typedef struct GenfkeyCb GenfkeyCb;
/* The code in this file defines a sqlite3 virtual-table module that
** provides a read-only view of the current database schema. There is one
** row in the schema table for each column in the database schema.
*/
#define SCHEMA \
"CREATE TABLE x(" \
"database," /* Name of database (i.e. main, temp etc.) */ \
"tablename," /* Name of table */ \
"cid," /* Column number (from left-to-right, 0 upward) */ \
"name," /* Column name */ \
"type," /* Specified type (i.e. VARCHAR(32)) */ \
"not_null," /* Boolean. True if NOT NULL was specified */ \
"dflt_value," /* Default value for this column */ \
"pk" /* True if this column is part of the primary key */ \
")"
#define SCHEMA2 \
"CREATE TABLE x(" \
"database," /* Name of database (i.e. main, temp etc.) */ \
"from_tbl," /* Name of table */ \
"fkid," \
"seq," \
"to_tbl," \
"from_col," \
"to_col," \
"on_update," \
"on_delete," \
"match" \
")"
#define SCHEMA3 \
"CREATE TABLE x(" \
"database," /* Name of database (i.e. main, temp etc.) */ \
"tablename," /* Name of table */ \
"seq," \
"name," \
"isunique" \
")"
#define SCHEMA4 \
"CREATE TABLE x(" \
"database," /* Name of database (i.e. main, temp etc.) */ \
"indexname," /* Name of table */ \
"seqno," \
"cid," \
"name" \
")"
#define SCHEMA5 \
"CREATE TABLE x(" \
"database," /* Name of database (i.e. main, temp etc.) */ \
"triggername," /* Name of trigger */ \
"dummy" /* Unused */ \
")"
typedef struct SchemaTable SchemaTable;
struct SchemaTable {
const char *zName;
const char *zObject;
const char *zPragma;
const char *zSchema;
} aSchemaTable[] = {
{ "table_info", "table", "PRAGMA %Q.table_info(%Q)", SCHEMA },
{ "foreign_key_list", "table", "PRAGMA %Q.foreign_key_list(%Q)", SCHEMA2 },
{ "index_list", "table", "PRAGMA %Q.index_list(%Q)", SCHEMA3 },
{ "index_info", "index", "PRAGMA %Q.index_info(%Q)", SCHEMA4 },
{ "trigger_list", "trigger", "SELECT 1", SCHEMA5 },
{ 0, 0, 0, 0 }
};
typedef struct schema_vtab schema_vtab;
typedef struct schema_cursor schema_cursor;
/* A schema table object */
struct schema_vtab {
sqlite3_vtab base;
sqlite3 *db;
SchemaTable *pType;
};
/* A schema table cursor object */
struct schema_cursor {
sqlite3_vtab_cursor base;
sqlite3_stmt *pDbList;
sqlite3_stmt *pTableList;
sqlite3_stmt *pColumnList;
int rowid;
};
/*
** Table destructor for the schema module.
*/
static int schemaDestroy(sqlite3_vtab *pVtab){
sqlite3_free(pVtab);
return 0;
}
/*
** Table constructor for the schema module.
*/
static int schemaCreate(
sqlite3 *db,
void *pAux,
int argc, const char *const*argv,
sqlite3_vtab **ppVtab,
char **pzErr
){
int rc = SQLITE_NOMEM;
schema_vtab *pVtab;
SchemaTable *pType = &aSchemaTable[0];
UNUSED_PARAMETER(pzErr);
if( argc>3 ){
int i;
pType = 0;
for(i=0; aSchemaTable[i].zName; i++){
if( 0==strcmp(argv[3], aSchemaTable[i].zName) ){
pType = &aSchemaTable[i];
}
}
if( !pType ){
return SQLITE_ERROR;
}
}
pVtab = sqlite3_malloc(sizeof(schema_vtab));
if( pVtab ){
memset(pVtab, 0, sizeof(schema_vtab));
pVtab->db = (sqlite3 *)pAux;
pVtab->pType = pType;
rc = sqlite3_declare_vtab(db, pType->zSchema);
}
*ppVtab = (sqlite3_vtab *)pVtab;
return rc;
}
/*
** Open a new cursor on the schema table.
*/
static int schemaOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
int rc = SQLITE_NOMEM;
schema_cursor *pCur;
UNUSED_PARAMETER(pVTab);
pCur = sqlite3_malloc(sizeof(schema_cursor));
if( pCur ){
memset(pCur, 0, sizeof(schema_cursor));
*ppCursor = (sqlite3_vtab_cursor *)pCur;
rc = SQLITE_OK;
}
return rc;
}
/*
** Close a schema table cursor.
*/
static int schemaClose(sqlite3_vtab_cursor *cur){
schema_cursor *pCur = (schema_cursor *)cur;
sqlite3_finalize(pCur->pDbList);
sqlite3_finalize(pCur->pTableList);
sqlite3_finalize(pCur->pColumnList);
sqlite3_free(pCur);
return SQLITE_OK;
}
static void columnToResult(sqlite3_context *ctx, sqlite3_stmt *pStmt, int iCol){
switch( sqlite3_column_type(pStmt, iCol) ){
case SQLITE_NULL:
sqlite3_result_null(ctx);
break;
case SQLITE_INTEGER:
sqlite3_result_int64(ctx, sqlite3_column_int64(pStmt, iCol));
break;
case SQLITE_FLOAT:
sqlite3_result_double(ctx, sqlite3_column_double(pStmt, iCol));
break;
case SQLITE_TEXT: {
const char *z = (const char *)sqlite3_column_text(pStmt, iCol);
sqlite3_result_text(ctx, z, -1, SQLITE_TRANSIENT);
break;
}
}
}
/*
** Retrieve a column of data.
*/
static int schemaColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
schema_cursor *pCur = (schema_cursor *)cur;
switch( i ){
case 0:
columnToResult(ctx, pCur->pDbList, 1);
break;
case 1:
columnToResult(ctx, pCur->pTableList, 0);
break;
default:
columnToResult(ctx, pCur->pColumnList, i-2);
break;
}
return SQLITE_OK;
}
/*
** Retrieve the current rowid.
*/
static int schemaRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
schema_cursor *pCur = (schema_cursor *)cur;
*pRowid = pCur->rowid;
return SQLITE_OK;
}
static int finalize(sqlite3_stmt **ppStmt){
int rc = sqlite3_finalize(*ppStmt);
*ppStmt = 0;
return rc;
}
static int schemaEof(sqlite3_vtab_cursor *cur){
schema_cursor *pCur = (schema_cursor *)cur;
return (pCur->pDbList ? 0 : 1);
}
/*
** Advance the cursor to the next row.
*/
static int schemaNext(sqlite3_vtab_cursor *cur){
int rc = SQLITE_OK;
schema_cursor *pCur = (schema_cursor *)cur;
schema_vtab *pVtab = (schema_vtab *)(cur->pVtab);
char *zSql = 0;
while( !pCur->pColumnList || SQLITE_ROW!=sqlite3_step(pCur->pColumnList) ){
if( SQLITE_OK!=(rc = finalize(&pCur->pColumnList)) ) goto next_exit;
while( !pCur->pTableList || SQLITE_ROW!=sqlite3_step(pCur->pTableList) ){
if( SQLITE_OK!=(rc = finalize(&pCur->pTableList)) ) goto next_exit;
assert(pCur->pDbList);
while( SQLITE_ROW!=sqlite3_step(pCur->pDbList) ){
rc = finalize(&pCur->pDbList);
goto next_exit;
}
/* Set zSql to the SQL to pull the list of tables from the
** sqlite_master (or sqlite_temp_master) table of the database
** identfied by the row pointed to by the SQL statement pCur->pDbList
** (iterating through a "PRAGMA database_list;" statement).
*/
if( sqlite3_column_int(pCur->pDbList, 0)==1 ){
zSql = sqlite3_mprintf(
"SELECT name FROM sqlite_temp_master WHERE type=%Q",
pVtab->pType->zObject
);
}else{
sqlite3_stmt *pDbList = pCur->pDbList;
zSql = sqlite3_mprintf(
"SELECT name FROM %Q.sqlite_master WHERE type=%Q",
sqlite3_column_text(pDbList, 1), pVtab->pType->zObject
);
}
if( !zSql ){
rc = SQLITE_NOMEM;
goto next_exit;
}
rc = sqlite3_prepare(pVtab->db, zSql, -1, &pCur->pTableList, 0);
sqlite3_free(zSql);
if( rc!=SQLITE_OK ) goto next_exit;
}
/* Set zSql to the SQL to the table_info pragma for the table currently
** identified by the rows pointed to by statements pCur->pDbList and
** pCur->pTableList.
*/
zSql = sqlite3_mprintf(pVtab->pType->zPragma,
sqlite3_column_text(pCur->pDbList, 1),
sqlite3_column_text(pCur->pTableList, 0)
);
if( !zSql ){
rc = SQLITE_NOMEM;
goto next_exit;
}
rc = sqlite3_prepare(pVtab->db, zSql, -1, &pCur->pColumnList, 0);
sqlite3_free(zSql);
if( rc!=SQLITE_OK ) goto next_exit;
}
pCur->rowid++;
next_exit:
/* TODO: Handle rc */
return rc;
}
/*
** Reset a schema table cursor.
*/
static int schemaFilter(
sqlite3_vtab_cursor *pVtabCursor,
int idxNum, const char *idxStr,
int argc, sqlite3_value **argv
){
int rc;
schema_vtab *pVtab = (schema_vtab *)(pVtabCursor->pVtab);
schema_cursor *pCur = (schema_cursor *)pVtabCursor;
UNUSED_PARAMETER(idxNum);
UNUSED_PARAMETER(idxStr);
UNUSED_PARAMETER(argc);
UNUSED_PARAMETER(argv);
pCur->rowid = 0;
finalize(&pCur->pTableList);
finalize(&pCur->pColumnList);
finalize(&pCur->pDbList);
rc = sqlite3_prepare(pVtab->db,"SELECT 0, 'main'", -1, &pCur->pDbList, 0);
return (rc==SQLITE_OK ? schemaNext(pVtabCursor) : rc);
}
/*
** Analyse the WHERE condition.
*/
static int schemaBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
UNUSED_PARAMETER(tab);
UNUSED_PARAMETER(pIdxInfo);
return SQLITE_OK;
}
/*
** A virtual table module that merely echos method calls into TCL
** variables.
*/
static sqlite3_module schemaModule = {
0, /* iVersion */
schemaCreate,
schemaCreate,
schemaBestIndex,
schemaDestroy,
schemaDestroy,
schemaOpen, /* xOpen - open a cursor */
schemaClose, /* xClose - close a cursor */
schemaFilter, /* xFilter - configure scan constraints */
schemaNext, /* xNext - advance a cursor */
schemaEof, /* xEof */
schemaColumn, /* xColumn - read data */
schemaRowid, /* xRowid - read data */
0, /* xUpdate */
0, /* xBegin */
0, /* xSync */
0, /* xCommit */
0, /* xRollback */
0, /* xFindMethod */
0, /* xRename */
};
/*
** Extension load function.
*/
static int installSchemaModule(sqlite3 *db, sqlite3 *sdb){
sqlite3_create_module(db, "schema", &schemaModule, (void *)sdb);
return 0;
}
/*
** sj(zValue, zJoin)
**
** The following block contains the implementation of an aggregate
** function that returns a string. Each time the function is stepped,
** it appends data to an internal buffer. When the aggregate is finalized,
** the contents of the buffer are returned.
**
** The first time the aggregate is stepped the buffer is set to a copy
** of the first argument. The second time and subsequent times it is
** stepped a copy of the second argument is appended to the buffer, then
** a copy of the first.
**
** Example:
**
** INSERT INTO t1(a) VALUES('1');
** INSERT INTO t1(a) VALUES('2');
** INSERT INTO t1(a) VALUES('3');
** SELECT sj(a, ', ') FROM t1;
**
** => "1, 2, 3"
**
*/
struct StrBuffer {
char *zBuf;
};
typedef struct StrBuffer StrBuffer;
static void joinFinalize(sqlite3_context *context){
StrBuffer *p;
p = (StrBuffer *)sqlite3_aggregate_context(context, sizeof(StrBuffer));
sqlite3_result_text(context, p->zBuf, -1, SQLITE_TRANSIENT);
sqlite3_free(p->zBuf);
}
static void joinStep(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
StrBuffer *p;
UNUSED_PARAMETER(argc);
p = (StrBuffer *)sqlite3_aggregate_context(context, sizeof(StrBuffer));
if( p->zBuf==0 ){
p->zBuf = sqlite3_mprintf("%s", sqlite3_value_text(argv[0]));
}else{
char *zTmp = p->zBuf;
p->zBuf = sqlite3_mprintf("%s%s%s",
zTmp, sqlite3_value_text(argv[1]), sqlite3_value_text(argv[0])
);
sqlite3_free(zTmp);
}
}
/*
** dq(zString)
**
** This scalar function accepts a single argument and interprets it as
** a text value. The return value is the argument enclosed in double
** quotes. If any double quote characters are present in the argument,
** these are escaped.
**
** dq('the raven "Nevermore."') == '"the raven ""Nevermore."""'
*/
static void doublequote(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
int ii;
char *zOut;
char *zCsr;
const char *zIn = (const char *)sqlite3_value_text(argv[0]);
int nIn = sqlite3_value_bytes(argv[0]);
UNUSED_PARAMETER(argc);
zOut = sqlite3_malloc(nIn*2+3);
zCsr = zOut;
*zCsr++ = '"';
for(ii=0; ii<nIn; ii++){
*zCsr++ = zIn[ii];
if( zIn[ii]=='"' ){
*zCsr++ = '"';
}
}
*zCsr++ = '"';
*zCsr++ = '\0';
sqlite3_result_text(context, zOut, -1, SQLITE_TRANSIENT);
sqlite3_free(zOut);
}
/*
** multireplace(zString, zSearch1, zReplace1, ...)
*/
static void multireplace(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
int i = 0;
char *zOut = 0;
int nOut = 0;
int nMalloc = 0;
const char *zIn = (const char *)sqlite3_value_text(argv[0]);
int nIn = sqlite3_value_bytes(argv[0]);
while( i<nIn ){
const char *zCopy = &zIn[i];
int nCopy = 1;
int nReplace = 1;
int j;
for(j=1; j<(argc-1); j+=2){
const char *z = (const char *)sqlite3_value_text(argv[j]);
int n = sqlite3_value_bytes(argv[j]);
if( n<=(nIn-i) && 0==strncmp(z, zCopy, n) ){
zCopy = (const char *)sqlite3_value_text(argv[j+1]);
nCopy = sqlite3_value_bytes(argv[j+1]);
nReplace = n;
break;
}
}
if( (nOut+nCopy)>nMalloc ){
nMalloc = 16 + (nOut+nCopy)*2;
zOut = (char *)sqlite3_realloc(zOut, nMalloc);
}
assert( nMalloc>=(nOut+nCopy) );
memcpy(&zOut[nOut], zCopy, nCopy);
i += nReplace;
nOut += nCopy;
}
sqlite3_result_text(context, zOut, nOut, SQLITE_TRANSIENT);
sqlite3_free(zOut);
}
/*
** A callback for sqlite3_exec() invokes the callback specified by the
** GenfkeyCb structure pointed to by the void* passed as the first argument.
*/
static int invokeCallback(void *p, int nArg, char **azArg, char **azCol){
GenfkeyCb *pCb = (GenfkeyCb *)p;
UNUSED_PARAMETER(nArg);
UNUSED_PARAMETER(azCol);
return pCb->xData(pCb->pCtx, pCb->eType, azArg[0]);
}
int detectSchemaProblem(
sqlite3 *db, /* Database connection */
const char *zMessage, /* English language error message */
const char *zSql, /* SQL statement to run */
GenfkeyCb *pCb
){
sqlite3_stmt *pStmt;
int rc;
rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
if( rc!=SQLITE_OK ){
return rc;
}
while( SQLITE_ROW==sqlite3_step(pStmt) ){
char *zDel;
int iFk = sqlite3_column_int(pStmt, 0);
const char *zTab = (const char *)sqlite3_column_text(pStmt, 1);
zDel = sqlite3_mprintf("Error in table %s: %s", zTab, zMessage);
rc = pCb->xData(pCb->pCtx, pCb->eType, zDel);
sqlite3_free(zDel);
if( rc!=SQLITE_OK ) return rc;
zDel = sqlite3_mprintf(
"DELETE FROM temp.fkey WHERE from_tbl = %Q AND fkid = %d"
, zTab, iFk
);
sqlite3_exec(db, zDel, 0, 0, 0);
sqlite3_free(zDel);
}
sqlite3_finalize(pStmt);
return SQLITE_OK;
}
/*
** Create and populate temporary table "fkey".
*/
static int populateTempTable(sqlite3 *db, GenfkeyCb *pCallback){
int rc;
rc = sqlite3_exec(db,
"CREATE VIRTUAL TABLE temp.v_fkey USING schema(foreign_key_list);"
"CREATE VIRTUAL TABLE temp.v_col USING schema(table_info);"
"CREATE VIRTUAL TABLE temp.v_idxlist USING schema(index_list);"
"CREATE VIRTUAL TABLE temp.v_idxinfo USING schema(index_info);"
"CREATE VIRTUAL TABLE temp.v_triggers USING schema(trigger_list);"
"CREATE TABLE temp.fkey AS "
"SELECT from_tbl, to_tbl, fkid, from_col, to_col, on_update, on_delete "
"FROM temp.v_fkey WHERE database = 'main';"
, 0, 0, 0
);
if( rc!=SQLITE_OK ) return rc;
rc = detectSchemaProblem(db, "foreign key columns do not exist",
"SELECT fkid, from_tbl "
"FROM temp.fkey "
"WHERE to_col IS NOT NULL AND NOT EXISTS (SELECT 1 "
"FROM temp.v_col WHERE tablename=to_tbl AND name==to_col"
")", pCallback
);
if( rc!=SQLITE_OK ) return rc;
/* At this point the temp.fkey table is mostly populated. If any foreign
** keys were specified so that they implicitly refer to they primary
** key of the parent table, the "to_col" values of the temp.fkey rows
** are still set to NULL.
**
** This is easily fixed for single column primary keys, but not for
** composites. With a composite primary key, there is no way to reliably
** query sqlite for the order in which the columns that make up the
** composite key were declared i.e. there is no way to tell if the
** schema actually contains "PRIMARY KEY(a, b)" or "PRIMARY KEY(b, a)".
** Therefore, this case is not handled. The following function call
** detects instances of this case.
*/
rc = detectSchemaProblem(db, "implicit mapping to composite primary key",
"SELECT fkid, from_tbl "
"FROM temp.fkey "
"WHERE to_col IS NULL "
"GROUP BY fkid, from_tbl HAVING count(*) > 1", pCallback
);
if( rc!=SQLITE_OK ) return rc;
/* Detect attempts to implicitly map to the primary key of a table
** that has no primary key column.
*/
rc = detectSchemaProblem(db, "implicit mapping to non-existant primary key",
"SELECT fkid, from_tbl "
"FROM temp.fkey "
"WHERE to_col IS NULL AND NOT EXISTS "
"(SELECT 1 FROM temp.v_col WHERE pk AND tablename = temp.fkey.to_tbl)"
, pCallback
);
if( rc!=SQLITE_OK ) return rc;
/* Fix all the implicit primary key mappings in the temp.fkey table. */
rc = sqlite3_exec(db,
"UPDATE temp.fkey SET to_col = "
"(SELECT name FROM temp.v_col WHERE pk AND tablename=temp.fkey.to_tbl)"
" WHERE to_col IS NULL;"
, 0, 0, 0
);
if( rc!=SQLITE_OK ) return rc;
/* Now check that all all parent keys are either primary keys or
** subject to a unique constraint.
*/
rc = sqlite3_exec(db,
"CREATE TABLE temp.idx2 AS SELECT "
"il.tablename AS tablename,"
"ii.indexname AS indexname,"
"ii.name AS col "
"FROM temp.v_idxlist AS il, temp.v_idxinfo AS ii "
"WHERE il.isunique AND il.database='main' AND ii.indexname = il.name;"
"INSERT INTO temp.idx2 "
"SELECT tablename, 'pk', name FROM temp.v_col WHERE pk;"
"CREATE TABLE temp.idx AS SELECT "
"tablename, indexname, sj(dq(col),',') AS cols "
"FROM (SELECT * FROM temp.idx2 ORDER BY col) "
"GROUP BY tablename, indexname;"
"CREATE TABLE temp.fkey2 AS SELECT "
"fkid, from_tbl, to_tbl, sj(dq(to_col),',') AS cols "
"FROM (SELECT * FROM temp.fkey ORDER BY to_col) "
"GROUP BY fkid, from_tbl;"
"CREATE TABLE temp.triggers AS SELECT "
"triggername FROM temp.v_triggers WHERE database='main' AND "
"triggername LIKE 'genfkey%';"
, 0, 0, 0
);
if( rc!=SQLITE_OK ) return rc;
rc = detectSchemaProblem(db, "foreign key is not unique",
"SELECT fkid, from_tbl "
"FROM temp.fkey2 "
"WHERE NOT EXISTS (SELECT 1 "
"FROM temp.idx WHERE tablename=to_tbl AND fkey2.cols==idx.cols"
")", pCallback
);
if( rc!=SQLITE_OK ) return rc;
return rc;
}
#define GENFKEY_ERROR 1
#define GENFKEY_DROPTRIGGER 2
#define GENFKEY_CREATETRIGGER 3
static int genfkey_create_triggers(
sqlite3 *sdb, /* Connection to read schema from */
const char *zDb, /* Name of db to read ("main", "temp") */
void *pCtx, /* Context pointer to pass to xData */
int (*xData)(void *, int, const char *)
){
const char *zSql =
"SELECT multireplace('"
"-- Triggers for foreign key mapping:\n"
"--\n"
"-- /from_readable/ REFERENCES /to_readable/\n"
"-- on delete /on_delete/\n"
"-- on update /on_update/\n"
"--\n"
/* The "BEFORE INSERT ON <referencing>" trigger. This trigger's job is to
** throw an exception if the user tries to insert a row into the
** referencing table for which there is no corresponding row in
** the referenced table.
*/
"CREATE TRIGGER /name/_insert_referencing BEFORE INSERT ON /tbl/ WHEN \n"
" /key_notnull/ AND NOT EXISTS (SELECT 1 FROM /ref/ WHERE /cond1/)\n"
"BEGIN\n"
" SELECT RAISE(ABORT, ''constraint failed'');\n"
"END;\n"
/* The "BEFORE UPDATE ON <referencing>" trigger. This trigger's job
** is to throw an exception if the user tries to update a row in the
** referencing table causing it to correspond to no row in the
** referenced table.
*/
"CREATE TRIGGER /name/_update_referencing BEFORE\n"
" UPDATE OF /rkey_list/ ON /tbl/ WHEN \n"
" /key_notnull/ AND \n"
" NOT EXISTS (SELECT 1 FROM /ref/ WHERE /cond1/)\n"
"BEGIN\n"
" SELECT RAISE(ABORT, ''constraint failed'');\n"
"END;\n"
/* The "BEFORE DELETE ON <referenced>" trigger. This trigger's job
** is to detect when a row is deleted from the referenced table to
** which rows in the referencing table correspond. The action taken
** depends on the value of the 'ON DELETE' clause.
*/
"CREATE TRIGGER /name/_delete_referenced BEFORE DELETE ON /ref/ WHEN\n"
" EXISTS (SELECT 1 FROM /tbl/ WHERE /cond2/)\n"
"BEGIN\n"
" /delete_action/\n"
"END;\n"
/* The "BEFORE DELETE ON <referenced>" trigger. This trigger's job
** is to detect when the key columns of a row in the referenced table
** to which one or more rows in the referencing table correspond are
** updated. The action taken depends on the value of the 'ON UPDATE'
** clause.
*/
"CREATE TRIGGER /name/_update_referenced AFTER\n"
" UPDATE OF /fkey_list/ ON /ref/ WHEN \n"
" EXISTS (SELECT 1 FROM /tbl/ WHERE /cond2/)\n"
"BEGIN\n"
" /update_action/\n"
"END;\n"
"'"
/* These are used in the SQL comment written above each set of triggers */
", '/from_readable/', from_tbl || '(' || sj(from_col, ', ') || ')'"
", '/to_readable/', to_tbl || '(' || sj(to_col, ', ') || ')'"
", '/on_delete/', on_delete"
", '/on_update/', on_update"
", '/name/', 'genfkey' || min(rowid)"
", '/tbl/', dq(from_tbl)"
", '/ref/', dq(to_tbl)"
", '/key_notnull/', sj('new.' || dq(from_col) || ' IS NOT NULL', ' AND ')"
", '/fkey_list/', sj(to_col, ', ')"
", '/rkey_list/', sj(from_col, ', ')"
", '/cond1/', sj(multireplace('new./from/ == /to/'"
", '/from/', dq(from_col)"
", '/to/', dq(to_col)"
"), ' AND ')"
", '/cond2/', sj(multireplace('old./to/ == /from/'"
", '/from/', dq(from_col)"
", '/to/', dq(to_col)"
"), ' AND ')"
", '/update_action/', CASE on_update "
"WHEN 'SET NULL' THEN "
"multireplace('UPDATE /tbl/ SET /setlist/ WHERE /where/;' "
", '/setlist/', sj(from_col||' = NULL',', ')"
", '/tbl/', dq(from_tbl)"
", '/where/', sj(from_col||' = old.'||dq(to_col),' AND ')"
")"
"WHEN 'CASCADE' THEN "
"multireplace('UPDATE /tbl/ SET /setlist/ WHERE /where/;' "
", '/setlist/', sj(dq(from_col)||' = new.'||dq(to_col),', ')"
", '/tbl/', dq(from_tbl)"
", '/where/', sj(dq(from_col)||' = old.'||dq(to_col),' AND ')"
")"
"ELSE "
" 'SELECT RAISE(ABORT, ''constraint failed'');'"
"END "
", '/delete_action/', CASE on_delete "
"WHEN 'SET NULL' THEN "
"multireplace('UPDATE /tbl/ SET /setlist/ WHERE /where/;' "
", '/setlist/', sj(from_col||' = NULL',', ')"
", '/tbl/', dq(from_tbl)"
", '/where/', sj(from_col||' = old.'||dq(to_col),' AND ')"
")"
"WHEN 'CASCADE' THEN "
"multireplace('DELETE FROM /tbl/ WHERE /where/;' "
", '/tbl/', dq(from_tbl)"
", '/where/', sj(dq(from_col)||' = old.'||dq(to_col),' AND ')"
")"
"ELSE "
" 'SELECT RAISE(ABORT, ''constraint failed'');'"
"END "
") FROM temp.fkey "
"GROUP BY from_tbl, fkid"
;
int rc;
const int enc = SQLITE_UTF8;
sqlite3 *db = 0;
GenfkeyCb cb;
cb.xData = xData;
cb.pCtx = pCtx;
UNUSED_PARAMETER(zDb);
/* Open the working database handle. */
rc = sqlite3_open(":memory:", &db);
if( rc!=SQLITE_OK ) goto genfkey_exit;
/* Create the special scalar and aggregate functions used by this program. */
sqlite3_create_function(db, "dq", 1, enc, 0, doublequote, 0, 0);
sqlite3_create_function(db, "multireplace", -1, enc, db, multireplace, 0, 0);
sqlite3_create_function(db, "sj", 2, enc, 0, 0, joinStep, joinFinalize);
/* Install the "schema" virtual table module */
installSchemaModule(db, sdb);
/* Create and populate a temp table with the information required to
** build the foreign key triggers. See function populateTempTable()
** for details.
*/
cb.eType = GENFKEY_ERROR;
rc = populateTempTable(db, &cb);
if( rc!=SQLITE_OK ) goto genfkey_exit;
/* Unless the --no-drop option was specified, generate DROP TRIGGER
** statements to drop any triggers in the database generated by a
** previous run of this program.
*/
cb.eType = GENFKEY_DROPTRIGGER;
rc = sqlite3_exec(db,
"SELECT 'DROP TRIGGER main.' || dq(triggername) || ';' FROM triggers"
,invokeCallback, (void *)&cb, 0
);
if( rc!=SQLITE_OK ) goto genfkey_exit;
/* Run the main query to create the trigger definitions. */
cb.eType = GENFKEY_CREATETRIGGER;
rc = sqlite3_exec(db, zSql, invokeCallback, (void *)&cb, 0);
if( rc!=SQLITE_OK ) goto genfkey_exit;
genfkey_exit:
sqlite3_close(db);
return rc;
}
#endif
/* End genfkey logic. */
/*************************************************************************/
/*************************************************************************/
/*
** If the following flag is set, then command execution stops
** at an error if we are not interactive.
@ -926,6 +1781,62 @@ static int run_schema_dump_query(
return rc;
}
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_SUBQUERY)
struct GenfkeyCmd {
sqlite3 *db; /* Database handle */
struct callback_data *pCb; /* Callback data */
int isIgnoreErrors; /* True for --ignore-errors */
int isExec; /* True for --exec */
int isNoDrop; /* True for --no-drop */
int nErr; /* Number of errors seen so far */
};
typedef struct GenfkeyCmd GenfkeyCmd;
static int genfkeyParseArgs(GenfkeyCmd *p, char **azArg, int nArg){
int ii;
memset(p, 0, sizeof(GenfkeyCmd));
for(ii=0; ii<nArg; ii++){
int n = strlen30(azArg[ii]);
if( n>2 && n<10 && 0==strncmp(azArg[ii], "--no-drop", n) ){
p->isNoDrop = 1;
}else if( n>2 && n<16 && 0==strncmp(azArg[ii], "--ignore-errors", n) ){
p->isIgnoreErrors = 1;
}else if( n>2 && n<7 && 0==strncmp(azArg[ii], "--exec", n) ){
p->isExec = 1;
}else{
fprintf(stderr, "unknown option: %s\n", azArg[ii]);
return -1;
}
}
return SQLITE_OK;
}
static int genfkeyCmdCb(void *pCtx, int eType, const char *z){
GenfkeyCmd *p = (GenfkeyCmd *)pCtx;
if( eType==GENFKEY_ERROR && !p->isIgnoreErrors ){
p->nErr++;
fprintf(stderr, "%s\n", z);
}
if( p->nErr==0 && (
(eType==GENFKEY_CREATETRIGGER)
|| (eType==GENFKEY_DROPTRIGGER && !p->isNoDrop)
)){
if( p->isExec ){
sqlite3_exec(p->db, z, 0, 0, 0);
}else{
char *zCol = "sql";
callback((void *)p->pCb, 1, (char **)&z, (char **)&zCol);
}
}
return SQLITE_OK;
}
#endif
/*
** Text of a help message
*/
@ -937,6 +1848,14 @@ static char zHelp[] =
".echo ON|OFF Turn command echo on or off\n"
".exit Exit this program\n"
".explain ON|OFF Turn output mode suitable for EXPLAIN on or off.\n"
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_SUBQUERY)
".genfkey ?OPTIONS? Options are:\n"
" --no-drop: Do not drop old fkey triggers.\n"
" --ignore-errors: Ignore tables with fkey errors\n"
" --exec: Execute generated SQL immediately\n"
" See file tool/genfkey.README in the source \n"
" distribution for further information.\n"
#endif
".header(s) ON|OFF Turn display of headers on or off\n"
".help Show this message\n"
".import FILE TABLE Import data from FILE into TABLE\n"
@ -1240,6 +2159,17 @@ static int do_meta_command(char *zLine, struct callback_data *p){
}
}else
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_SUBQUERY)
if( c=='g' && strncmp(azArg[0], "genfkey", n)==0 ){
GenfkeyCmd cmd;
if( 0==genfkeyParseArgs(&cmd, &azArg[1], nArg-1) ){
cmd.db = p->db;
cmd.pCb = p;
genfkey_create_triggers(p->db, "main", (void *)&cmd, genfkeyCmdCb);
}
}else
#endif
if( c=='h' && (strncmp(azArg[0], "header", n)==0 ||
strncmp(azArg[0], "headers", n)==0 )&& nArg>1 ){
p->showHeader = booleanValue(azArg[1]);

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.833 2009/02/05 16:53:43 drh Exp $
** @(#) $Id: sqliteInt.h,v 1.854 2009/04/08 13:51:51 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
@ -444,6 +444,22 @@ extern const int sqlite3one;
#define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32))
#define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
/*
** Round up a number to the next larger multiple of 8. This is used
** to force 8-byte alignment on 64-bit architectures.
*/
#define ROUND8(x) (((x)+7)&~7)
/*
** Round down to the nearest multiple of 8
*/
#define ROUNDDOWN8(x) ((x)&~7)
/*
** Assert that the pointer X is aligned to an 8-byte boundary.
*/
#define EIGHT_BYTE_ALIGNMENT(X) ((((char*)(X) - (char*)0)&7)==0)
/*
** An instance of the following structure is used to store the busy-handler
** callback for a given sqlite handle.
@ -675,10 +691,17 @@ struct Schema {
** lookaside malloc subsystem. Each available memory allocation in
** the lookaside subsystem is stored on a linked list of LookasideSlot
** objects.
**
** Lookaside allocations are only allowed for objects that are associated
** with a particular database connection. Hence, schema information cannot
** be stored in lookaside because in shared cache mode the schema information
** is shared by multiple database connections. Therefore, while parsing
** schema information, the Lookaside.bEnabled flag is cleared so that
** lookaside allocations are not used to construct the schema objects.
*/
struct Lookaside {
u16 sz; /* Size of each buffer in bytes */
u8 bEnabled; /* True if use lookaside. False to ignore it */
u8 bEnabled; /* False to disable new lookaside allocations */
u8 bMalloced; /* True if pStart obtained from sqlite3_malloc() */
int nOut; /* Number of buffers currently checked out */
int mxOut; /* Highwater mark for nOut */
@ -807,7 +830,26 @@ struct sqlite3 {
#endif
Savepoint *pSavepoint; /* List of active savepoints */
int nSavepoint; /* Number of non-transaction savepoints */
int nStatement; /* Number of nested statement-transactions */
u8 isTransactionSavepoint; /* True if the outermost savepoint is a TS */
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
/* The following variables are all protected by the STATIC_MASTER
** mutex, not by sqlite3.mutex. They are used by code in notify.c.
**
** When X.pUnlockConnection==Y, that means that X is waiting for Y to
** unlock so that it can proceed.
**
** When X.pBlockingConnection==Y, that means that something that X tried
** tried to do recently failed with an SQLITE_LOCKED error due to locks
** held by Y.
*/
sqlite3 *pBlockingConnection; /* Connection that caused SQLITE_LOCKED */
sqlite3 *pUnlockConnection; /* Connection to watch for unlock */
void *pUnlockArg; /* Argument to xUnlockNotify */
void (*xUnlockNotify)(void **, int); /* Unlock notify callback */
sqlite3 *pNextBlocked; /* Next in list of all blocked connections */
#endif
};
/*
@ -845,8 +887,8 @@ struct sqlite3 {
#define SQLITE_RecoveryMode 0x00040000 /* Ignore schema errors */
#define SQLITE_SharedCache 0x00080000 /* Cache sharing is enabled */
#define SQLITE_Vtab 0x00100000 /* There exists a virtual table */
#define SQLITE_CommitBusy 0x00200000 /* In the process of committing */
#define SQLITE_ReverseOrder 0x00400000 /* Reverse unordered SELECTs */
/*
** Possible values for the sqlite.magic field.
@ -886,6 +928,7 @@ struct FuncDef {
#define SQLITE_FUNC_EPHEM 0x04 /* Ephemeral. Delete with VDBE */
#define SQLITE_FUNC_NEEDCOLL 0x08 /* sqlite3GetFuncCollSeq() might be called */
#define SQLITE_FUNC_PRIVATE 0x10 /* Allowed for internal use only */
#define SQLITE_FUNC_COUNT 0x20 /* Built-in count(*) aggregate */
/*
** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
@ -1080,7 +1123,7 @@ struct CollSeq {
** of a SELECT statement.
*/
struct Table {
sqlite3 *db; /* Associated database connection. Might be NULL. */
sqlite3 *dbMem; /* DB connection used for lookaside allocations. */
char *zName; /* Name of the table or view */
int iPKey; /* If not negative, use aCol[iPKey] as the primary key */
int nCol; /* Number of columns in this table */
@ -1091,7 +1134,6 @@ struct Table {
u16 nRef; /* Number of pointers to this Table */
u8 tabFlags; /* Mask of TF_* values */
u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */
Trigger *pTrigger; /* List of SQL triggers on this table */
FKey *pFKey; /* Linked list of all foreign keys in this table */
char *zColAff; /* String defining the affinity of each column */
#ifndef SQLITE_OMIT_CHECK
@ -1106,6 +1148,7 @@ struct Table {
int nModuleArg; /* Number of arguments to the module */
char **azModuleArg; /* Text of all module args. [0] is module name */
#endif
Trigger *pTrigger; /* List of triggers stored in pSchema */
Schema *pSchema; /* Schema that contains this table */
Table *pNextZombie; /* Next on the Parse.pZombieTab list */
};
@ -1363,19 +1406,27 @@ struct AggInfo {
** Each node of an expression in the parse tree is an instance
** of this structure.
**
** Expr.op is the opcode. The integer parser token codes are reused
** as opcodes here. For example, the parser defines TK_GE to be an integer
** code representing the ">=" operator. This same integer code is reused
** Expr.op is the opcode. The integer parser token codes are reused
** as opcodes here. For example, the parser defines TK_GE to be an integer
** code representing the ">=" operator. This same integer code is reused
** to represent the greater-than-or-equal-to operator in the expression
** tree.
**
** Expr.pRight and Expr.pLeft are subexpressions. Expr.pList is a list
** of argument if the expression is a function.
** If the expression is an SQL literal (TK_INTEGER, TK_FLOAT, TK_BLOB,
** or TK_STRING), then Expr.token contains the text of the SQL literal. If
** the expression is a variable (TK_VARIABLE), then Expr.token contains the
** variable name. Finally, if the expression is an SQL function (TK_FUNCTION),
** then Expr.token contains the name of the function.
**
** Expr.token is the operator token for this node. For some expressions
** that have subexpressions, Expr.token can be the complete text that gave
** rise to the Expr. In the latter case, the token is marked as being
** a compound token.
** Expr.pRight and Expr.pLeft are the left and right subexpressions of a
** binary operator. Either or both may be NULL.
**
** Expr.x.pList is a list of arguments if the expression is an SQL function,
** a CASE expression or an IN expression of the form "<lhs> IN (<y>, <z>...)".
** Expr.x.pSelect is used if the expression is a sub-select or an expression of
** the form "<lhs> IN (SELECT ...)". If the EP_xIsSelect bit is set in the
** Expr.flags mask, then Expr.x.pSelect is valid. Otherwise, Expr.x.pList is
** valid.
**
** An expression of the form ID or ID.ID refers to a column in a table.
** For such expressions, Expr.op is set to TK_COLUMN and Expr.iTable is
@ -1385,10 +1436,9 @@ struct AggInfo {
** value is also stored in the Expr.iAgg column in the aggregate so that
** it can be accessed after all aggregates are computed.
**
** If the expression is a function, the Expr.iTable is an integer code
** representing which function. If the expression is an unbound variable
** marker (a question mark character '?' in the original SQL) then the
** Expr.iTable holds the index number for that variable.
** If the expression is an unbound variable marker (a question mark
** character '?' in the original SQL) then the Expr.iTable holds the index
** number for that variable.
**
** If the expression is a subquery then Expr.iColumn holds an integer
** register number containing the result of the subquery. If the
@ -1396,32 +1446,62 @@ struct AggInfo {
** gives a different answer at different times during statement processing
** then iTable is the address of a subroutine that computes the subquery.
**
** The Expr.pSelect field points to a SELECT statement. The SELECT might
** be the right operand of an IN operator. Or, if a scalar SELECT appears
** in an expression the opcode is TK_SELECT and Expr.pSelect is the only
** operand.
**
** If the Expr is of type OP_Column, and the table it is selecting from
** is a disk table or the "old.*" pseudo-table, then pTab points to the
** corresponding table definition.
**
** ALLOCATION NOTES:
**
** Expr objects can use a lot of memory space in database schema. To
** help reduce memory requirements, sometimes an Expr object will be
** truncated. And to reduce the number of memory allocations, sometimes
** two or more Expr objects will be stored in a single memory allocation,
** together with Expr.token and/or Expr.span strings.
**
** If the EP_Reduced, EP_SpanToken, and EP_TokenOnly flags are set when
** an Expr object is truncated. When EP_Reduced is set, then all
** the child Expr objects in the Expr.pLeft and Expr.pRight subtrees
** are contained within the same memory allocation. Note, however, that
** the subtrees in Expr.x.pList or Expr.x.pSelect are always separately
** allocated, regardless of whether or not EP_Reduced is set.
*/
struct Expr {
u8 op; /* Operation performed by this node */
char affinity; /* The affinity of the column or 0 if not a column */
u16 flags; /* Various flags. See below */
CollSeq *pColl; /* The collation type of the column or 0 */
Expr *pLeft, *pRight; /* Left and right subnodes */
ExprList *pList; /* A list of expressions used as function arguments
** or in "<expr> IN (<expr-list)" */
VVA_ONLY(u8 vvaFlags;) /* Flags used for VV&A only. EVVA_* below. */
u16 flags; /* Various flags. EP_* See below */
Token token; /* An operand token */
/* If the EP_TokenOnly flag is set in the Expr.flags mask, then no
** space is allocated for the fields below this point. An attempt to
** access them will result in a segfault or malfunction.
*********************************************************************/
Token span; /* Complete text of the expression */
/* If the EP_SpanToken flag is set in the Expr.flags mask, then no
** space is allocated for the fields below this point. An attempt to
** access them will result in a segfault or malfunction.
*********************************************************************/
Expr *pLeft; /* Left subnode */
Expr *pRight; /* Right subnode */
union {
ExprList *pList; /* Function arguments or in "<expr> IN (<expr-list)" */
Select *pSelect; /* Used for sub-selects and "<expr> IN (<select>)" */
} x;
CollSeq *pColl; /* The collation type of the column or 0 */
/* If the EP_Reduced flag is set in the Expr.flags mask, then no
** space is allocated for the fields below this point. An attempt to
** access them will result in a segfault or malfunction.
*********************************************************************/
int iTable, iColumn; /* When op==TK_COLUMN, then this expr node means the
** iColumn-th field of the iTable-th table. */
AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
int iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
int iRightJoinTable; /* If EP_FromJoin, the right table of the join */
Select *pSelect; /* When the expression is a sub-select. Also the
** right side of "<expr> IN (<select>)" */
Table *pTab; /* Table for TK_COLUMN expressions. */
#if SQLITE_MAX_EXPR_DEPTH>0
int nHeight; /* Height of the tree headed by this node */
@ -1443,6 +1523,21 @@ struct Expr {
#define EP_AnyAff 0x0200 /* Can take a cached column of any affinity */
#define EP_FixedDest 0x0400 /* Result needed in a specific register */
#define EP_IntValue 0x0800 /* Integer value contained in iTable */
#define EP_xIsSelect 0x1000 /* x.pSelect is valid (otherwise x.pList is) */
#define EP_Reduced 0x2000 /* Expr struct is EXPR_REDUCEDSIZE bytes only */
#define EP_TokenOnly 0x4000 /* Expr struct is EXPR_TOKENONLYSIZE bytes only */
#define EP_SpanToken 0x8000 /* Expr size is EXPR_SPANTOKENSIZE bytes */
/*
** The following are the meanings of bits in the Expr.vvaFlags field.
** This information is only used when SQLite is compiled with
** SQLITE_DEBUG defined.
*/
#ifndef NDEBUG
#define EVVA_ReadOnlyToken 0x01 /* Expr.token.z is read-only */
#endif
/*
** These macros can be used to test, set, or clear bits in the
** Expr.flags field.
@ -1452,6 +1547,23 @@ struct Expr {
#define ExprSetProperty(E,P) (E)->flags|=(P)
#define ExprClearProperty(E,P) (E)->flags&=~(P)
/*
** Macros to determine the number of bytes required by a normal Expr
** struct, an Expr struct with the EP_Reduced flag set in Expr.flags
** and an Expr struct with the EP_TokenOnly flag set.
*/
#define EXPR_FULLSIZE sizeof(Expr) /* Full size */
#define EXPR_REDUCEDSIZE offsetof(Expr,iTable) /* Common features */
#define EXPR_SPANTOKENSIZE offsetof(Expr,pLeft) /* Fewer features */
#define EXPR_TOKENONLYSIZE offsetof(Expr,span) /* Smallest possible */
/*
** Flags passed to the sqlite3ExprDup() function. See the header comment
** above sqlite3ExprDup() for details.
*/
#define EXPRDUP_REDUCE 0x0001 /* Used reduced-size Expr nodes */
#define EXPRDUP_SPAN 0x0002 /* Make a copy of Expr.span */
/*
** A list of expressions. Each expression may optionally have a
** name. An expr/name combination can be used in several ways, such
@ -2237,7 +2349,7 @@ void sqlite3SetString(char **, sqlite3*, const char*, ...);
void sqlite3ErrorMsg(Parse*, const char*, ...);
void sqlite3ErrorClear(Parse*);
void sqlite3Dequote(char*);
void sqlite3DequoteExpr(sqlite3*, Expr*);
void sqlite3DequoteExpr(Expr*);
int sqlite3KeywordCode(const unsigned char*, int);
int sqlite3RunParser(Parse*, const char*, char **);
void sqlite3FinishCoding(Parse*);
@ -2379,12 +2491,12 @@ void sqlite3GenerateConstraintChecks(Parse*,Table*,int,int,
void sqlite3CompleteInsertion(Parse*, Table*, int, int, int*, int, int, int);
int sqlite3OpenTableAndIndices(Parse*, Table*, int, int);
void sqlite3BeginWriteOperation(Parse*, int, int);
Expr *sqlite3ExprDup(sqlite3*,Expr*);
void sqlite3TokenCopy(sqlite3*,Token*, Token*);
ExprList *sqlite3ExprListDup(sqlite3*,ExprList*);
SrcList *sqlite3SrcListDup(sqlite3*,SrcList*);
Expr *sqlite3ExprDup(sqlite3*,Expr*,int);
void sqlite3TokenCopy(sqlite3*,Token*,const Token*);
ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int);
SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int);
IdList *sqlite3IdListDup(sqlite3*,IdList*);
Select *sqlite3SelectDup(sqlite3*,Select*);
Select *sqlite3SelectDup(sqlite3*,Select*,int);
void sqlite3FuncDefInsert(FuncDefHash*, FuncDef*);
FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,int,u8,int);
void sqlite3RegisterBuiltinFunctions(sqlite3*);
@ -2411,9 +2523,10 @@ void sqlite3MaterializeView(Parse*, Table*, Expr*, int);
void sqlite3FinishTrigger(Parse*, TriggerStep*, Token*);
void sqlite3DropTrigger(Parse*, SrcList*, int);
void sqlite3DropTriggerPtr(Parse*, Trigger*);
int sqlite3TriggersExist(Table*, int, ExprList*);
int sqlite3CodeRowTrigger(Parse*, int, ExprList*, int, Table *, int, int,
int, int, u32*, u32*);
Trigger *sqlite3TriggersExist(Parse *, Table*, int, ExprList*, int *pMask);
Trigger *sqlite3TriggerList(Parse *, Table *);
int sqlite3CodeRowTrigger(Parse*, Trigger *, int, ExprList*, int, Table *,
int, int, int, int, u32*, u32*);
void sqliteViewTriggers(Parse*, Table*, Expr*, int, ExprList*);
void sqlite3DeleteTriggerStep(sqlite3*, TriggerStep*);
TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*);
@ -2428,7 +2541,8 @@ void sqlite3MaterializeView(Parse*, Table*, Expr*, int);
# define sqlite3DeleteTrigger(A,B)
# define sqlite3DropTriggerPtr(A,B)
# define sqlite3UnlinkAndDeleteTrigger(A,B,C)
# define sqlite3CodeRowTrigger(A,B,C,D,E,F,G,H,I,J,K) 0
# define sqlite3CodeRowTrigger(A,B,C,D,E,F,G,H,I,J,K,L) 0
# define sqlite3TriggerList(X, Y) 0
#endif
int sqlite3JoinType(Parse*, Token*, Token*, Token*);
@ -2460,7 +2574,7 @@ int sqlite3GetInt32(const char *, int*);
int sqlite3FitsIn64Bits(const char *, int);
int sqlite3Utf16ByteLen(const void *pData, int nChar);
int sqlite3Utf8CharLen(const char *pData, int nByte);
int sqlite3Utf8Read(const u8*, const u8*, const u8**);
int sqlite3Utf8Read(const u8*, const u8**);
/*
** Routines to read and write variable-length integers. These used to
@ -2686,6 +2800,17 @@ int sqlite3IsMemJournal(sqlite3_file *);
u32 sqlite3Get4byte(const u8*);
void sqlite3Put4byte(u8*, u32);
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
void sqlite3ConnectionBlocked(sqlite3 *, sqlite3 *);
void sqlite3ConnectionUnlocked(sqlite3 *db);
void sqlite3ConnectionClosed(sqlite3 *db);
#else
#define sqlite3ConnectionBlocked(x,y)
#define sqlite3ConnectionUnlocked(x)
#define sqlite3ConnectionClosed(x)
#endif
#ifdef SQLITE_SSE
#include "sseInt.h"
#endif

View File

@ -16,7 +16,7 @@
** These routines are in a separate files so that they will not be linked
** if they are not used.
**
** $Id: table.c,v 1.39 2009/01/19 20:49:10 drh Exp $
** $Id: table.c,v 1.40 2009/04/10 14:28:00 drh Exp $
*/
#include "sqliteInt.h"
#include <stdlib.h>
@ -29,14 +29,13 @@
** to the callback function is uses to build the result.
*/
typedef struct TabResult {
char **azResult;
char *zErrMsg;
int nResult;
int nAlloc;
int nRow;
int nColumn;
int nData;
int rc;
char **azResult; /* Accumulated output */
char *zErrMsg; /* Error message text, if an error occurs */
int nAlloc; /* Slots allocated for azResult[] */
int nRow; /* Number of rows in the result */
int nColumn; /* Number of columns in the result */
int nData; /* Slots used in azResult[]. (nRow+1)*nColumn */
int rc; /* Return code from sqlite3_exec() */
} TabResult;
/*
@ -45,10 +44,10 @@ typedef struct TabResult {
** memory as necessary.
*/
static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
TabResult *p = (TabResult*)pArg;
int need;
int i;
char *z;
TabResult *p = (TabResult*)pArg; /* Result accumulator */
int need; /* Slots needed in p->azResult[] */
int i; /* Loop counter */
char *z; /* A single column of result */
/* Make sure there is enough space in p->azResult to hold everything
** we need to remember from this invocation of the callback.
@ -58,9 +57,9 @@ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
}else{
need = nCol;
}
if( p->nData + need >= p->nAlloc ){
if( p->nData + need > p->nAlloc ){
char **azNew;
p->nAlloc = p->nAlloc*2 + need + 1;
p->nAlloc = p->nAlloc*2 + need;
azNew = sqlite3_realloc( p->azResult, sizeof(char*)*p->nAlloc );
if( azNew==0 ) goto malloc_failed;
p->azResult = azNew;
@ -134,7 +133,6 @@ int sqlite3_get_table(
if( pnRow ) *pnRow = 0;
if( pzErrMsg ) *pzErrMsg = 0;
res.zErrMsg = 0;
res.nResult = 0;
res.nRow = 0;
res.nColumn = 0;
res.nData = 1;
@ -168,13 +166,12 @@ int sqlite3_get_table(
}
if( res.nAlloc>res.nData ){
char **azNew;
azNew = sqlite3_realloc( res.azResult, sizeof(char*)*(res.nData+1) );
azNew = sqlite3_realloc( res.azResult, sizeof(char*)*res.nData );
if( azNew==0 ){
sqlite3_free_table(&res.azResult[1]);
db->errCode = SQLITE_NOMEM;
return SQLITE_NOMEM;
}
res.nAlloc = res.nData+1;
res.azResult = azNew;
}
*pazResult = &res.azResult[1];

View File

@ -12,7 +12,7 @@
** A TCL Interface to SQLite. Append this file to sqlite3.c and
** compile the whole thing to build a TCL-enabled version of SQLite.
**
** $Id: tclsqlite.c,v 1.237 2009/02/17 16:29:11 danielk1977 Exp $
** $Id: tclsqlite.c,v 1.241 2009/03/27 12:44:35 drh Exp $
*/
#include "tcl.h"
#include <errno.h>
@ -109,6 +109,7 @@ struct SqliteDb {
SqlFunc *pFunc; /* List of SQL functions */
Tcl_Obj *pUpdateHook; /* Update hook script (if any) */
Tcl_Obj *pRollbackHook; /* Rollback hook script (if any) */
Tcl_Obj *pUnlockNotify; /* Unlock notify script (if any) */
SqlCollate *pCollate; /* List of SQL collation functions */
int rc; /* Return code of most recent sqlite3_exec() */
Tcl_Obj *pCollateNeeded; /* Collation needed script */
@ -574,6 +575,33 @@ static void DbRollbackHandler(void *clientData){
}
}
#if defined(SQLITE_TEST) && defined(SQLITE_ENABLE_UNLOCK_NOTIFY)
static void setTestUnlockNotifyVars(Tcl_Interp *interp, int iArg, int nArg){
char zBuf[64];
sprintf(zBuf, "%d", iArg);
Tcl_SetVar(interp, "sqlite_unlock_notify_arg", zBuf, TCL_GLOBAL_ONLY);
sprintf(zBuf, "%d", nArg);
Tcl_SetVar(interp, "sqlite_unlock_notify_argcount", zBuf, TCL_GLOBAL_ONLY);
}
#else
# define setTestUnlockNotifyVars(x,y,z)
#endif
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
static void DbUnlockNotify(void **apArg, int nArg){
int i;
for(i=0; i<nArg; i++){
const int flags = (TCL_EVAL_GLOBAL|TCL_EVAL_DIRECT);
SqliteDb *pDb = (SqliteDb *)apArg[i];
setTestUnlockNotifyVars(pDb->interp, i, nArg);
assert( pDb->pUnlockNotify);
Tcl_EvalObjEx(pDb->interp, pDb->pUnlockNotify, flags);
Tcl_DecrRefCount(pDb->pUnlockNotify);
pDb->pUnlockNotify = 0;
}
}
#endif
static void DbUpdateHandler(
void *p,
int op,
@ -993,8 +1021,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
"profile", "progress", "rekey",
"restore", "rollback_hook", "status",
"timeout", "total_changes", "trace",
"transaction", "update_hook", "version",
0
"transaction", "unlock_notify", "update_hook",
"version", 0
};
enum DB_enum {
DB_AUTHORIZER, DB_BACKUP, DB_BUSY,
@ -1007,7 +1035,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
DB_PROFILE, DB_PROGRESS, DB_REKEY,
DB_RESTORE, DB_ROLLBACK_HOOK, DB_STATUS,
DB_TIMEOUT, DB_TOTAL_CHANGES, DB_TRACE,
DB_TRANSACTION, DB_UPDATE_HOOK, DB_VERSION,
DB_TRANSACTION, DB_UNLOCK_NOTIFY, DB_UPDATE_HOOK,
DB_VERSION,
};
/* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */
@ -2450,6 +2479,42 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
break;
}
/*
** $db unlock_notify ?script?
*/
case DB_UNLOCK_NOTIFY: {
#ifndef SQLITE_ENABLE_UNLOCK_NOTIFY
Tcl_AppendResult(interp, "unlock_notify not available in this build", 0);
rc = TCL_ERROR;
#else
if( objc!=2 && objc!=3 ){
Tcl_WrongNumArgs(interp, 2, objv, "?SCRIPT?");
rc = TCL_ERROR;
}else{
void (*xNotify)(void **, int) = 0;
void *pNotifyArg = 0;
if( pDb->pUnlockNotify ){
Tcl_DecrRefCount(pDb->pUnlockNotify);
pDb->pUnlockNotify = 0;
}
if( objc==3 ){
xNotify = DbUnlockNotify;
pNotifyArg = (void *)pDb;
pDb->pUnlockNotify = objv[2];
Tcl_IncrRefCount(pDb->pUnlockNotify);
}
if( sqlite3_unlock_notify(pDb->db, xNotify, pNotifyArg) ){
Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), 0);
rc = TCL_ERROR;
}
}
#endif
break;
}
/*
** $db update_hook ?script?
** $db rollback_hook ?script?
@ -2530,8 +2595,21 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
int i;
const char *zFile;
const char *zVfs = 0;
int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX;
int flags;
Tcl_DString translatedFilename;
/* In normal use, each TCL interpreter runs in a single thread. So
** by default, we can turn of mutexing on SQLite database connections.
** However, for testing purposes it is useful to have mutexes turned
** on. So, by default, mutexes default off. But if compiled with
** SQLITE_TCL_DEFAULT_FULLMUTEX then mutexes default on.
*/
#ifdef SQLITE_TCL_DEFAULT_FULLMUTEX
flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX;
#else
flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX;
#endif
if( objc==2 ){
zArg = Tcl_GetStringFromObj(objv[1], 0);
if( strcmp(zArg,"-version")==0 ){

View File

@ -13,7 +13,7 @@
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
**
** $Id: test1.c,v 1.347 2009/02/03 16:51:25 danielk1977 Exp $
** $Id: test1.c,v 1.351 2009/04/08 15:45:32 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
@ -125,6 +125,7 @@ const char *sqlite3TestErrorName(int rc){
case SQLITE_ABORT: zName = "SQLITE_ABORT"; break;
case SQLITE_BUSY: zName = "SQLITE_BUSY"; break;
case SQLITE_LOCKED: zName = "SQLITE_LOCKED"; break;
case SQLITE_LOCKED_SHAREDCACHE: zName = "SQLITE_LOCKED_SHAREDCACHE";break;
case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break;
case SQLITE_READONLY: zName = "SQLITE_READONLY"; break;
case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break;
@ -495,7 +496,7 @@ static int test_exec_nr(
/*
** Usage: sqlite3_mprintf_z_test SEPARATOR ARG0 ARG1 ...
**
** Test the %z format of sqliteMPrintf(). Use multiple mprintf() calls to
** Test the %z format of sqlite_mprintf(). Use multiple mprintf() calls to
** concatenate arg0 through argn using separator as the separator.
** Return the result.
*/
@ -509,7 +510,7 @@ static int test_mprintf_z(
int i;
for(i=2; i<argc && (i==2 || zResult); i++){
zResult = sqlite3MPrintf(0, "%z%s%s", zResult, argv[1], argv[i]);
zResult = sqlite3_mprintf("%z%s%s", zResult, argv[1], argv[i]);
}
Tcl_AppendResult(interp, zResult, 0);
sqlite3_free(zResult);
@ -519,7 +520,7 @@ static int test_mprintf_z(
/*
** Usage: sqlite3_mprintf_n_test STRING
**
** Test the %n format of sqliteMPrintf(). Return the length of the
** Test the %n format of sqlite_mprintf(). Return the length of the
** input string.
*/
static int test_mprintf_n(
@ -530,7 +531,7 @@ static int test_mprintf_n(
){
char *zStr;
int n = 0;
zStr = sqlite3MPrintf(0, "%s%n", argv[1], &n);
zStr = sqlite3_mprintf("%s%n", argv[1], &n);
sqlite3_free(zStr);
Tcl_SetObjResult(interp, Tcl_NewIntObj(n));
return TCL_OK;
@ -3260,6 +3261,7 @@ static int test_errmsg16(
#ifndef SQLITE_OMIT_UTF16
sqlite3 *db;
const void *zErr;
const char *z;
int bytes = 0;
if( objc!=2 ){
@ -3271,7 +3273,8 @@ static int test_errmsg16(
zErr = sqlite3_errmsg16(db);
if( zErr ){
bytes = sqlite3Utf16ByteLen(zErr, -1);
z = zErr;
for(bytes=0; z[bytes] || z[bytes+1]; bytes+=2){}
}
Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zErr, bytes));
#endif /* SQLITE_OMIT_UTF16 */
@ -3661,6 +3664,24 @@ static int test_step(
return TCL_OK;
}
static int test_sql(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
sqlite3_stmt *pStmt;
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "STMT");
return TCL_ERROR;
}
if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
Tcl_SetResult(interp, (char *)sqlite3_sql(pStmt), TCL_VOLATILE);
return TCL_OK;
}
/*
** Usage: sqlite3_column_count STMT
**
@ -3934,7 +3955,10 @@ static int test_stmt_utf16(
zName16 = xFunc(pStmt, col);
if( zName16 ){
pRet = Tcl_NewByteArrayObj(zName16, sqlite3Utf16ByteLen(zName16, -1)+2);
int n;
const char *z = zName16;
for(n=0; z[n] || z[n+1]; n+=2){}
pRet = Tcl_NewByteArrayObj(zName16, n+2);
Tcl_SetObjResult(interp, pRet);
}
#endif /* SQLITE_OMIT_UTF16 */
@ -4816,6 +4840,42 @@ static int test_pcache_stats(
return TCL_OK;
}
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
static void test_unlock_notify_cb(void **aArg, int nArg){
int ii;
for(ii=0; ii<nArg; ii++){
Tcl_EvalEx((Tcl_Interp *)aArg[ii], "unlock_notify", -1, TCL_EVAL_GLOBAL);
}
}
#endif /* SQLITE_ENABLE_UNLOCK_NOTIFY */
/*
** tclcmd: sqlite3_unlock_notify db
*/
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
static int test_unlock_notify(
ClientData clientData, /* Unused */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj *CONST objv[] /* Command arguments */
){
sqlite3 *db;
int rc;
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "DB");
return TCL_ERROR;
}
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
return TCL_ERROR;
}
rc = sqlite3_unlock_notify(db, test_unlock_notify_cb, (void *)interp);
Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
return TCL_OK;
}
#endif
/*
** Register commands with the TCL interpreter.
@ -4916,6 +4976,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_transfer_bindings", test_transfer_bind ,0 },
{ "sqlite3_changes", test_changes ,0 },
{ "sqlite3_step", test_step ,0 },
{ "sqlite3_sql", test_sql ,0 },
{ "sqlite3_next_stmt", test_next_stmt ,0 },
{ "sqlite3_release_memory", test_release_memory, 0},
@ -5000,6 +5061,9 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_blob_write", test_blob_write, 0 },
#endif
{ "pcache_stats", test_pcache_stats, 0 },
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
{ "sqlite3_unlock_notify", test_unlock_notify, 0 },
#endif
};
static int bitmask_size = sizeof(Bitmask)*8;
int i;

View File

@ -13,7 +13,7 @@
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
**
** $Id: test3.c,v 1.102 2008/10/27 13:59:34 danielk1977 Exp $
** $Id: test3.c,v 1.103 2009/03/18 10:33:02 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "btreeInt.h"
@ -235,7 +235,7 @@ static int btree_begin_statement(
}
pBt = sqlite3TestTextToPtr(argv[1]);
sqlite3BtreeEnter(pBt);
rc = sqlite3BtreeBeginStmt(pBt);
rc = sqlite3BtreeBeginStmt(pBt, 1);
sqlite3BtreeLeave(pBt);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
@ -264,7 +264,10 @@ static int btree_rollback_statement(
}
pBt = sqlite3TestTextToPtr(argv[1]);
sqlite3BtreeEnter(pBt);
rc = sqlite3BtreeRollbackStmt(pBt);
rc = sqlite3BtreeSavepoint(pBt, SAVEPOINT_ROLLBACK, 0);
if( rc==SQLITE_OK ){
rc = sqlite3BtreeSavepoint(pBt, SAVEPOINT_RELEASE, 0);
}
sqlite3BtreeLeave(pBt);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
@ -293,7 +296,7 @@ static int btree_commit_statement(
}
pBt = sqlite3TestTextToPtr(argv[1]);
sqlite3BtreeEnter(pBt);
rc = sqlite3BtreeCommitStmt(pBt);
rc = sqlite3BtreeSavepoint(pBt, SAVEPOINT_RELEASE, 0);
sqlite3BtreeLeave(pBt);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);

View File

@ -13,7 +13,7 @@
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
**
** $Id: test8.c,v 1.75 2008/08/31 00:29:08 shane Exp $
** $Id: test8.c,v 1.76 2009/04/08 15:45:32 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
@ -253,7 +253,7 @@ static int getIndexArray(
}
/* Compile an sqlite pragma to loop through all indices on table zTab */
zSql = sqlite3MPrintf(0, "PRAGMA index_list(%s)", zTab);
zSql = sqlite3_mprintf("PRAGMA index_list(%s)", zTab);
if( !zSql ){
rc = SQLITE_NOMEM;
goto get_index_array_out;
@ -267,7 +267,7 @@ static int getIndexArray(
while( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
const char *zIdx = (const char *)sqlite3_column_text(pStmt, 1);
sqlite3_stmt *pStmt2 = 0;
zSql = sqlite3MPrintf(0, "PRAGMA index_info(%s)", zIdx);
zSql = sqlite3_mprintf("PRAGMA index_info(%s)", zIdx);
if( !zSql ){
rc = SQLITE_NOMEM;
goto get_index_array_out;
@ -413,7 +413,7 @@ static int echoConstructor(
pVtab->db = db;
/* Allocate echo_vtab.zThis */
pVtab->zThis = sqlite3MPrintf(0, "%s", argv[2]);
pVtab->zThis = sqlite3_mprintf("%s", argv[2]);
if( !pVtab->zThis ){
echoDestructor((sqlite3_vtab *)pVtab);
return SQLITE_NOMEM;
@ -421,10 +421,10 @@ static int echoConstructor(
/* Allocate echo_vtab.zTableName */
if( argc>3 ){
pVtab->zTableName = sqlite3MPrintf(0, "%s", argv[3]);
pVtab->zTableName = sqlite3_mprintf("%s", argv[3]);
dequoteString(pVtab->zTableName);
if( pVtab->zTableName && pVtab->zTableName[0]=='*' ){
char *z = sqlite3MPrintf(0, "%s%s", argv[2], &(pVtab->zTableName[1]));
char *z = sqlite3_mprintf("%s%s", argv[2], &(pVtab->zTableName[1]));
sqlite3_free(pVtab->zTableName);
pVtab->zTableName = z;
pVtab->isPattern = 1;
@ -482,8 +482,8 @@ static int echoCreate(
if( rc==SQLITE_OK && argc==5 ){
char *zSql;
echo_vtab *pVtab = *(echo_vtab **)ppVtab;
pVtab->zLogName = sqlite3MPrintf(0, "%s", argv[4]);
zSql = sqlite3MPrintf(0, "CREATE TABLE %Q(logmsg)", pVtab->zLogName);
pVtab->zLogName = sqlite3_mprintf("%s", argv[4]);
zSql = sqlite3_mprintf("CREATE TABLE %Q(logmsg)", pVtab->zLogName);
rc = sqlite3_exec(db, zSql, 0, 0, 0);
sqlite3_free(zSql);
if( rc!=SQLITE_OK ){
@ -536,7 +536,7 @@ static int echoDestroy(sqlite3_vtab *pVtab){
/* Drop the "log" table, if one exists (see echoCreate() for details) */
if( p && p->zLogName ){
char *zSql;
zSql = sqlite3MPrintf(0, "DROP TABLE %Q", p->zLogName);
zSql = sqlite3_mprintf("DROP TABLE %Q", p->zLogName);
rc = sqlite3_exec(p->db, zSql, 0, 0, 0);
sqlite3_free(zSql);
}
@ -1224,7 +1224,7 @@ static int echoRename(sqlite3_vtab *vtab, const char *zNewName){
if( p->isPattern ){
int nThis = strlen(p->zThis);
char *zSql = sqlite3MPrintf(0, "ALTER TABLE %s RENAME TO %s%s",
char *zSql = sqlite3_mprintf("ALTER TABLE %s RENAME TO %s%s",
p->zTableName, zNewName, &p->zTableName[nThis]
);
rc = sqlite3_exec(p->db, zSql, 0, 0, 0);

View File

@ -14,7 +14,7 @@
** for completeness. Test code is written in C for these cases
** as there is not much point in binding to Tcl.
**
** $Id: test9.c,v 1.6 2008/07/11 13:53:55 drh Exp $
** $Id: test9.c,v 1.7 2009/04/02 18:32:27 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
@ -114,6 +114,7 @@ static int c_misuse_test(
){
const char *zErrFunction = "N/A";
sqlite3 *db = 0;
sqlite3_stmt *pStmt;
int rc;
if( objc!=1 ){
@ -138,29 +139,37 @@ static int c_misuse_test(
goto error_out;
}
rc = sqlite3_prepare(db, 0, 0, 0, 0);
pStmt = (sqlite3_stmt*)1234;
rc = sqlite3_prepare(db, 0, 0, &pStmt, 0);
if( rc!=SQLITE_MISUSE ){
zErrFunction = "sqlite3_prepare";
goto error_out;
}
assert( pStmt==0 ); /* Verify that pStmt is zeroed even on a MISUSE error */
rc = sqlite3_prepare_v2(db, 0, 0, 0, 0);
pStmt = (sqlite3_stmt*)1234;
rc = sqlite3_prepare_v2(db, 0, 0, &pStmt, 0);
if( rc!=SQLITE_MISUSE ){
zErrFunction = "sqlite3_prepare_v2";
goto error_out;
}
assert( pStmt==0 );
#ifndef SQLITE_OMIT_UTF16
rc = sqlite3_prepare16(db, 0, 0, 0, 0);
pStmt = (sqlite3_stmt*)1234;
rc = sqlite3_prepare16(db, 0, 0, &pStmt, 0);
if( rc!=SQLITE_MISUSE ){
zErrFunction = "sqlite3_prepare16";
goto error_out;
}
rc = sqlite3_prepare16_v2(db, 0, 0, 0, 0);
assert( pStmt==0 );
pStmt = (sqlite3_stmt*)1234;
rc = sqlite3_prepare16_v2(db, 0, 0, &pStmt, 0);
if( rc!=SQLITE_MISUSE ){
zErrFunction = "sqlite3_prepare16_v2";
goto error_out;
}
assert( pStmt==0 );
#endif
return TCL_OK;

View File

@ -10,7 +10,7 @@
**
*************************************************************************
**
** $Id: test_async.c,v 1.48 2008/09/26 20:02:50 drh Exp $
** $Id: test_async.c,v 1.57 2009/04/07 11:21:29 danielk1977 Exp $
**
** This file contains an example implementation of an asynchronous IO
** backend for SQLite.
@ -109,7 +109,7 @@
#define ENABLE_FILE_LOCKING
#ifndef SQLITE_AMALGAMATION
# include "sqlite3.h"
# include "sqliteInt.h"
# include <assert.h>
# include <string.h>
#endif
@ -280,7 +280,7 @@ static struct TestAsyncStaticData {
volatile int ioDelay; /* Extra delay between write operations */
volatile int writerHaltWhenIdle; /* Writer thread halts when queue empty */
volatile int writerHaltNow; /* Writer thread halts after next op */
int ioError; /* True if an IO error has occured */
int ioError; /* True if an IO error has occurred */
int nFile; /* Number of open files (from sqlite pov) */
} async = {
PTHREAD_MUTEX_INITIALIZER,
@ -419,7 +419,7 @@ struct AsyncFileData {
sqlite3_file *pBaseWrite; /* Write handle to the underlying Os file */
AsyncFileLock lock; /* Lock state for this handle */
AsyncLock *pLock; /* AsyncLock object for this file system entry */
AsyncWrite close;
AsyncWrite closeOp; /* Preallocated close operation */
};
/*
@ -483,7 +483,6 @@ static int async_mutex_lock(pthread_mutex_t *pMutex){
assert(&(aHolder[2])==&asyncdebug.writerMutexHolder);
assert( pthread_self()!=0 );
for(iIdx=0; iIdx<3; iIdx++){
if( pMutex==&aMutex[iIdx] ) break;
@ -610,7 +609,9 @@ static void assert_mutex_is_held(pthread_mutex_t *pMutex){
*/
static void addAsyncWrite(AsyncWrite *pWrite){
/* We must hold the queue mutex in order to modify the queue pointers */
pthread_mutex_lock(&async.queueMutex);
if( pWrite->op!=ASYNC_UNLOCK ){
pthread_mutex_lock(&async.queueMutex);
}
/* Add the record to the end of the write-op queue */
assert( !pWrite->pNext );
@ -629,7 +630,9 @@ static void addAsyncWrite(AsyncWrite *pWrite){
}
/* Drop the queue mutex */
pthread_mutex_unlock(&async.queueMutex);
if( pWrite->op!=ASYNC_UNLOCK ){
pthread_mutex_unlock(&async.queueMutex);
}
/* The writer thread might have been idle because there was nothing
** on the write-op queue for it to do. So wake it up. */
@ -639,7 +642,7 @@ static void addAsyncWrite(AsyncWrite *pWrite){
/*
** Increment async.nFile in a thread-safe manner.
*/
static void incrOpenFileCount(){
static void incrOpenFileCount(void){
/* We must hold the queue mutex in order to modify async.nFile */
pthread_mutex_lock(&async.queueMutex);
if( async.nFile==0 ){
@ -701,7 +704,7 @@ static int asyncClose(sqlite3_file *pFile){
p->lock.eLock = 0;
pthread_mutex_unlock(&async.lockMutex);
addAsyncWrite(&p->close);
addAsyncWrite(&p->closeOp);
return SQLITE_OK;
}
@ -956,10 +959,12 @@ static int asyncUnlock(sqlite3_file *pFile, int eLock){
AsyncFileData *p = ((AsyncFile *)pFile)->pData;
if( p->zName ){
AsyncFileLock *pLock = &p->lock;
pthread_mutex_lock(&async.queueMutex);
pthread_mutex_lock(&async.lockMutex);
pLock->eLock = MIN(pLock->eLock, eLock);
pthread_mutex_unlock(&async.lockMutex);
rc = addNewAsyncWrite(p, ASYNC_UNLOCK, 0, eLock, 0);
pthread_mutex_unlock(&async.lockMutex);
pthread_mutex_unlock(&async.queueMutex);
}
return rc;
}
@ -1041,6 +1046,25 @@ static int unlinkAsyncFile(AsyncFileData *pData){
return rc;
}
/*
** The parameter passed to this function is a copy of a 'flags' parameter
** passed to this modules xOpen() method. This function returns true
** if the file should be opened asynchronously, or false if it should
** be opened immediately.
**
** If the file is to be opened asynchronously, then asyncOpen() will add
** an entry to the event queue and the file will not actually be opened
** until the event is processed. Otherwise, the file is opened directly
** by the caller.
*/
static int doAsynchronousOpen(int flags){
return (flags&SQLITE_OPEN_CREATE) && (
(flags&SQLITE_OPEN_MAIN_JOURNAL) ||
(flags&SQLITE_OPEN_TEMP_JOURNAL) ||
(flags&SQLITE_OPEN_DELETEONCLOSE)
);
}
/*
** Open a file.
*/
@ -1075,7 +1099,7 @@ static int asyncOpen(
AsyncFileData *pData;
AsyncLock *pLock = 0;
char *z;
int isExclusive = (flags&SQLITE_OPEN_EXCLUSIVE);
int isAsyncOpen = doAsynchronousOpen(flags);
/* If zName is NULL, then the upper layer is requesting an anonymous file */
if( zName ){
@ -1097,8 +1121,8 @@ static int asyncOpen(
pData->pBaseRead = (sqlite3_file*)z;
z += pVfs->szOsFile;
pData->pBaseWrite = (sqlite3_file*)z;
pData->close.pFileData = pData;
pData->close.op = ASYNC_CLOSE;
pData->closeOp.pFileData = pData;
pData->closeOp.op = ASYNC_CLOSE;
if( zName ){
z += pVfs->szOsFile;
@ -1107,10 +1131,14 @@ static int asyncOpen(
memcpy(pData->zName, zName, nName);
}
if( !isExclusive ){
rc = pVfs->xOpen(pVfs, zName, pData->pBaseRead, flags, pOutFlags);
if( rc==SQLITE_OK && ((*pOutFlags)&SQLITE_OPEN_READWRITE) ){
rc = pVfs->xOpen(pVfs, zName, pData->pBaseWrite, flags, 0);
if( !isAsyncOpen ){
int flagsout;
rc = pVfs->xOpen(pVfs, pData->zName, pData->pBaseRead, flags, &flagsout);
if( rc==SQLITE_OK && (flagsout&SQLITE_OPEN_READWRITE) ){
rc = pVfs->xOpen(pVfs, pData->zName, pData->pBaseWrite, flags, 0);
}
if( pOutFlags ){
*pOutFlags = flagsout;
}
}
@ -1126,7 +1154,7 @@ static int asyncOpen(
#ifdef ENABLE_FILE_LOCKING
if( flags&SQLITE_OPEN_MAIN_DB ){
pLock->pFile = (sqlite3_file *)&pLock[1];
rc = pVfs->xOpen(pVfs, zName, pLock->pFile, flags, 0);
rc = pVfs->xOpen(pVfs, pData->zName, pLock->pFile, flags, 0);
if( rc!=SQLITE_OK ){
sqlite3_free(pLock);
pLock = 0;
@ -1175,7 +1203,7 @@ static int asyncOpen(
pData->pLock = pLock;
}
if( rc==SQLITE_OK && isExclusive ){
if( rc==SQLITE_OK && isAsyncOpen ){
rc = addNewAsyncWrite(pData, ASYNC_OPENEXCLUSIVE, (sqlite3_int64)flags,0,0);
if( rc==SQLITE_OK ){
if( pOutFlags ) *pOutFlags = flags;
@ -1186,6 +1214,9 @@ static int asyncOpen(
sqlite3_free(pData);
}
}
if( rc!=SQLITE_OK ){
p->pMethod = 0;
}
return rc;
}
@ -1259,40 +1290,27 @@ static int asyncFullPathname(
** file-system uses unix style paths.
*/
if( rc==SQLITE_OK ){
int iIn;
int iOut = 0;
int nPathOut = strlen(zPathOut);
for(iIn=0; iIn<nPathOut; iIn++){
/* Replace any occurences of "//" with "/" */
if( iIn<=(nPathOut-2) && zPathOut[iIn]=='/' && zPathOut[iIn+1]=='/'
){
continue;
int i, j;
int n = nPathOut;
char *z = zPathOut;
while( n>1 && z[n-1]=='/' ){ n--; }
for(i=j=0; i<n; i++){
if( z[i]=='/' ){
if( z[i+1]=='/' ) continue;
if( z[i+1]=='.' && i+2<n && z[i+2]=='/' ){
i += 1;
continue;
}
if( z[i+1]=='.' && i+3<n && z[i+2]=='.' && z[i+3]=='/' ){
while( j>0 && z[j-1]!='/' ){ j--; }
if( j>0 ){ j--; }
i += 2;
continue;
}
}
/* Replace any occurences of "/./" with "/" */
if( iIn<=(nPathOut-3)
&& zPathOut[iIn]=='/' && zPathOut[iIn+1]=='.' && zPathOut[iIn+2]=='/'
){
iIn++;
continue;
}
/* Replace any occurences of "<path-component>/../" with "" */
if( iOut>0 && iIn<=(nPathOut-4)
&& zPathOut[iIn]=='/' && zPathOut[iIn+1]=='.'
&& zPathOut[iIn+2]=='.' && zPathOut[iIn+3]=='/'
){
iIn += 3;
iOut--;
for( ; iOut>0 && zPathOut[iOut-1]!='/'; iOut--);
continue;
}
zPathOut[iOut++] = zPathOut[iIn];
z[j++] = z[i];
}
zPathOut[iOut] = '\0';
z[j] = 0;
}
return rc;
@ -1305,11 +1323,11 @@ static void asyncDlError(sqlite3_vfs *pAsyncVfs, int nByte, char *zErrMsg){
sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
pVfs->xDlError(pVfs, nByte, zErrMsg);
}
static void *asyncDlSym(
static void (*asyncDlSym(
sqlite3_vfs *pAsyncVfs,
void *pHandle,
const char *zSymbol
){
))(void){
sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
return pVfs->xDlSym(pVfs, pHandle, zSymbol);
}
@ -1513,15 +1531,54 @@ static void *asyncWriterThread(void *pIsStarted){
}
case ASYNC_UNLOCK: {
AsyncWrite *pIter;
AsyncFileData *pData = p->pFileData;
int eLock = p->nByte;
pthread_mutex_lock(&async.lockMutex);
pData->lock.eAsyncLock = MIN(
pData->lock.eAsyncLock, MAX(pData->lock.eLock, eLock)
);
assert(pData->lock.eAsyncLock>=pData->lock.eLock);
rc = getFileLock(pData->pLock);
pthread_mutex_unlock(&async.lockMutex);
/* When a file is locked by SQLite using the async backend, it is
** locked within the 'real' file-system synchronously. When it is
** unlocked, an ASYNC_UNLOCK event is added to the write-queue to
** unlock the file asynchronously. The design of the async backend
** requires that the 'real' file-system file be locked from the
** time that SQLite first locks it (and probably reads from it)
** until all asynchronous write events that were scheduled before
** SQLite unlocked the file have been processed.
**
** This is more complex if SQLite locks and unlocks the file multiple
** times in quick succession. For example, if SQLite does:
**
** lock, write, unlock, lock, write, unlock
**
** Each "lock" operation locks the file immediately. Each "write"
** and "unlock" operation adds an event to the event queue. If the
** second "lock" operation is performed before the first "unlock"
** operation has been processed asynchronously, then the first
** "unlock" cannot be safely processed as is, since this would mean
** the file was unlocked when the second "write" operation is
** processed. To work around this, when processing an ASYNC_UNLOCK
** operation, SQLite:
**
** 1) Unlocks the file to the minimum of the argument passed to
** the xUnlock() call and the current lock from SQLite's point
** of view, and
**
** 2) Only unlocks the file at all if this event is the last
** ASYNC_UNLOCK event on this file in the write-queue.
*/
assert( holdingMutex==1 );
assert( async.pQueueFirst==p );
for(pIter=async.pQueueFirst->pNext; pIter; pIter=pIter->pNext){
if( pIter->pFileData==pData && pIter->op==ASYNC_UNLOCK ) break;
}
if( !pIter ){
pthread_mutex_lock(&async.lockMutex);
pData->lock.eAsyncLock = MIN(
pData->lock.eAsyncLock, MAX(pData->lock.eLock, eLock)
);
assert(pData->lock.eAsyncLock>=pData->lock.eLock);
rc = getFileLock(pData->pLock);
pthread_mutex_unlock(&async.lockMutex);
}
break;
}
@ -1564,12 +1621,12 @@ static void *asyncWriterThread(void *pIsStarted){
}
assert( holdingMutex );
/* An IO error has occured. We cannot report the error back to the
/* An IO error has occurred. We cannot report the error back to the
** connection that requested the I/O since the error happened
** asynchronously. The connection has already moved on. There
** really is nobody to report the error to.
**
** The file for which the error occured may have been a database or
** The file for which the error occurred may have been a database or
** journal file. Regardless, none of the currently queued operations
** associated with the same database should now be performed. Nor should
** any subsequently requested IO on either a database or journal file

View File

@ -10,7 +10,7 @@
**
*************************************************************************
**
** $Id: test_backup.c,v 1.1 2009/02/03 16:51:25 danielk1977 Exp $
** $Id: test_backup.c,v 1.3 2009/03/30 12:56:52 drh Exp $
*/
#include "tcl.h"
@ -61,12 +61,13 @@ static int backupTestCmd(
switch( aSub[iCmd].eCmd ){
case BACKUP_FINISH: {
const char *zCmdName;
Tcl_CmdInfo cmdInfo;
Tcl_Command cmd = Tcl_GetCommandFromObj(interp, objv[0]);
Tcl_GetCommandInfoFromToken(cmd, &cmdInfo);
zCmdName = Tcl_GetString(objv[0]);
Tcl_GetCommandInfo(interp, zCmdName, &cmdInfo);
cmdInfo.deleteProc = 0;
Tcl_SetCommandInfoFromToken(cmd, &cmdInfo);
Tcl_DeleteCommandFromToken(interp, cmd);
Tcl_SetCommandInfo(interp, zCmdName, &cmdInfo);
Tcl_DeleteCommand(interp, zCmdName);
rc = sqlite3_backup_finish(p);
Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_STATIC);
@ -145,4 +146,3 @@ int Sqlitetestbackup_Init(Tcl_Interp *interp){
Tcl_CreateObjCommand(interp, "sqlite3_backup", backupTestInit, 0, 0);
return TCL_OK;
}

View File

@ -16,7 +16,7 @@
** The focus of this file is providing the TCL testing layer
** access to compile-time constants.
**
** $Id: test_config.c,v 1.47 2009/01/12 14:01:45 danielk1977 Exp $
** $Id: test_config.c,v 1.48 2009/03/16 13:19:36 danielk1977 Exp $
*/
#include "sqliteLimit.h"
@ -493,6 +493,12 @@ Tcl_SetVar2(interp, "sqlite_options", "long_double",
Tcl_SetVar2(interp, "sqlite_options", "update_delete_limit", "0", TCL_GLOBAL_ONLY);
#endif
#if defined(SQLITE_ENABLE_UNLOCK_NOTIFY)
Tcl_SetVar2(interp, "sqlite_options", "unlock_notify", "1", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "unlock_notify", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_SECURE_DELETE
Tcl_SetVar2(interp, "sqlite_options", "secure_delete", "1", TCL_GLOBAL_ONLY);
#else

View File

@ -12,7 +12,7 @@
** Code for testing all sorts of SQLite interfaces. This code
** implements new SQL functions used by the test scripts.
**
** $Id: test_func.c,v 1.13 2008/08/28 02:26:07 drh Exp $
** $Id: test_func.c,v 1.14 2009/03/19 18:51:07 danielk1977 Exp $
*/
#include "sqlite3.h"
#include "tcl.h"
@ -146,6 +146,25 @@ static void test_destructor_count(
sqlite3_result_int(pCtx, test_destructor_count_var);
}
/*
** The following aggregate function, test_agg_errmsg16(), takes zero
** arguments. It returns the text value returned by the sqlite3_errmsg16()
** API function.
*/
void sqlite3BeginBenignMalloc(void);
void sqlite3EndBenignMalloc(void);
static void test_agg_errmsg16_step(sqlite3_context *a, int b,sqlite3_value **c){
}
static void test_agg_errmsg16_final(sqlite3_context *ctx){
const void *z;
sqlite3 * db = sqlite3_context_db_handle(ctx);
sqlite3_aggregate_context(ctx, 2048);
sqlite3BeginBenignMalloc();
z = sqlite3_errmsg16(db);
sqlite3EndBenignMalloc();
sqlite3_result_text16(ctx, z, -1, SQLITE_TRANSIENT);
}
/*
** Routines for testing the sqlite3_get_auxdata() and sqlite3_set_auxdata()
** interface.
@ -318,6 +337,10 @@ static int registerTestFunctions(sqlite3 *db){
sqlite3_create_function(db, aFuncs[i].zName, aFuncs[i].nArg,
aFuncs[i].eTextRep, 0, aFuncs[i].xFunc, 0, 0);
}
sqlite3_create_function(db, "test_agg_errmsg16", 0, SQLITE_ANY, 0, 0,
test_agg_errmsg16_step, test_agg_errmsg16_final);
return SQLITE_OK;
}

View File

@ -15,7 +15,7 @@
** correctly populates and syncs a journal file before writing to a
** corresponding database file.
**
** $Id: test_journal.c,v 1.11 2009/02/12 09:11:56 danielk1977 Exp $
** $Id: test_journal.c,v 1.15 2009/04/07 11:21:29 danielk1977 Exp $
*/
#if SQLITE_TEST /* This file is used for testing only */
@ -50,7 +50,7 @@
** c) The set of page numbers corresponding to free-list leaf pages.
** d) A check-sum for every page in the database file.
**
** The start of a write-transaction is deemed to have occured when a
** The start of a write-transaction is deemed to have occurred when a
** 28-byte journal header is written to byte offset 0 of the journal
** file.
**
@ -206,6 +206,17 @@ struct JtGlobal {
};
static struct JtGlobal g = {0, 0};
/*
** Functions to obtain and relinquish a mutex to protect g.pList. The
** STATIC_PRNG mutex is reused, purely for the sake of convenience.
*/
static void enterJtMutex(void){
sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PRNG));
}
static void leaveJtMutex(void){
sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PRNG));
}
extern int sqlite3_io_error_pending;
static void stop_ioerr_simulation(int *piSave){
*piSave = sqlite3_io_error_pending;
@ -236,11 +247,12 @@ static int jtClose(sqlite3_file *pFile){
jt_file *p = (jt_file *)pFile;
closeTransaction(p);
enterJtMutex();
if( p->zName ){
for(pp=&g.pList; *pp!=p; pp=&(*pp)->pNext);
*pp = p->pNext;
}
leaveJtMutex();
return sqlite3OsClose(p->pReal);
}
@ -257,7 +269,6 @@ static int jtRead(
return sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst);
}
/*
** Parameter zJournal is the name of a journal file that is currently
** open. This function locates and returns the handle opened on the
@ -274,6 +285,7 @@ static int jtRead(
**/
static jt_file *locateDatabaseHandle(const char *zJournal){
jt_file *pMain = 0;
enterJtMutex();
for(pMain=g.pList; pMain; pMain=pMain->pNext){
int nName = strlen(zJournal) - strlen("-journal");
if( (pMain->flags&SQLITE_OPEN_MAIN_DB)
@ -284,6 +296,7 @@ static jt_file *locateDatabaseHandle(const char *zJournal){
break;
}
}
leaveJtMutex();
return pMain;
}
@ -656,6 +669,7 @@ static int jtOpen(
){
int rc;
jt_file *p = (jt_file *)pFile;
pFile->pMethods = 0;
p->pReal = (sqlite3_file *)&p[1];
p->pReal->pMethods = 0;
rc = sqlite3OsOpen(g.pVfs, zName, p->pReal, flags, pOutFlags);
@ -668,10 +682,12 @@ static int jtOpen(
p->pNext = 0;
p->pWritable = 0;
p->aCksum = 0;
enterJtMutex();
if( zName ){
p->pNext = g.pList;
g.pList = p;
}
leaveJtMutex();
}
return rc;
}
@ -798,7 +814,7 @@ int jt_register(char *zWrap, int isDefault){
/*
** Uninstall the jt VFS, if it is installed.
*/
void jt_unregister(){
void jt_unregister(void){
sqlite3_vfs_unregister(&jt_vfs);
}

View File

@ -13,7 +13,7 @@
** This file contains code used to implement test interfaces to the
** memory allocation subsystem.
**
** $Id: test_malloc.c,v 1.53 2009/02/04 15:27:40 danielk1977 Exp $
** $Id: test_malloc.c,v 1.54 2009/04/07 11:21:29 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
@ -49,7 +49,7 @@ static void sqlite3Fault(void){
** Check to see if a fault should be simulated. Return true to simulate
** the fault. Return false if the fault should not be simulated.
*/
static int faultsimStep(){
static int faultsimStep(void){
if( likely(!memfault.enable) ){
return 0;
}
@ -771,7 +771,7 @@ static void test_memdebug_callback(int nByte, int nFrame, void **aFrame){
}
#endif /* SQLITE_MEMDEBUG */
static void test_memdebug_log_clear(){
static void test_memdebug_log_clear(void){
Tcl_HashSearch search;
Tcl_HashEntry *pEntry;
for(

View File

@ -10,7 +10,7 @@
**
*************************************************************************
**
** $Id: test_mutex.c,v 1.14 2009/02/11 05:18:07 danielk1977 Exp $
** $Id: test_mutex.c,v 1.15 2009/03/20 13:15:30 drh Exp $
*/
#include "tcl.h"
@ -248,7 +248,7 @@ static int test_read_mutex_counters(
int ii;
char *aName[8] = {
"fast", "recursive", "static_master", "static_mem",
"static_mem2", "static_prng", "static_lru", "static_lru2"
"static_open", "static_prng", "static_lru", "static_lru2"
};
if( objc!=1 ){

View File

@ -10,7 +10,7 @@
**
*************************************************************************
**
** $Id: test_onefile.c,v 1.11 2009/02/10 18:54:03 danielk1977 Exp $
** $Id: test_onefile.c,v 1.12 2009/04/07 11:21:29 danielk1977 Exp $
**
** OVERVIEW:
**
@ -810,7 +810,7 @@ static int fsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
** true, the fs vfs becomes the new default vfs. It is the only publicly
** available function in this file.
*/
int fs_register(){
int fs_register(void){
if( fs_vfs.pParent ) return SQLITE_OK;
fs_vfs.pParent = sqlite3_vfs_find(0);
fs_vfs.base.mxPathname = fs_vfs.pParent->mxPathname;

View File

@ -21,7 +21,7 @@
** This pagecache implementation is designed for simplicity
** not speed.
**
** $Id: test_pcache.c,v 1.2 2009/01/07 03:59:47 drh Exp $
** $Id: test_pcache.c,v 1.3 2009/04/11 11:38:54 drh Exp $
*/
#include "sqlite3.h"
#include <string.h>
@ -75,9 +75,19 @@ static void testpcacheShutdown(void *pArg){
}
/*
** Number of pages in a cache
** Number of pages in a cache.
**
** The number of pages is a hard upper bound in this test module.
** If more pages are requested, sqlite3PcacheFetch() returns NULL.
**
** If testing with in-memory temp tables, provide a larger pcache.
** Some of the test cases need this.
*/
#define TESTPCACHE_NPAGE 217
#if defined(SQLITE_TEMP_STORE) && SQLITE_TEMP_STORE>=2
# define TESTPCACHE_NPAGE 499
#else
# define TESTPCACHE_NPAGE 217
#endif
#define TESTPCACHE_RESERVE 17
/*

View File

@ -14,7 +14,7 @@
** test that sqlite3 database handles may be concurrently accessed by
** multiple threads. Right now this only works on unix.
**
** $Id: test_thread.c,v 1.10 2009/02/03 19:55:20 shane Exp $
** $Id: test_thread.c,v 1.15 2009/03/27 12:32:56 drh Exp $
*/
#include "sqliteInt.h"
@ -55,8 +55,19 @@ struct EvalEvent {
static Tcl_ObjCmdProc sqlthread_proc;
static Tcl_ObjCmdProc clock_seconds_proc;
#if defined(SQLITE_OS_UNIX) && defined(SQLITE_ENABLE_UNLOCK_NOTIFY)
static Tcl_ObjCmdProc blocking_step_proc;
static Tcl_ObjCmdProc blocking_prepare_v2_proc;
#endif
int Sqlitetest1_Init(Tcl_Interp *);
/* Functions from test1.c */
void *sqlite3TestTextToPtr(const char *);
const char *sqlite3TestErrorName(int);
int getDbPointer(Tcl_Interp *, const char *, sqlite3 **);
int sqlite3TestMakePointerStr(Tcl_Interp *, char *, void *);
int sqlite3TestErrCode(Tcl_Interp *, sqlite3 *, int);
/*
** Handler for events of type EvalEvent.
*/
@ -106,6 +117,13 @@ static Tcl_ThreadCreateType tclScriptThread(ClientData pSqlThread){
interp = Tcl_CreateInterp();
Tcl_CreateObjCommand(interp, "clock_seconds", clock_seconds_proc, 0, 0);
Tcl_CreateObjCommand(interp, "sqlthread", sqlthread_proc, pSqlThread, 0);
#if defined(SQLITE_OS_UNIX) && defined(SQLITE_ENABLE_UNLOCK_NOTIFY)
Tcl_CreateObjCommand(interp, "sqlite3_blocking_step", blocking_step_proc,0,0);
Tcl_CreateObjCommand(interp,
"sqlite3_blocking_prepare_v2", blocking_prepare_v2_proc, (void *)1, 0);
Tcl_CreateObjCommand(interp,
"sqlite3_nonblocking_prepare_v2", blocking_prepare_v2_proc, 0, 0);
#endif
Sqlitetest1_Init(interp);
Sqlitetest_mutex_Init(interp);
@ -359,12 +377,248 @@ static int clock_seconds_proc(
return TCL_OK;
}
/*************************************************************************
** This block contains the implementation of the [sqlite3_blocking_step]
** command available to threads created by [sqlthread spawn] commands. It
** is only available on UNIX for now. This is because pthread condition
** variables are used.
**
** The source code for the C functions sqlite3_blocking_step(),
** blocking_step_notify() and the structure UnlockNotification is
** automatically extracted from this file and used as part of the
** documentation for the sqlite3_unlock_notify() API function. This
** should be considered if these functions are to be extended (i.e. to
** support windows) in the future.
*/
#if defined(SQLITE_OS_UNIX) && defined(SQLITE_ENABLE_UNLOCK_NOTIFY)
/* BEGIN_SQLITE_BLOCKING_STEP */
/* This example uses the pthreads API */
#include <pthread.h>
/*
** A pointer to an instance of this structure is passed as the user-context
** pointer when registering for an unlock-notify callback.
*/
typedef struct UnlockNotification UnlockNotification;
struct UnlockNotification {
int fired; /* True after unlock event has occured */
pthread_cond_t cond; /* Condition variable to wait on */
pthread_mutex_t mutex; /* Mutex to protect structure */
};
/*
** This function is an unlock-notify callback registered with SQLite.
*/
static void unlock_notify_cb(void **apArg, int nArg){
int i;
for(i=0; i<nArg; i++){
UnlockNotification *p = (UnlockNotification *)apArg[i];
pthread_mutex_lock(&p->mutex);
p->fired = 1;
pthread_cond_signal(&p->cond);
pthread_mutex_unlock(&p->mutex);
}
}
/*
** This function assumes that an SQLite API call (either sqlite3_prepare_v2()
** or sqlite3_step()) has just returned SQLITE_LOCKED. The argument is the
** associated database connection.
**
** This function calls sqlite3_unlock_notify() to register for an
** unlock-notify callback, then blocks until that callback is delivered
** and returns SQLITE_OK. The caller should then retry the failed operation.
**
** Or, if sqlite3_unlock_notify() indicates that to block would deadlock
** the system, then this function returns SQLITE_LOCKED immediately. In
** this case the caller should not retry the operation and should roll
** back the current transaction (if any).
*/
static int wait_for_unlock_notify(sqlite3 *db){
int rc;
UnlockNotification un;
/* Initialize the UnlockNotification structure. */
un.fired = 0;
pthread_mutex_init(&un.mutex, 0);
pthread_cond_init(&un.cond, 0);
/* Register for an unlock-notify callback. */
rc = sqlite3_unlock_notify(db, unlock_notify_cb, (void *)&un);
assert( rc==SQLITE_LOCKED || rc==SQLITE_OK );
/* The call to sqlite3_unlock_notify() always returns either SQLITE_LOCKED
** or SQLITE_OK.
**
** If SQLITE_LOCKED was returned, then the system is deadlocked. In this
** case this function needs to return SQLITE_LOCKED to the caller so
** that the current transaction can be rolled back. Otherwise, block
** until the unlock-notify callback is invoked, then return SQLITE_OK.
*/
if( rc==SQLITE_OK ){
pthread_mutex_lock(&un.mutex);
if( !un.fired ){
pthread_cond_wait(&un.cond, &un.mutex);
}
pthread_mutex_unlock(&un.mutex);
}
/* Destroy the mutex and condition variables. */
pthread_cond_destroy(&un.cond);
pthread_mutex_destroy(&un.mutex);
return rc;
}
/*
** This function is a wrapper around the SQLite function sqlite3_step().
** It functions in the same way as step(), except that if a required
** shared-cache lock cannot be obtained, this function may block waiting for
** the lock to become available. In this scenario the normal API step()
** function always returns SQLITE_LOCKED.
**
** If this function returns SQLITE_LOCKED, the caller should rollback
** the current transaction (if any) and try again later. Otherwise, the
** system may become deadlocked.
*/
int sqlite3_blocking_step(sqlite3_stmt *pStmt){
int rc;
while( SQLITE_LOCKED==(rc = sqlite3_step(pStmt)) ){
rc = wait_for_unlock_notify(sqlite3_db_handle(pStmt));
if( rc!=SQLITE_OK ) break;
sqlite3_reset(pStmt);
}
return rc;
}
/*
** This function is a wrapper around the SQLite function sqlite3_prepare_v2().
** It functions in the same way as prepare_v2(), except that if a required
** shared-cache lock cannot be obtained, this function may block waiting for
** the lock to become available. In this scenario the normal API prepare_v2()
** function always returns SQLITE_LOCKED.
**
** If this function returns SQLITE_LOCKED, the caller should rollback
** the current transaction (if any) and try again later. Otherwise, the
** system may become deadlocked.
*/
int sqlite3_blocking_prepare_v2(
sqlite3 *db, /* Database handle. */
const char *zSql, /* UTF-8 encoded SQL statement. */
int nSql, /* Length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
const char **pz /* OUT: End of parsed string */
){
int rc;
while( SQLITE_LOCKED==(rc = sqlite3_prepare_v2(db, zSql, nSql, ppStmt, pz)) ){
rc = wait_for_unlock_notify(db);
if( rc!=SQLITE_OK ) break;
}
return rc;
}
/* END_SQLITE_BLOCKING_STEP */
/*
** Usage: sqlite3_blocking_step STMT
**
** Advance the statement to the next row.
*/
static int blocking_step_proc(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
sqlite3_stmt *pStmt;
int rc;
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "STMT");
return TCL_ERROR;
}
pStmt = (sqlite3_stmt*)sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
rc = sqlite3_blocking_step(pStmt);
Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), 0);
return TCL_OK;
}
/*
** Usage: sqlite3_blocking_prepare_v2 DB sql bytes ?tailvar?
** Usage: sqlite3_nonblocking_prepare_v2 DB sql bytes ?tailvar?
*/
static int blocking_prepare_v2_proc(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
sqlite3 *db;
const char *zSql;
int bytes;
const char *zTail = 0;
sqlite3_stmt *pStmt = 0;
char zBuf[50];
int rc;
int isBlocking = !(clientData==0);
if( objc!=5 && objc!=4 ){
Tcl_AppendResult(interp, "wrong # args: should be \"",
Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
return TCL_ERROR;
}
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
zSql = Tcl_GetString(objv[2]);
if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
if( isBlocking ){
rc = sqlite3_blocking_prepare_v2(db, zSql, bytes, &pStmt, &zTail);
}else{
rc = sqlite3_prepare_v2(db, zSql, bytes, &pStmt, &zTail);
}
assert(rc==SQLITE_OK || pStmt==0);
if( zTail && objc>=5 ){
if( bytes>=0 ){
bytes = bytes - (zTail-zSql);
}
Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0);
}
if( rc!=SQLITE_OK ){
assert( pStmt==0 );
sprintf(zBuf, "%s ", (char *)sqlite3TestErrorName(rc));
Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0);
return TCL_ERROR;
}
if( pStmt ){
if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
Tcl_AppendResult(interp, zBuf, 0);
}
return TCL_OK;
}
#endif /* SQLITE_OS_UNIX && SQLITE_ENABLE_UNLOCK_NOTIFY */
/*
** End of implementation of [sqlite3_blocking_step].
************************************************************************/
/*
** Register commands with the TCL interpreter.
*/
int SqlitetestThread_Init(Tcl_Interp *interp){
Tcl_CreateObjCommand(interp, "sqlthread", sqlthread_proc, 0, 0);
Tcl_CreateObjCommand(interp, "clock_seconds", clock_seconds_proc, 0, 0);
#if defined(SQLITE_OS_UNIX) && defined(SQLITE_ENABLE_UNLOCK_NOTIFY)
Tcl_CreateObjCommand(interp, "sqlite3_blocking_step", blocking_step_proc,0,0);
Tcl_CreateObjCommand(interp,
"sqlite3_blocking_prepare_v2", blocking_prepare_v2_proc, (void *)1, 0);
Tcl_CreateObjCommand(interp,
"sqlite3_nonblocking_prepare_v2", blocking_prepare_v2_proc, 0, 0);
#endif
return TCL_OK;
}
#else

View File

@ -14,7 +14,7 @@
** sqlite3_wsd_init() and sqlite3_wsd_find() functions required if the
** SQLITE_OMIT_WSD symbol is defined at build time.
**
** $Id: test_wsd.c,v 1.3 2008/10/07 15:25:49 drh Exp $
** $Id: test_wsd.c,v 1.4 2009/03/23 04:33:33 danielk1977 Exp $
*/
#if defined(SQLITE_OMIT_WSD) && defined(SQLITE_TEST)
@ -69,7 +69,7 @@ void *sqlite3_wsd_find(void *K, int L){
/* If no entry for K was found, create and populate a new one. */
if( !pVar ){
int nByte = (sizeof(ProcessLocalVar) + L + 7)&~7;
int nByte = ROUND8(sizeof(ProcessLocalVar) + L);
assert( pGlobal->nFree>=nByte );
pVar = (ProcessLocalVar *)pGlobal->pFree;
pVar->pKey = K;

View File

@ -15,7 +15,7 @@
** individual tokens and sends those tokens one-by-one over to the
** parser for analysis.
**
** $Id: tokenize.c,v 1.153 2009/01/20 16:53:41 danielk1977 Exp $
** $Id: tokenize.c,v 1.155 2009/03/31 03:41:57 shane Exp $
*/
#include "sqliteInt.h"
#include <stdlib.h>
@ -381,14 +381,17 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
** error message.
*/
int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
int nErr = 0;
int i;
void *pEngine;
int tokenType;
int lastTokenParsed = -1;
sqlite3 *db = pParse->db;
int mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
int nErr = 0; /* Number of errors encountered */
int i; /* Loop counter */
void *pEngine; /* The LEMON-generated LALR(1) parser */
int tokenType; /* type of the next token */
int lastTokenParsed = -1; /* type of the previous token */
u8 enableLookaside; /* Saved value of db->lookaside.bEnabled */
sqlite3 *db = pParse->db; /* The database connection */
int mxSqlLen; /* Max length of an SQL string */
mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
if( db->activeVdbeCnt==0 ){
db->u1.isInterrupted = 0;
}
@ -408,6 +411,8 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
assert( pParse->nVarExpr==0 );
assert( pParse->nVarExprAlloc==0 );
assert( pParse->apVarExpr==0 );
enableLookaside = db->lookaside.bEnabled;
if( db->lookaside.pStart ) db->lookaside.bEnabled = 1;
while( !db->mallocFailed && zSql[i]!=0 ){
assert( i>=0 );
pParse->sLastToken.z = (u8*)&zSql[i];
@ -462,6 +467,7 @@ abort_parse:
);
#endif /* YYDEBUG */
sqlite3ParserFree(pEngine, sqlite3_free);
db->lookaside.bEnabled = enableLookaside;
if( db->mallocFailed ){
pParse->rc = SQLITE_NOMEM;
}

View File

@ -10,7 +10,7 @@
*************************************************************************
**
**
** $Id: trigger.c,v 1.133 2008/12/26 07:56:39 danielk1977 Exp $
** $Id: trigger.c,v 1.135 2009/02/28 10:47:42 danielk1977 Exp $
*/
#include "sqliteInt.h"
@ -33,6 +33,30 @@ void sqlite3DeleteTriggerStep(sqlite3 *db, TriggerStep *pTriggerStep){
}
}
/*
** Given table pTab, return a list of all the triggers attached to
** the table. The list is connected by Trigger.pNext pointers.
*/
Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){
Schema * const pTmpSchema = pParse->db->aDb[1].pSchema;
Trigger *pList = 0; /* List of triggers to return */
if( pTmpSchema!=pTab->pSchema ){
HashElem *p;
for(p=sqliteHashFirst(&pTmpSchema->trigHash); p; p=sqliteHashNext(p)){
Trigger *pTrig = (Trigger *)sqliteHashData(p);
if( pTrig->pTabSchema==pTab->pSchema
&& 0==sqlite3StrICmp(pTrig->table, pTab->zName)
){
pTrig->pNext = (pList ? pList : pTab->pTrigger);
pList = pTrig;
}
}
}
return (pList ? pList : pTab->pTrigger);
}
/*
** This is called by the parser when it sees a CREATE TRIGGER statement
** up to the point of the BEGIN before the trigger actions. A Trigger
@ -182,7 +206,7 @@ void sqlite3BeginTrigger(
pTrigger->pTabSchema = pTab->pSchema;
pTrigger->op = (u8)op;
pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER;
pTrigger->pWhen = sqlite3ExprDup(db, pWhen);
pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE);
pTrigger->pColumns = sqlite3IdListDup(db, pColumns);
sqlite3TokenCopy(db, &pTrigger->nameToken,pName);
assert( pParse->pNewTrigger==0 );
@ -209,14 +233,16 @@ void sqlite3FinishTrigger(
TriggerStep *pStepList, /* The triggered program */
Token *pAll /* Token that describes the complete CREATE TRIGGER */
){
Trigger *pTrig = 0; /* The trigger whose construction is finishing up */
sqlite3 *db = pParse->db; /* The database */
Trigger *pTrig = pParse->pNewTrigger; /* Trigger being finished */
char *zName; /* Name of trigger */
sqlite3 *db = pParse->db; /* The database */
DbFixer sFix;
int iDb; /* Database containing the trigger */
int iDb; /* Database containing the trigger */
pTrig = pParse->pNewTrigger;
pParse->pNewTrigger = 0;
if( pParse->nErr || !pTrig ) goto triggerfinish_cleanup;
zName = pTrig->name;
iDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema);
pTrig->step_list = pStepList;
while( pStepList ){
@ -242,32 +268,29 @@ void sqlite3FinishTrigger(
z = sqlite3DbStrNDup(db, (char*)pAll->z, pAll->n);
sqlite3NestedParse(pParse,
"INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')",
db->aDb[iDb].zName, SCHEMA_TABLE(iDb), pTrig->name,
db->aDb[iDb].zName, SCHEMA_TABLE(iDb), zName,
pTrig->table, z);
sqlite3DbFree(db, z);
sqlite3ChangeCookie(pParse, iDb);
sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 0, 0, sqlite3MPrintf(
db, "type='trigger' AND name='%q'", pTrig->name), P4_DYNAMIC
db, "type='trigger' AND name='%q'", zName), P4_DYNAMIC
);
}
if( db->init.busy ){
int n;
Table *pTab;
Trigger *pDel;
pDel = sqlite3HashInsert(&db->aDb[iDb].pSchema->trigHash,
pTrig->name, sqlite3Strlen30(pTrig->name), pTrig);
if( pDel ){
assert( pDel==pTrig );
Trigger *pLink = pTrig;
Hash *pHash = &db->aDb[iDb].pSchema->trigHash;
pTrig = sqlite3HashInsert(pHash, zName, sqlite3Strlen30(zName), pTrig);
if( pTrig ){
db->mallocFailed = 1;
goto triggerfinish_cleanup;
}else if( pLink->pSchema==pLink->pTabSchema ){
Table *pTab;
int n = sqlite3Strlen30(pLink->table) + 1;
pTab = sqlite3HashFind(&pLink->pTabSchema->tblHash, pLink->table, n);
assert( pTab!=0 );
pLink->pNext = pTab->pTrigger;
pTab->pTrigger = pLink;
}
n = sqlite3Strlen30(pTrig->table) + 1;
pTab = sqlite3HashFind(&pTrig->pTabSchema->tblHash, pTrig->table, n);
assert( pTab!=0 );
pTrig->pNext = pTab->pTrigger;
pTab->pTrigger = pTrig;
pTrig = 0;
}
triggerfinish_cleanup:
@ -292,17 +315,17 @@ static void sqlitePersistTriggerStep(sqlite3 *db, TriggerStep *p){
p->target.dyn = 1;
}
if( p->pSelect ){
Select *pNew = sqlite3SelectDup(db, p->pSelect);
Select *pNew = sqlite3SelectDup(db, p->pSelect, 1);
sqlite3SelectDelete(db, p->pSelect);
p->pSelect = pNew;
}
if( p->pWhere ){
Expr *pNew = sqlite3ExprDup(db, p->pWhere);
Expr *pNew = sqlite3ExprDup(db, p->pWhere, EXPRDUP_REDUCE);
sqlite3ExprDelete(db, p->pWhere);
p->pWhere = pNew;
}
if( p->pExprList ){
ExprList *pNew = sqlite3ExprListDup(db, p->pExprList);
ExprList *pNew = sqlite3ExprListDup(db, p->pExprList, 1);
sqlite3ExprListDelete(db, p->pExprList);
p->pExprList = pNew;
}
@ -546,6 +569,9 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
sqlite3ChangeCookie(pParse, iDb);
sqlite3VdbeAddOp2(v, OP_Close, 0, 0);
sqlite3VdbeAddOp4(v, OP_DropTrigger, iDb, 0, 0, pTrigger->name, 0);
if( pParse->nMem<3 ){
pParse->nMem = 3;
}
}
}
@ -553,25 +579,15 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
** Remove a trigger from the hash tables of the sqlite* pointer.
*/
void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){
Hash *pHash = &(db->aDb[iDb].pSchema->trigHash);
Trigger *pTrigger;
int nName = sqlite3Strlen30(zName);
pTrigger = sqlite3HashInsert(&(db->aDb[iDb].pSchema->trigHash),
zName, nName, 0);
pTrigger = sqlite3HashInsert(pHash, zName, sqlite3Strlen30(zName), 0);
if( pTrigger ){
Table *pTable = tableOfTrigger(pTrigger);
assert( pTable!=0 );
if( pTable->pTrigger == pTrigger ){
pTable->pTrigger = pTrigger->pNext;
}else{
Trigger *cc = pTable->pTrigger;
while( cc ){
if( cc->pNext == pTrigger ){
cc->pNext = cc->pNext->pNext;
break;
}
cc = cc->pNext;
}
assert(cc);
if( pTrigger->pSchema==pTrigger->pTabSchema ){
Table *pTab = tableOfTrigger(pTrigger);
Trigger **pp;
for(pp=&pTab->pTrigger; *pp!=pTrigger; pp=&((*pp)->pNext));
*pp = (*pp)->pNext;
}
sqlite3DeleteTrigger(db, pTrigger);
db->flags |= SQLITE_InternChanges;
@ -597,30 +613,31 @@ static int checkColumnOverLap(IdList *pIdList, ExprList *pEList){
}
/*
** Return a bit vector to indicate what kind of triggers exist for operation
** "op" on table pTab. If pChanges is not NULL then it is a list of columns
** that are being updated. Triggers only match if the ON clause of the
** trigger definition overlaps the set of columns being updated.
**
** The returned bit vector is some combination of TRIGGER_BEFORE and
** TRIGGER_AFTER.
** Return a list of all triggers on table pTab if there exists at least
** one trigger that must be fired when an operation of type 'op' is
** performed on the table, and, if that operation is an UPDATE, if at
** least one of the columns in pChanges is being modified.
*/
int sqlite3TriggersExist(
Trigger *sqlite3TriggersExist(
Parse *pParse, /* Parse context */
Table *pTab, /* The table the contains the triggers */
int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */
ExprList *pChanges /* Columns that change in an UPDATE statement */
ExprList *pChanges, /* Columns that change in an UPDATE statement */
int *pMask /* OUT: Mask of TRIGGER_BEFORE|TRIGGER_AFTER */
){
Trigger *pTrigger;
int mask = 0;
pTrigger = IsVirtual(pTab) ? 0 : pTab->pTrigger;
while( pTrigger ){
if( pTrigger->op==op && checkColumnOverLap(pTrigger->pColumns, pChanges) ){
mask |= pTrigger->tr_tm;
Trigger *pList = sqlite3TriggerList(pParse, pTab);
Trigger *p;
assert( pList==0 || IsVirtual(pTab)==0 );
for(p=pList; p; p=p->pNext){
if( p->op==op && checkColumnOverLap(p->pColumns, pChanges) ){
mask |= p->tr_tm;
}
pTrigger = pTrigger->pNext;
}
return mask;
if( pMask ){
*pMask = mask;
}
return (mask ? pList : 0);
}
/*
@ -677,7 +694,7 @@ static int codeTriggerProgram(
pParse->trigStack->orconf = orconf;
switch( pTriggerStep->op ){
case TK_SELECT: {
Select *ss = sqlite3SelectDup(db, pTriggerStep->pSelect);
Select *ss = sqlite3SelectDup(db, pTriggerStep->pSelect, 0);
if( ss ){
SelectDest dest;
@ -692,8 +709,8 @@ static int codeTriggerProgram(
pSrc = targetSrcList(pParse, pTriggerStep);
sqlite3VdbeAddOp2(v, OP_ResetCount, 0, 0);
sqlite3Update(pParse, pSrc,
sqlite3ExprListDup(db, pTriggerStep->pExprList),
sqlite3ExprDup(db, pTriggerStep->pWhere), orconf);
sqlite3ExprListDup(db, pTriggerStep->pExprList, 0),
sqlite3ExprDup(db, pTriggerStep->pWhere, 0), orconf);
sqlite3VdbeAddOp2(v, OP_ResetCount, 1, 0);
break;
}
@ -702,8 +719,8 @@ static int codeTriggerProgram(
pSrc = targetSrcList(pParse, pTriggerStep);
sqlite3VdbeAddOp2(v, OP_ResetCount, 0, 0);
sqlite3Insert(pParse, pSrc,
sqlite3ExprListDup(db, pTriggerStep->pExprList),
sqlite3SelectDup(db, pTriggerStep->pSelect),
sqlite3ExprListDup(db, pTriggerStep->pExprList, 0),
sqlite3SelectDup(db, pTriggerStep->pSelect, 0),
sqlite3IdListDup(db, pTriggerStep->pIdList), orconf);
sqlite3VdbeAddOp2(v, OP_ResetCount, 1, 0);
break;
@ -713,7 +730,7 @@ static int codeTriggerProgram(
sqlite3VdbeAddOp2(v, OP_ResetCount, 0, 0);
pSrc = targetSrcList(pParse, pTriggerStep);
sqlite3DeleteFrom(pParse, pSrc,
sqlite3ExprDup(db, pTriggerStep->pWhere));
sqlite3ExprDup(db, pTriggerStep->pWhere, 0));
sqlite3VdbeAddOp2(v, OP_ResetCount, 1, 0);
break;
}
@ -757,6 +774,7 @@ static int codeTriggerProgram(
*/
int sqlite3CodeRowTrigger(
Parse *pParse, /* Parse context */
Trigger *pTrigger, /* List of triggers on table pTab */
int op, /* One of TK_UPDATE, TK_INSERT, TK_DELETE */
ExprList *pChanges, /* Changes list for any UPDATE OF triggers */
int tr_tm, /* One of TRIGGER_BEFORE, TRIGGER_AFTER */
@ -780,7 +798,7 @@ int sqlite3CodeRowTrigger(
assert(newIdx != -1 || oldIdx != -1);
for(p=pTab->pTrigger; p; p=p->pNext){
for(p=pTrigger; p; p=p->pNext){
int fire_this = 0;
/* Determine whether we should code this trigger */
@ -830,7 +848,7 @@ int sqlite3CodeRowTrigger(
/* code the WHEN clause */
endTrigger = sqlite3VdbeMakeLabel(pParse->pVdbe);
whenExpr = sqlite3ExprDup(db, p->pWhen);
whenExpr = sqlite3ExprDup(db, p->pWhen, 0);
if( db->mallocFailed || sqlite3ResolveExprNames(&sNC, whenExpr) ){
pParse->trigStack = trigStackEntry.pNext;
sqlite3ExprDelete(db, whenExpr);

View File

@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
**
** $Id: update.c,v 1.191 2008/12/23 23:56:22 drh Exp $
** $Id: update.c,v 1.196 2009/02/28 10:47:42 danielk1977 Exp $
*/
#include "sqliteInt.h"
@ -107,7 +107,7 @@ void sqlite3Update(
#ifndef SQLITE_OMIT_TRIGGER
int isView; /* Trying to update a view */
int triggers_exist = 0; /* True if any row triggers exist */
Trigger *pTrigger; /* List of triggers on pTab, if required */
#endif
int iBeginAfterTrigger = 0; /* Address of after trigger program */
int iEndAfterTrigger = 0; /* Exit of after trigger program */
@ -143,10 +143,10 @@ void sqlite3Update(
** updated is a view
*/
#ifndef SQLITE_OMIT_TRIGGER
triggers_exist = sqlite3TriggersExist(pTab, TK_UPDATE, pChanges);
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_UPDATE, pChanges, 0);
isView = pTab->pSelect!=0;
#else
# define triggers_exist 0
# define pTrigger 0
# define isView 0
#endif
#ifdef SQLITE_OMIT_VIEW
@ -154,7 +154,7 @@ void sqlite3Update(
# define isView 0
#endif
if( sqlite3IsReadOnly(pParse, pTab, triggers_exist) ){
if( sqlite3IsReadOnly(pParse, pTab, (pTrigger?1:0)) ){
goto update_cleanup;
}
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
@ -167,7 +167,7 @@ void sqlite3Update(
/* If there are FOR EACH ROW triggers, allocate cursors for the
** special OLD and NEW tables
*/
if( triggers_exist ){
if( pTrigger ){
newIdx = pParse->nTab++;
oldIdx = pParse->nTab++;
}
@ -299,27 +299,27 @@ void sqlite3Update(
/* Generate the code for triggers.
*/
if( triggers_exist ){
if( pTrigger ){
int iGoto;
/* Create pseudo-tables for NEW and OLD
*/
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, pTab->nCol);
sqlite3VdbeAddOp2(v, OP_OpenPseudo, oldIdx, 0);
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, pTab->nCol);
sqlite3VdbeAddOp2(v, OP_OpenPseudo, newIdx, 0);
sqlite3VdbeAddOp3(v, OP_OpenPseudo, oldIdx, 0, pTab->nCol);
sqlite3VdbeAddOp3(v, OP_OpenPseudo, newIdx, 0, pTab->nCol);
iGoto = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
addr = sqlite3VdbeMakeLabel(v);
iBeginBeforeTrigger = sqlite3VdbeCurrentAddr(v);
if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TRIGGER_BEFORE, pTab,
newIdx, oldIdx, onError, addr, &old_col_mask, &new_col_mask) ){
if( sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges,
TRIGGER_BEFORE, pTab, newIdx, oldIdx, onError, addr,
&old_col_mask, &new_col_mask) ){
goto update_cleanup;
}
iEndBeforeTrigger = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
iBeginAfterTrigger = sqlite3VdbeCurrentAddr(v);
if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TRIGGER_AFTER, pTab,
newIdx, oldIdx, onError, addr, &old_col_mask, &new_col_mask) ){
if( sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges,
TRIGGER_AFTER, pTab, newIdx, oldIdx, onError, addr,
&old_col_mask, &new_col_mask) ){
goto update_cleanup;
}
iEndAfterTrigger = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
@ -399,7 +399,7 @@ void sqlite3Update(
}
/* Jump back to this point if a trigger encounters an IGNORE constraint. */
if( triggers_exist ){
if( pTrigger ){
sqlite3VdbeResolveLabel(v, addr);
}
@ -412,7 +412,7 @@ void sqlite3Update(
addr = sqlite3VdbeAddOp3(v, OP_RowSetRead, regRowSet, 0, regOldRowid);
}
if( triggers_exist ){
if( pTrigger ){
int regRowid;
int regRow;
int regCols;
@ -541,7 +541,7 @@ void sqlite3Update(
/* If there are triggers, close all the cursors after each iteration
** through the loop. The fire the after triggers.
*/
if( triggers_exist ){
if( pTrigger ){
sqlite3VdbeAddOp2(v, OP_Goto, 0, iBeginAfterTrigger);
sqlite3VdbeJumpHere(v, iEndAfterTrigger);
}
@ -559,7 +559,7 @@ void sqlite3Update(
}
}
sqlite3VdbeAddOp2(v, OP_Close, iCur, 0);
if( triggers_exist ){
if( pTrigger ){
sqlite3VdbeAddOp2(v, OP_Close, newIdx, 0);
sqlite3VdbeAddOp2(v, OP_Close, oldIdx, 0);
}
@ -633,12 +633,12 @@ static void updateVirtualTable(
sqlite3CreateIdExpr(pParse, "_rowid_"), 0);
if( pRowid ){
pEList = sqlite3ExprListAppend(pParse, pEList,
sqlite3ExprDup(db, pRowid), 0);
sqlite3ExprDup(db, pRowid, 0), 0);
}
assert( pTab->iPKey<0 );
for(i=0; i<pTab->nCol; i++){
if( aXRef[i]>=0 ){
pExpr = sqlite3ExprDup(db, pChanges->a[aXRef[i]].pExpr);
pExpr = sqlite3ExprDup(db, pChanges->a[aXRef[i]].pExpr, 0);
}else{
pExpr = sqlite3CreateIdExpr(pParse, pTab->aCol[i].zName);
}

View File

@ -12,7 +12,7 @@
** This file contains routines used to translate between UTF-8,
** UTF-16, UTF-16BE, and UTF-16LE.
**
** $Id: utf.c,v 1.70 2008/12/10 22:30:25 shane Exp $
** $Id: utf.c,v 1.73 2009/04/01 18:40:32 drh Exp $
**
** Notes on UTF-8:
**
@ -110,22 +110,20 @@ static const unsigned char sqlite3Utf8Trans1[] = {
#define READ_UTF16LE(zIn, c){ \
c = (*zIn++); \
c += ((*zIn++)<<8); \
if( c>=0xD800 && c<0xE000 ){ \
if( c>=0xD800 && c<0xE000 ){ \
int c2 = (*zIn++); \
c2 += ((*zIn++)<<8); \
c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \
if( (c & 0xFFFF0000)==0 ) c = 0xFFFD; \
} \
}
#define READ_UTF16BE(zIn, c){ \
c = ((*zIn++)<<8); \
c += (*zIn++); \
if( c>=0xD800 && c<0xE000 ){ \
if( c>=0xD800 && c<0xE000 ){ \
int c2 = ((*zIn++)<<8); \
c2 += (*zIn++); \
c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \
if( (c & 0xFFFF0000)==0 ) c = 0xFFFD; \
} \
}
@ -168,13 +166,25 @@ static const unsigned char sqlite3Utf8Trans1[] = {
|| (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \
}
int sqlite3Utf8Read(
const unsigned char *z, /* First byte of UTF-8 character */
const unsigned char *zTerm, /* Pretend this byte is 0x00 */
const unsigned char *zIn, /* First byte of UTF-8 character */
const unsigned char **pzNext /* Write first byte past UTF-8 char here */
){
int c;
READ_UTF8(z, zTerm, c);
*pzNext = z;
/* Same as READ_UTF8() above but without the zTerm parameter.
** For this routine, we assume the UTF8 string is always zero-terminated.
*/
c = *(zIn++);
if( c>=0xc0 ){
c = sqlite3Utf8Trans1[c-0xc0];
while( (*zIn & 0xc0)==0x80 ){
c = (c<<6) + (0x3f & *(zIn++));
}
if( c<0x80
|| (c&0xFFFFF800)==0xD800
|| (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; }
}
*pzNext = zIn;
return c;
}
@ -341,7 +351,8 @@ int sqlite3VdbeMemHandleBom(Mem *pMem){
int rc = SQLITE_OK;
u8 bom = 0;
if( pMem->n<0 || pMem->n>1 ){
assert( pMem->n>=0 );
if( pMem->n>1 ){
u8 b1 = *(u8 *)pMem->z;
u8 b2 = *(((u8 *)pMem->z) + 1);
if( b1==0xFE && b2==0xFF ){
@ -407,17 +418,16 @@ int sqlite3Utf8CharLen(const char *zIn, int nByte){
int sqlite3Utf8To8(unsigned char *zIn){
unsigned char *zOut = zIn;
unsigned char *zStart = zIn;
unsigned char *zTerm = &zIn[sqlite3Strlen30((char *)zIn)];
u32 c;
while( zIn[0] ){
c = sqlite3Utf8Read(zIn, zTerm, (const u8**)&zIn);
c = sqlite3Utf8Read(zIn, (const u8**)&zIn);
if( c!=0xfffd ){
WRITE_UTF8(zOut, c);
}
}
*zOut = 0;
return zOut - zStart;
return (int)(zOut - zStart);
}
#endif
@ -445,15 +455,13 @@ char *sqlite3Utf16to8(sqlite3 *db, const void *z, int nByte){
}
/*
** pZ is a UTF-16 encoded unicode string. If nChar is less than zero,
** return the number of bytes up to (but not including), the first pair
** of consecutive 0x00 bytes in pZ. If nChar is not less than zero,
** then return the number of bytes in the first nChar unicode characters
** in pZ (or up until the first pair of 0x00 bytes, whichever comes first).
** pZ is a UTF-16 encoded unicode string at least nChar characters long.
** Return the number of bytes in the first nChar unicode characters
** in pZ. nChar must be non-negative.
*/
int sqlite3Utf16ByteLen(const void *zIn, int nChar){
unsigned int c = 1;
char const *z = zIn;
int c;
unsigned char const *z = zIn;
int n = 0;
if( SQLITE_UTF16NATIVE==SQLITE_UTF16BE ){
/* Using an "if (SQLITE_UTF16NATIVE==SQLITE_UTF16BE)" construct here
@ -465,17 +473,17 @@ int sqlite3Utf16ByteLen(const void *zIn, int nChar){
** which branch will be followed. It is therefore assumed that no runtime
** penalty is paid for this "if" statement.
*/
while( c && ((nChar<0) || n<nChar) ){
while( n<nChar ){
READ_UTF16BE(z, c);
n++;
}
}else{
while( c && ((nChar<0) || n<nChar) ){
while( n<nChar ){
READ_UTF16LE(z, c);
n++;
}
}
return (int)(z-(char const *)zIn)-((c==0)?2:0);
return (int)(z-(unsigned char const *)zIn);
}
#if defined(SQLITE_TEST)
@ -488,7 +496,6 @@ void sqlite3UtfSelfTest(void){
unsigned int i, t;
unsigned char zBuf[20];
unsigned char *z;
unsigned char *zTerm;
int n;
unsigned int c;
@ -498,9 +505,8 @@ void sqlite3UtfSelfTest(void){
n = (int)(z-zBuf);
assert( n>0 && n<=4 );
z[0] = 0;
zTerm = z;
z = zBuf;
c = sqlite3Utf8Read(z, zTerm, (const u8**)&z);
c = sqlite3Utf8Read(z, (const u8**)&z);
t = i;
if( i>=0xD800 && i<=0xDFFF ) t = 0xFFFD;
if( (i&0xFFFFFFFE)==0xFFFE ) t = 0xFFFD;

View File

@ -14,7 +14,7 @@
** This file contains functions for allocating memory, comparing
** strings, and stuff like that.
**
** $Id: util.c,v 1.248 2009/02/04 03:59:25 shane Exp $
** $Id: util.c,v 1.249 2009/03/01 22:29:20 drh Exp $
*/
#include "sqliteInt.h"
#include <stdarg.h>
@ -694,7 +694,7 @@ u8 sqlite3GetVarint(const unsigned char *p, u64 *v){
/* a: p2<<28 | p4<<14 | p6 (unmasked) */
if (!(a&0x80))
{
a &= (0x7f<<28)|(0x7f<<14)|(0x7f);
a &= (0x1f<<28)|(0x7f<<14)|(0x7f);
b &= (0x7f<<14)|(0x7f);
b = b<<7;
a |= b;
@ -711,7 +711,7 @@ u8 sqlite3GetVarint(const unsigned char *p, u64 *v){
/* b: p3<<28 | p5<<14 | p7 (unmasked) */
if (!(b&0x80))
{
b &= (0x7f<<28)|(0x7f<<14)|(0x7f);
b &= (0x1f<<28)|(0x7f<<14)|(0x7f);
/* moved CSE2 up */
/* a &= (0x7f<<14)|(0x7f); */
a = a<<7;
@ -806,8 +806,8 @@ u8 sqlite3GetVarint32(const unsigned char *p, u32 *v){
/* a: p0<<28 | p2<<14 | p4 (unmasked) */
if (!(a&0x80))
{
a &= (0x7f<<28)|(0x7f<<14)|(0x7f);
b &= (0x7f<<28)|(0x7f<<14)|(0x7f);
a &= (0x1f<<28)|(0x7f<<14)|(0x7f);
b &= (0x1f<<28)|(0x7f<<14)|(0x7f);
b = b<<7;
*v = a | b;
return 5;

View File

@ -14,7 +14,7 @@
** Most of the code in this file may be omitted by defining the
** SQLITE_OMIT_VACUUM macro.
**
** $Id: vacuum.c,v 1.86 2009/02/03 16:51:25 danielk1977 Exp $
** $Id: vacuum.c,v 1.87 2009/04/02 20:16:59 drh Exp $
*/
#include "sqliteInt.h"
#include "vdbeInt.h"
@ -140,8 +140,8 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
}
#endif
if( sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain), nRes)
|| (!isMemDb && sqlite3BtreeSetPageSize(pTemp, db->nextPagesize, nRes))
if( sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain), nRes, 0)
|| (!isMemDb && sqlite3BtreeSetPageSize(pTemp, db->nextPagesize, nRes, 0))
|| db->mallocFailed
){
rc = SQLITE_NOMEM;
@ -268,7 +268,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
}
if( rc==SQLITE_OK ){
rc = sqlite3BtreeSetPageSize(pMain, sqlite3BtreeGetPageSize(pTemp), nRes);
rc = sqlite3BtreeSetPageSize(pMain, sqlite3BtreeGetPageSize(pTemp), nRes,1);
}
end_of_vacuum:

View File

@ -43,7 +43,7 @@
** in this file for details. If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.817 2009/02/16 17:55:47 shane Exp $
** $Id: vdbe.c,v 1.832 2009/04/10 12:55:17 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "vdbeInt.h"
@ -187,7 +187,7 @@ int sqlite3VdbeOpcodeHasProperty(int opcode, int mask){
static VdbeCursor *allocateCursor(
Vdbe *p, /* The virtual machine */
int iCur, /* Index of the new VdbeCursor */
Op *pOp, /* */
int nField, /* Number of fields in the table or index */
int iDb, /* When database the cursor belongs to, or -1 */
int isBtreeCursor /* */
){
@ -213,15 +213,6 @@ static VdbeCursor *allocateCursor(
int nByte;
VdbeCursor *pCx = 0;
/* If the opcode of pOp is OP_SetNumColumns, then pOp->p2 contains
** the number of fields in the records contained in the table or
** index being opened. Use this to reserve space for the
** VdbeCursor.aType[] array.
*/
int nField = 0;
if( pOp->opcode==OP_SetNumColumns || pOp->opcode==OP_OpenEphemeral ){
nField = pOp->p2;
}
nByte =
sizeof(VdbeCursor) +
(isBtreeCursor?sqlite3BtreeCursorSize():0) +
@ -563,7 +554,7 @@ int sqlite3VdbeExec(
Mem *pOut = 0; /* Output operand */
u8 opProperty;
int iCompare = 0; /* Result of last OP_Compare operation */
int *aPermute = 0; /* Permuation of columns for OP_Compare */
int *aPermute = 0; /* Permutation of columns for OP_Compare */
#ifdef VDBE_PROFILE
u64 start; /* CPU clock count at start of opcode */
int origPc; /* Program counter at start of opcode */
@ -571,11 +562,13 @@ int sqlite3VdbeExec(
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
int nProgressOps = 0; /* Opcodes executed since progress callback. */
#endif
UnpackedRecord aTempRec[16]; /* Space to hold a transient UnpackedRecord */
/* Temporary space into which to unpack a record. */
char aTempRec[ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*3 + 7];
assert( p->magic==VDBE_MAGIC_RUN ); /* sqlite3_step() verifies this */
assert( db->magic==SQLITE_MAGIC_BUSY );
sqlite3BtreeMutexArrayEnter(&p->aMutex);
sqlite3VdbeMutexArrayEnter(p);
if( p->rc==SQLITE_NOMEM ){
/* This happens if a malloc() inside a call to sqlite3_column_text() or
** sqlite3_column_text16() failed. */
@ -819,6 +812,16 @@ case OP_Yield: { /* in1 */
break;
}
/* Opcode: HaltIfNull P1 P2 P3 P4 *
**
** Check the value in register P3. If is is NULL then Halt using
** parameter P1, P2, and P4 as if this were a Halt instruction. If the
** value in register P3 is not NULL, then this routine is a no-op.
*/
case OP_HaltIfNull: { /* in3 */
if( (pIn3->flags & MEM_Null)==0 ) break;
/* Fall through into OP_Halt */
}
/* Opcode: Halt P1 P2 * P4 *
**
@ -967,26 +970,34 @@ case OP_Blob: { /* out2-prerelease */
break;
}
/* Opcode: Variable P1 P2 * * *
/* Opcode: Variable P1 P2 P3 P4 *
**
** The value of variable P1 is written into register P2. A variable is
** an unknown in the original SQL string as handed to sqlite3_compile().
** Any occurrence of the '?' character in the original SQL is considered
** a variable. Variables in the SQL string are number from left to
** right beginning with 1. The values of variables are set using the
** sqlite3_bind() API.
** Transfer the values of bound parameters P1..P1+P3-1 into registers
** P2..P2+P3-1.
**
** If the parameter is named, then its name appears in P4 and P3==1.
** The P4 value is used by sqlite3_bind_parameter_name().
*/
case OP_Variable: { /* out2-prerelease */
case OP_Variable: {
int j = pOp->p1 - 1;
int k = pOp->p2;
Mem *pVar;
assert( j>=0 && j<p->nVar );
int n = pOp->p3;
assert( j>=0 && j+n<=p->nVar );
assert( k>=1 && k+n-1<=p->nMem );
assert( pOp->p4.z==0 || pOp->p3==1 );
pVar = &p->aVar[j];
if( sqlite3VdbeMemTooBig(pVar) ){
goto too_big;
while( n-- > 0 ){
pVar = &p->aVar[j++];
if( sqlite3VdbeMemTooBig(pVar) ){
goto too_big;
}
pOut = &p->aMem[k++];
sqlite3VdbeMemReleaseExternal(pOut);
pOut->flags = MEM_Null;
sqlite3VdbeMemShallowCopy(pOut, pVar, MEM_Static);
UPDATE_MAX_BLOBSIZE(pOut);
}
sqlite3VdbeMemShallowCopy(pOut, &p->aVar[j], MEM_Static);
UPDATE_MAX_BLOBSIZE(pOut);
break;
}
@ -1002,15 +1013,14 @@ case OP_Move: {
int n = pOp->p3;
int p1 = pOp->p1;
int p2 = pOp->p2;
assert( n>0 );
assert( p1>0 );
assert( p1+n<p->nMem );
pIn1 = &p->aMem[p1];
assert( p2>0 );
assert( p2+n<p->nMem );
pOut = &p->aMem[p2];
assert( n>0 && p1>0 && p2>0 );
assert( p1+n<=p2 || p2+n<=p1 );
pIn1 = &p->aMem[p1];
pOut = &p->aMem[p2];
while( n-- ){
assert( pOut<=&p->aMem[p->nMem] );
assert( pIn1<=&p->aMem[p->nMem] );
zMalloc = pOut->zMalloc;
pOut->zMalloc = 0;
sqlite3VdbeMemMove(pOut, pIn1);
@ -1076,7 +1086,24 @@ case OP_ResultRow: {
int i;
assert( p->nResColumn==pOp->p2 );
assert( pOp->p1>0 );
assert( pOp->p1+pOp->p2<=p->nMem );
assert( pOp->p1+pOp->p2<=p->nMem+1 );
/* If the SQLITE_CountRows flag is set in sqlite3.flags mask, then
** DML statements invoke this opcode to return the number of rows
** modified to the user. This is the only way that a VM that
** opens a statement transaction may invoke this opcode.
**
** In case this is such a statement, close any statement transaction
** opened by this VM before returning control to the user. This is to
** ensure that statement-transactions are always nested, not overlapping.
** If the open statement-transaction is not closed here, then the user
** may step another VM that opens its own statement transaction. This
** may lead to overlapping statement transactions.
*/
assert( p->iStatement==0 || db->flags&SQLITE_CountRows );
if( SQLITE_OK!=(rc = sqlite3VdbeCloseStatement(p, SAVEPOINT_RELEASE)) ){
break;
}
/* Invalidate all ephemeral cursor row caches */
p->cacheCtr = (p->cacheCtr + 2)|1;
@ -1095,7 +1122,6 @@ case OP_ResultRow: {
/* Return SQLITE_ROW
*/
p->nCallback++;
p->pc = pc + 1;
rc = SQLITE_ROW;
goto vdbe_return;
@ -1300,7 +1326,7 @@ case OP_Function: {
apVal = p->apArg;
assert( apVal || n==0 );
assert( n==0 || (pOp->p2>0 && pOp->p2+n<=p->nMem) );
assert( n==0 || (pOp->p2>0 && pOp->p2+n<=p->nMem+1) );
assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n );
pArg = &p->aMem[pOp->p2];
for(i=0; i<n; i++, pArg++){
@ -1701,7 +1727,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
/* Opcode: Permutation * * * P4 *
**
** Set the permuation used by the OP_Compare operator to be the array
** Set the permutation used by the OP_Compare operator to be the array
** of integers in P4.
**
** The permutation is only valid until the next OP_Permutation, OP_Compare,
@ -1736,9 +1762,9 @@ case OP_Compare: {
assert( n>0 );
assert( pKeyInfo!=0 );
p1 = pOp->p1;
assert( p1>0 && p1+n-1<p->nMem );
assert( p1>0 && p1+n<=p->nMem+1 );
p2 = pOp->p2;
assert( p2>0 && p2+n-1<p->nMem );
assert( p2>0 && p2+n<=p->nMem+1 );
for(i=0; i<n; i++){
int idx = aPermute ? aPermute[i] : i;
CollSeq *pColl; /* Collating sequence to use on this term */
@ -1932,9 +1958,11 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */
** this opcode must be present immediately before the opcode that
** opens the cursor.
*/
#if 0
case OP_SetNumColumns: {
break;
}
#endif
/* Opcode: Column P1 P2 P3 P4 *
**
@ -2253,7 +2281,7 @@ case OP_MakeRecord: {
nField = pOp->p1;
zAffinity = pOp->p4.z;
assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=p->nMem );
assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=p->nMem+1 );
pData0 = &p->aMem[nField];
nField = pOp->p2;
pLast = &pData0[nField-1];
@ -2330,6 +2358,26 @@ case OP_MakeRecord: {
break;
}
/* Opcode: Count P1 P2 * * *
**
** Store the number of entries (an integer value) in the table or index
** opened by cursor P1 in register P2
*/
#ifndef SQLITE_OMIT_BTREECOUNT
case OP_Count: { /* out2-prerelease */
i64 nEntry;
BtCursor *pCrsr = p->apCsr[pOp->p1]->pCursor;
if( pCrsr ){
rc = sqlite3BtreeCount(pCrsr, &nEntry);
}else{
nEntry = 0;
}
pOut->flags = MEM_Int;
pOut->u.i = nEntry;
break;
}
#endif
/* Opcode: Statement P1 * * * *
**
** Begin an individual statement transaction which is part of a larger
@ -2361,10 +2409,12 @@ case OP_Statement: {
pBt = db->aDb[i].pBt;
assert( sqlite3BtreeIsInTrans(pBt) );
assert( (p->btreeMask & (1<<i))!=0 );
if( !sqlite3BtreeIsInStmt(pBt) ){
rc = sqlite3BtreeBeginStmt(pBt);
p->openedStatement = 1;
if( p->iStatement==0 ){
assert( db->nStatement>=0 && db->nSavepoint>=0 );
db->nStatement++;
p->iStatement = db->nSavepoint + db->nStatement;
}
rc = sqlite3BtreeBeginStmt(pBt, p->iStatement);
}
break;
}
@ -2471,7 +2521,7 @@ case OP_Savepoint: {
rc = sqlite3BtreeSavepoint(db->aDb[ii].pBt, p1, iSavepoint);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
}
}
if( p1==SAVEPOINT_ROLLBACK && (db->flags&SQLITE_InternChanges)!=0 ){
sqlite3ExpirePreparedStatements(db);
@ -2507,7 +2557,8 @@ case OP_Savepoint: {
**
** Set the database auto-commit flag to P1 (1 or 0). If P2 is true, roll
** back any currently active btree transactions. If there are any active
** VMs (apart from this one), then the COMMIT or ROLLBACK statement fails.
** VMs (apart from this one), then a ROLLBACK fails. A COMMIT fails if
** there are active writing VMs or active VMs that use shared cache.
**
** This instruction causes the VM to halt.
*/
@ -2550,6 +2601,7 @@ case OP_AutoCommit: {
goto vdbe_return;
}
}
assert( db->nStatement==0 );
sqlite3CloseSavepoints(db);
if( p->rc==SQLITE_OK ){
rc = SQLITE_DONE;
@ -2767,9 +2819,11 @@ case OP_VerifyCookie: {
** to get a read lock but fails, the script terminates with an
** SQLITE_BUSY error code.
**
** The P4 value is a pointer to a KeyInfo structure that defines the
** content and collating sequence of indices. P4 is NULL for cursors
** that are not pointing to indices.
** The P4 value may be either an integer (P4_INT32) or a pointer to
** a KeyInfo structure (P4_KEYINFO). If it is a pointer to a KeyInfo
** structure, then said structure defines the content and collating
** sequence of the index being opened. Otherwise, if P4 is an integer
** value, it is set to the number of columns in the table.
**
** See also OpenWrite.
*/
@ -2779,9 +2833,11 @@ case OP_VerifyCookie: {
** page is P2. Or if P5!=0 use the content of register P2 to find the
** root page.
**
** The P4 value is a pointer to a KeyInfo structure that defines the
** content and collating sequence of indices. P4 is NULL for cursors
** that are not pointing to indices.
** The P4 value may be either an integer (P4_INT32) or a pointer to
** a KeyInfo structure (P4_KEYINFO). If it is a pointer to a KeyInfo
** structure, then said structure defines the content and collating
** sequence of the index being opened. Otherwise, if P4 is an integer
** value, it is set to the number of columns in the table.
**
** This instruction works just like OpenRead except that it opens the cursor
** in read/write mode. For a given table, there can be one or more read-only
@ -2791,6 +2847,8 @@ case OP_VerifyCookie: {
*/
case OP_OpenRead:
case OP_OpenWrite: {
int nField = 0;
KeyInfo *pKeyInfo = 0;
int i = pOp->p1;
int p2 = pOp->p2;
int iDb = pOp->p3;
@ -2824,16 +2882,19 @@ case OP_OpenWrite: {
}
}
assert( i>=0 );
pCur = allocateCursor(p, i, &pOp[-1], iDb, 1);
if( pOp->p4type==P4_KEYINFO ){
pKeyInfo = pOp->p4.pKeyInfo;
pKeyInfo->enc = ENC(p->db);
nField = pKeyInfo->nField+1;
}else if( pOp->p4type==P4_INT32 ){
nField = pOp->p4.i;
}
pCur = allocateCursor(p, i, nField, iDb, 1);
if( pCur==0 ) goto no_mem;
pCur->nullRow = 1;
rc = sqlite3BtreeCursor(pX, p2, wrFlag, pOp->p4.p, pCur->pCursor);
if( pOp->p4type==P4_KEYINFO ){
pCur->pKeyInfo = pOp->p4.pKeyInfo;
pCur->pKeyInfo->enc = ENC(p->db);
}else{
pCur->pKeyInfo = 0;
}
rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->pCursor);
pCur->pKeyInfo = pKeyInfo;
switch( rc ){
case SQLITE_BUSY: {
p->pc = pc;
@ -2908,7 +2969,7 @@ case OP_OpenEphemeral: {
SQLITE_OPEN_TRANSIENT_DB;
assert( i>=0 );
pCx = allocateCursor(p, i, pOp, -1, 1);
pCx = allocateCursor(p, i, pOp->p2, -1, 1);
if( pCx==0 ) goto no_mem;
pCx->nullRow = 1;
rc = sqlite3BtreeFactory(db, 0, 1, SQLITE_DEFAULT_TEMP_CACHE_SIZE, openFlags,
@ -2943,7 +3004,7 @@ case OP_OpenEphemeral: {
break;
}
/* Opcode: OpenPseudo P1 P2 * * *
/* Opcode: OpenPseudo P1 P2 P3 * *
**
** Open a new cursor that points to a fake table that contains a single
** row of data. Any attempt to write a second row of data causes the
@ -2962,12 +3023,15 @@ case OP_OpenEphemeral: {
** is stored. In this case, the vdbe program must ensure that the
** memory cell containing the row data is not overwritten until the
** pseudo table is closed (or a new row is inserted into it).
**
** P3 is the number of fields in the records that will be stored by
** the pseudo-table.
*/
case OP_OpenPseudo: {
int i = pOp->p1;
VdbeCursor *pCx;
assert( i>=0 );
pCx = allocateCursor(p, i, &pOp[-1], -1, 0);
pCx = allocateCursor(p, i, pOp->p3, -1, 0);
if( pCx==0 ) goto no_mem;
pCx->nullRow = 1;
pCx->pseudoTable = 1;
@ -3512,9 +3576,8 @@ case OP_NewRowid: { /* out2-prerelease */
#endif
if( !pC->useRandomRowid ){
if( pC->nextRowidValid ){
v = pC->nextRowid;
}else{
v = sqlite3BtreeGetCachedRowid(pC->pCursor);
if( v==0 ){
rc = sqlite3BtreeLast(pC->pCursor, &res);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
@ -3551,12 +3614,7 @@ case OP_NewRowid: { /* out2-prerelease */
}
#endif
if( v<MAX_ROWID ){
pC->nextRowidValid = 1;
pC->nextRowid = v+1;
}else{
pC->nextRowidValid = 0;
}
sqlite3BtreeSetCachedRowid(pC->pCursor, v<MAX_ROWID ? v+1 : 0);
}
if( pC->useRandomRowid ){
assert( pOp->p3==0 ); /* SQLITE_FULL must have occurred prior to this */
@ -3634,9 +3692,6 @@ case OP_Insert: {
iKey = intToKey(pKey->u.i);
if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = pKey->u.i;
if( pC->nextRowidValid && pKey->u.i>=pC->nextRowid ){
pC->nextRowidValid = 0;
}
if( pData->flags & MEM_Null ){
pData->z = 0;
pData->n = 0;
@ -3671,6 +3726,7 @@ case OP_Insert: {
}else{
nZero = 0;
}
sqlite3BtreeSetCachedRowid(pC->pCursor, 0);
rc = sqlite3BtreeInsert(pC->pCursor, 0, iKey,
pData->z, pData->n, nZero,
pOp->p5 & OPFLAG_APPEND);
@ -3733,8 +3789,8 @@ case OP_Delete: {
rc = sqlite3VdbeCursorMoveto(pC);
if( rc ) goto abort_due_to_error;
sqlite3BtreeSetCachedRowid(pC->pCursor, 0);
rc = sqlite3BtreeDelete(pC->pCursor);
pC->nextRowidValid = 0;
pC->cacheStatus = CACHE_STALE;
/* Invoke the update-hook if required. */
@ -4066,7 +4122,7 @@ case OP_IdxDelete: {
VdbeCursor *pC;
BtCursor *pCrsr;
assert( pOp->p3>0 );
assert( pOp->p2>0 && pOp->p2+pOp->p3<=p->nMem );
assert( pOp->p2>0 && pOp->p2+pOp->p3<=p->nMem+1 );
assert( i>=0 && i<p->nCursor );
assert( p->apCsr[i]!=0 );
if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
@ -4099,11 +4155,13 @@ case OP_IdxRowid: { /* out2-prerelease */
BtCursor *pCrsr;
VdbeCursor *pC;
assert( i>=0 && i<p->nCursor );
assert( p->apCsr[i]!=0 );
if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
i64 rowid;
rc = sqlite3VdbeCursorMoveto(pC);
if( rc ) goto abort_due_to_error;
assert( pC->deferredMoveto==0 );
assert( pC->isTable==0 );
if( !pC->nullRow ){
@ -4242,7 +4300,7 @@ case OP_Destroy: { /* out2-prerelease */
** P2==1 then the table to be clear is in the auxiliary database file
** that is used to store tables create using CREATE TEMPORARY TABLE.
**
** If the P3 value is non-zero, then the table refered to must be an
** If the P3 value is non-zero, then the table referred to must be an
** intkey table (an SQL table, not an index). In this case the row change
** count is incremented by the number of rows in the table being cleared.
** If P3 is greater than zero, then the value stored in register P3 is
@ -4321,33 +4379,58 @@ case OP_CreateTable: { /* out2-prerelease */
** then runs the new virtual machine. It is thus a re-entrant opcode.
*/
case OP_ParseSchema: {
char *zSql;
int iDb = pOp->p1;
const char *zMaster;
InitData initData;
assert( iDb>=0 && iDb<db->nDb );
if( !pOp->p2 && !DbHasProperty(db, iDb, DB_SchemaLoaded) ){
break;
/* If pOp->p2 is 0, then this opcode is being executed to read a
** single row, for example the row corresponding to a new index
** created by this VDBE, from the sqlite_master table. It only
** does this if the corresponding in-memory schema is currently
** loaded. Otherwise, the new index definition can be loaded along
** with the rest of the schema when it is required.
**
** Although the mutex on the BtShared object that corresponds to
** database iDb (the database containing the sqlite_master table
** read by this instruction) is currently held, it is necessary to
** obtain the mutexes on all attached databases before checking if
** the schema of iDb is loaded. This is because, at the start of
** the sqlite3_exec() call below, SQLite will invoke
** sqlite3BtreeEnterAll(). If all mutexes are not already held, the
** iDb mutex may be temporarily released to avoid deadlock. If
** this happens, then some other thread may delete the in-memory
** schema of database iDb before the SQL statement runs. The schema
** will not be reloaded becuase the db->init.busy flag is set. This
** can result in a "no such table: sqlite_master" or "malformed
** database schema" error being returned to the user.
*/
assert( sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) );
sqlite3BtreeEnterAll(db);
if( pOp->p2 || DbHasProperty(db, iDb, DB_SchemaLoaded) ){
const char *zMaster = SCHEMA_TABLE(iDb);
char *zSql;
InitData initData;
initData.db = db;
initData.iDb = pOp->p1;
initData.pzErrMsg = &p->zErrMsg;
zSql = sqlite3MPrintf(db,
"SELECT name, rootpage, sql FROM '%q'.%s WHERE %s",
db->aDb[iDb].zName, zMaster, pOp->p4.z);
if( zSql==0 ){
rc = SQLITE_NOMEM;
}else{
(void)sqlite3SafetyOff(db);
assert( db->init.busy==0 );
db->init.busy = 1;
initData.rc = SQLITE_OK;
assert( !db->mallocFailed );
rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
if( rc==SQLITE_OK ) rc = initData.rc;
sqlite3DbFree(db, zSql);
db->init.busy = 0;
(void)sqlite3SafetyOn(db);
}
}
zMaster = SCHEMA_TABLE(iDb);
initData.db = db;
initData.iDb = pOp->p1;
initData.pzErrMsg = &p->zErrMsg;
zSql = sqlite3MPrintf(db,
"SELECT name, rootpage, sql FROM '%q'.%s WHERE %s",
db->aDb[iDb].zName, zMaster, pOp->p4.z);
if( zSql==0 ) goto no_mem;
(void)sqlite3SafetyOff(db);
assert( db->init.busy==0 );
db->init.busy = 1;
initData.rc = SQLITE_OK;
assert( !db->mallocFailed );
rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
if( rc==SQLITE_OK ) rc = initData.rc;
sqlite3DbFree(db, zSql);
db->init.busy = 0;
(void)sqlite3SafetyOn(db);
sqlite3BtreeLeaveAll(db);
if( rc==SQLITE_NOMEM ){
goto no_mem;
}
@ -4781,7 +4864,7 @@ case OP_TableLock: {
assert( (p->btreeMask & (1<<p1))!=0 );
assert( isWriteLock==0 || isWriteLock==1 );
rc = sqlite3BtreeLockTable(db->aDb[p1].pBt, pOp->p2, isWriteLock);
if( rc==SQLITE_LOCKED ){
if( (rc&0xFF)==SQLITE_LOCKED ){
const char *z = pOp->p4.z;
sqlite3SetString(&p->zErrMsg, db, "database table is locked: %s", z);
}
@ -4796,8 +4879,8 @@ case OP_TableLock: {
** xBegin method for that table.
**
** Also, whether or not P4 is set, check that this is not being called from
** within a callback to a virtual table xSync() method. If it is, set the
** error code to SQLITE_LOCKED.
** within a callback to a virtual table xSync() method. If it is, the error
** code will be set to SQLITE_LOCKED.
*/
case OP_VBegin: {
sqlite3_vtab *pVtab = pOp->p4.pVtab;
@ -4863,7 +4946,7 @@ case OP_VOpen: {
pVtabCursor->pVtab = pVtab;
/* Initialise vdbe cursor object */
pCur = allocateCursor(p, pOp->p1, &pOp[-1], -1, 0);
pCur = allocateCursor(p, pOp->p1, 0, -1, 0);
if( pCur ){
pCur->pVtabCursor = pVtabCursor;
pCur->pModule = pVtabCursor->pVtab->pModule;
@ -5023,7 +5106,7 @@ case OP_VColumn: {
pVtab->zErrMsg = 0;
/* Copy the result of the function to the P3 register. We
** do this regardless of whether or not an error occured to ensure any
** do this regardless of whether or not an error occurred to ensure any
** dynamic allocation in sContext.s (a Mem struct) is released.
*/
sqlite3VdbeChangeEncoding(&sContext.s, encoding);
@ -5204,13 +5287,14 @@ case OP_Pagecount: { /* out2-prerelease */
** the UTF-8 string contained in P4 is emitted on the trace callback.
*/
case OP_Trace: {
if( pOp->p4.z ){
char *zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql);
if( zTrace ){
if( db->xTrace ){
db->xTrace(db->pTraceArg, pOp->p4.z);
db->xTrace(db->pTraceArg, zTrace);
}
#ifdef SQLITE_DEBUG
if( (db->flags & SQLITE_SqlTrace)!=0 ){
sqlite3DebugPrintf("SQL-trace: %s\n", pOp->p4.z);
sqlite3DebugPrintf("SQL-trace: %s\n", zTrace);
}
#endif /* SQLITE_DEBUG */
}

View File

@ -15,7 +15,7 @@
** or VDBE. The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
**
** $Id: vdbe.h,v 1.139 2008/10/31 10:53:23 danielk1977 Exp $
** $Id: vdbe.h,v 1.141 2009/04/10 00:56:29 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
@ -181,14 +181,13 @@ void sqlite3VdbeSetNumCols(Vdbe*,int);
int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, void(*)(void*));
void sqlite3VdbeCountChanges(Vdbe*);
sqlite3 *sqlite3VdbeDb(Vdbe*);
void sqlite3VdbeSetSql(Vdbe*, const char *z, int n);
void sqlite3VdbeSetSql(Vdbe*, const char *z, int n, int);
void sqlite3VdbeSwap(Vdbe*,Vdbe*);
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
int sqlite3VdbeReleaseMemory(int);
#endif
UnpackedRecord *sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,
UnpackedRecord*,int);
UnpackedRecord *sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,char*,int);
void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord*);
int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*);

View File

@ -15,7 +15,7 @@
** 6000 lines long) it was split up into several smaller files and
** this header information was factored out.
**
** $Id: vdbeInt.h,v 1.162 2009/02/03 15:39:01 drh Exp $
** $Id: vdbeInt.h,v 1.167 2009/04/10 12:55:17 danielk1977 Exp $
*/
#ifndef _VDBEINT_H_
#define _VDBEINT_H_
@ -59,13 +59,11 @@ struct VdbeCursor {
BtCursor *pCursor; /* The cursor structure of the backend */
int iDb; /* Index of cursor database in db->aDb[] (or -1) */
i64 lastRowid; /* Last rowid from a Next or NextIdx operation */
i64 nextRowid; /* Next rowid returned by OP_NewRowid */
Bool zeroed; /* True if zeroed out and ready for reuse */
Bool rowidIsValid; /* True if lastRowid is valid */
Bool atFirst; /* True if pointing to first entry */
Bool useRandomRowid; /* Generate new record numbers semi-randomly */
Bool nullRow; /* True if pointing to a row with no data */
Bool nextRowidValid; /* True if the nextRowid field is valid */
Bool pseudoTable; /* This is a NEW or OLD pseudo-tables of a trigger */
Bool ephemPseudoTable;
Bool deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
@ -279,16 +277,13 @@ struct Vdbe {
u32 magic; /* Magic number for sanity checking */
int nMem; /* Number of memory locations currently allocated */
Mem *aMem; /* The memory locations */
int nCallback; /* Number of callbacks invoked so far */
int cacheCtr; /* VdbeCursor row cache generation counter */
int contextStackTop; /* Index of top element in the context stack */
int contextStackDepth; /* The size of the "context" stack */
Context *contextStack; /* Stack used by opcodes ContextPush & ContextPop*/
int pc; /* The program counter */
int rc; /* Value to return */
unsigned uniqueCnt; /* Used by OP_MakeRecord when P2!=0 */
int errorAction; /* Recovery action to do in case of an error */
int inTempTrans; /* True if temp database is transactioned */
int nResColumn; /* Number of columns in one row of the result set */
char **azResColumn; /* Values for one row of result */
char *zErrMsg; /* Error message written here */
@ -300,17 +295,18 @@ struct Vdbe {
u8 inVtabMethod; /* See comments above */
u8 usesStmtJournal; /* True if uses a statement journal */
u8 readOnly; /* True for read-only statements */
u8 isPrepareV2; /* True if prepared with prepare_v2() */
int nChange; /* Number of db changes made since last reset */
i64 startTime; /* Time when query started - used for profiling */
int btreeMask; /* Bitmask of db->aDb[] entries referenced */
BtreeMutexArray aMutex; /* An array of Btree used here and needing locks */
int aCounter[2]; /* Counters used by sqlite3_stmt_status() */
int nSql; /* Number of bytes in zSql */
char *zSql; /* Text of the SQL statement that generated this */
void *pFree; /* Free this when deleting the vdbe */
#ifdef SQLITE_DEBUG
FILE *trace; /* Write an execution trace here, if not NULL */
#endif
int openedStatement; /* True if this VM has opened a statement journal */
int iStatement; /* Statement number (or 0 if has not opened stmt) */
#ifdef SQLITE_SSE
int fetchId; /* Statement number used by sqlite3_fetch_statement */
int lru; /* Counter used for LRU cache replacement */
@ -378,10 +374,17 @@ int sqlite3VdbeMemFinalize(Mem*, FuncDef*);
const char *sqlite3OpcodeName(int);
int sqlite3VdbeOpcodeHasProperty(int, int);
int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve);
int sqlite3VdbeCloseStatement(Vdbe *, int);
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
int sqlite3VdbeReleaseBuffers(Vdbe *p);
#endif
#ifndef SQLITE_OMIT_SHARED_CACHE
void sqlite3VdbeMutexArrayEnter(Vdbe *p);
#else
# define sqlite3VdbeMutexArrayEnter(p)
#endif
int sqlite3VdbeMemTranslate(Mem*, u8);
#ifdef SQLITE_DEBUG
void sqlite3VdbePrintSql(Vdbe*);

View File

@ -13,7 +13,7 @@
** This file contains code use to implement APIs that are part of the
** VDBE.
**
** $Id: vdbeapi.c,v 1.151 2009/02/04 03:59:25 shane Exp $
** $Id: vdbeapi.c,v 1.161 2009/04/10 23:11:31 drh Exp $
*/
#include "sqliteInt.h"
#include "vdbeInt.h"
@ -204,12 +204,14 @@ int sqlite3_finalize(sqlite3_stmt *pStmt){
rc = SQLITE_OK;
}else{
Vdbe *v = (Vdbe*)pStmt;
sqlite3 *db = v->db;
#if SQLITE_THREADSAFE
sqlite3_mutex *mutex = v->db->mutex;
#endif
sqlite3_mutex_enter(mutex);
stmtLruRemove(v);
rc = sqlite3VdbeFinalize(v);
rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(mutex);
}
return rc;
@ -234,6 +236,7 @@ int sqlite3_reset(sqlite3_stmt *pStmt){
stmtLruAdd(v);
sqlite3VdbeMakeReady(v, -1, 0, 0, 0);
assert( (rc & (v->db->errMask))==rc );
rc = sqlite3ApiExit(v->db, rc);
sqlite3_mutex_leave(v->db->mutex);
}
return rc;
@ -440,7 +443,7 @@ static int sqlite3Step(Vdbe *p){
}
if( p->pc<=0 && p->expired ){
if( p->rc==SQLITE_OK ){
if( ALWAYS(p->rc==SQLITE_OK) ){
p->rc = SQLITE_SCHEMA;
}
rc = SQLITE_ERROR;
@ -488,34 +491,41 @@ static int sqlite3Step(Vdbe *p){
#ifndef SQLITE_OMIT_TRACE
/* Invoke the profile callback if there is one
*/
if( rc!=SQLITE_ROW && db->xProfile && !db->init.busy && p->nOp>0
&& p->aOp[0].opcode==OP_Trace && p->aOp[0].p4.z!=0 ){
if( rc!=SQLITE_ROW && db->xProfile && !db->init.busy && p->zSql ){
double rNow;
u64 elapseTime;
sqlite3OsCurrentTime(db->pVfs, &rNow);
elapseTime = (u64)((rNow - (int)rNow)*3600.0*24.0*1000000000.0);
elapseTime -= p->startTime;
db->xProfile(db->pProfileArg, p->aOp[0].p4.z, elapseTime);
db->xProfile(db->pProfileArg, p->zSql, elapseTime);
}
#endif
db->errCode = rc;
/*sqlite3Error(p->db, rc, 0);*/
p->rc = sqlite3ApiExit(p->db, p->rc);
end_of_step:
assert( (rc&0xff)==rc );
if( p->zSql && (rc&0xff)<SQLITE_ROW ){
/* This behavior occurs if sqlite3_prepare_v2() was used to build
** the prepared statement. Return error codes directly */
p->db->errCode = p->rc;
/* sqlite3Error(p->db, p->rc, 0); */
return p->rc;
}else{
/* This is for legacy sqlite3_prepare() builds and when the code
** is SQLITE_ROW or SQLITE_DONE */
return rc;
if( SQLITE_NOMEM==sqlite3ApiExit(p->db, p->rc) ){
p->rc = SQLITE_NOMEM;
}
end_of_step:
/* At this point local variable rc holds the value that should be
** returned if this statement was compiled using the legacy
** sqlite3_prepare() interface. According to the docs, this can only
** be one of the values in the first assert() below. Variable p->rc
** contains the value that would be returned if sqlite3_finalize()
** were called on statement p.
*/
assert( rc==SQLITE_ROW || rc==SQLITE_DONE || rc==SQLITE_ERROR
|| rc==SQLITE_BUSY || rc==SQLITE_MISUSE
);
assert( p->rc!=SQLITE_ROW && p->rc!=SQLITE_DONE );
if( p->isPrepareV2 && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
/* If this statement was prepared using sqlite3_prepare_v2(), and an
** error has occured, then return the error code in p->rc to the
** caller. Set the error code in the database handle to the same value.
*/
rc = db->errCode = p->rc;
}
return (rc&db->errMask);
}
/*
@ -545,11 +555,11 @@ int sqlite3_step(sqlite3_stmt *pStmt){
sqlite3_mutex_enter(db->mutex);
while( (rc = sqlite3Step(v))==SQLITE_SCHEMA
&& cnt++ < 5
&& vdbeReprepare(v) ){
&& (rc = vdbeReprepare(v))==SQLITE_OK ){
sqlite3_reset(pStmt);
v->expired = 0;
}
if( rc==SQLITE_SCHEMA && v->zSql && db->pErr ){
if( rc==SQLITE_SCHEMA && ALWAYS(v->isPrepareV2) && ALWAYS(db->pErr) ){
/* This case occurs after failing to recompile an sql statement.
** The error message from the SQL compiler has already been loaded
** into the database handle. This block copies the error message
@ -608,7 +618,7 @@ void sqlite3InvalidFunction(
const char *zName = context->pFunc->zName;
char *zErr;
UNUSED_PARAMETER2(NotUsed, NotUsed2);
zErr = sqlite3MPrintf(0,
zErr = sqlite3_mprintf(
"unable to use function %s in the requested context", zName);
sqlite3_result_error(context, zErr, -1);
sqlite3_free(zErr);
@ -711,7 +721,7 @@ failed:
** context.
*/
int sqlite3_aggregate_count(sqlite3_context *p){
assert( p && p->pFunc && p->pFunc->xStep );
assert( p && p->pMem && p->pFunc && p->pFunc->xStep );
return p->pMem->n;
}
#endif
@ -754,7 +764,7 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
}else{
/* ((double)0) In case of SQLITE_OMIT_FLOATING_POINT... */
static const Mem nullMem = {{0}, (double)0, 0, "", 0, MEM_Null, SQLITE_NULL, 0, 0, 0 };
if( pVm->db ){
if( pVm && ALWAYS(pVm->db) ){
sqlite3_mutex_enter(pVm->db->mutex);
sqlite3Error(pVm->db, SQLITE_RANGE, 0);
}
@ -894,24 +904,23 @@ static const void *columnName(
const void *ret = 0;
Vdbe *p = (Vdbe *)pStmt;
int n;
sqlite3 *db = p->db;
if( p!=0 ){
n = sqlite3_column_count(pStmt);
if( N<n && N>=0 ){
N += useType*n;
sqlite3_mutex_enter(p->db->mutex);
ret = xFunc(&p->aColName[N]);
/* A malloc may have failed inside of the xFunc() call. If this
** is the case, clear the mallocFailed flag and return NULL.
*/
if( p->db && p->db->mallocFailed ){
p->db->mallocFailed = 0;
ret = 0;
}
sqlite3_mutex_leave(p->db->mutex);
assert( db!=0 );
n = sqlite3_column_count(pStmt);
if( N<n && N>=0 ){
N += useType*n;
sqlite3_mutex_enter(db->mutex);
assert( db->mallocFailed==0 );
ret = xFunc(&p->aColName[N]);
/* A malloc may have failed inside of the xFunc() call. If this
** is the case, clear the mallocFailed flag and return NULL.
*/
if( db->mallocFailed ){
db->mallocFailed = 0;
ret = 0;
}
sqlite3_mutex_leave(db->mutex);
}
return ret;
}
@ -1151,8 +1160,8 @@ int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){
rc = sqlite3VdbeChangeEncoding(&p->aVar[i-1], ENC(p->db));
}
sqlite3_mutex_leave(p->db->mutex);
rc = sqlite3ApiExit(p->db, rc);
}
rc = sqlite3ApiExit(p->db, rc);
return rc;
}
int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){
@ -1182,18 +1191,21 @@ int sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){
*/
static void createVarMap(Vdbe *p){
if( !p->okVar ){
int j;
Op *pOp;
sqlite3_mutex_enter(p->db->mutex);
if( !p->okVar ){
int j;
Op *pOp;
for(j=0, pOp=p->aOp; j<p->nOp; j++, pOp++){
if( pOp->opcode==OP_Variable ){
assert( pOp->p1>0 && pOp->p1<=p->nVar );
p->azVar[pOp->p1-1] = pOp->p4.z;
}
/* The race condition here is harmless. If two threads call this
** routine on the same Vdbe at the same time, they both might end
** up initializing the Vdbe.azVar[] array. That is a little extra
** work but it results in the same answer.
*/
for(j=0, pOp=p->aOp; j<p->nOp; j++, pOp++){
if( pOp->opcode==OP_Variable ){
assert( pOp->p1>0 && pOp->p1<=p->nVar );
p->azVar[pOp->p1-1] = pOp->p4.z;
}
p->okVar = 1;
}
p->okVar = 1;
sqlite3_mutex_leave(p->db->mutex);
}
}
@ -1238,36 +1250,40 @@ int sqlite3_bind_parameter_index(sqlite3_stmt *pStmt, const char *zName){
/*
** Transfer all bindings from the first statement over to the second.
** If the two statements contain a different number of bindings, then
** an SQLITE_ERROR is returned.
*/
int sqlite3TransferBindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){
Vdbe *pFrom = (Vdbe*)pFromStmt;
Vdbe *pTo = (Vdbe*)pToStmt;
int i, rc = SQLITE_OK;
if( (pFrom->magic!=VDBE_MAGIC_RUN && pFrom->magic!=VDBE_MAGIC_HALT)
|| (pTo->magic!=VDBE_MAGIC_RUN && pTo->magic!=VDBE_MAGIC_HALT)
|| pTo->db!=pFrom->db ){
return SQLITE_MISUSE;
}
if( pFrom->nVar!=pTo->nVar ){
return SQLITE_ERROR;
}
int i;
assert( pTo->db==pFrom->db );
assert( pTo->nVar==pFrom->nVar );
sqlite3_mutex_enter(pTo->db->mutex);
for(i=0; rc==SQLITE_OK && i<pFrom->nVar; i++){
for(i=0; i<pFrom->nVar; i++){
sqlite3VdbeMemMove(&pTo->aVar[i], &pFrom->aVar[i]);
}
sqlite3_mutex_leave(pTo->db->mutex);
assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
return rc;
return SQLITE_OK;
}
#ifndef SQLITE_OMIT_DEPRECATED
/*
** Deprecated external interface. Internal/core SQLite code
** should call sqlite3TransferBindings.
**
** Is is misuse to call this routine with statements from different
** database connections. But as this is a deprecated interface, we
** will not bother to check for that condition.
**
** If the two statements contain a different number of bindings, then
** an SQLITE_ERROR is returned. Nothing else can go wrong, so otherwise
** SQLITE_OK is returned.
*/
int sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){
Vdbe *pFrom = (Vdbe*)pFromStmt;
Vdbe *pTo = (Vdbe*)pToStmt;
if( pFrom->nVar!=pTo->nVar ){
return SQLITE_ERROR;
}
return sqlite3TransferBindings(pFromStmt, pToStmt);
}
#endif

View File

@ -14,7 +14,7 @@
** to version 2.8.7, all this code was combined into the vdbe.c source file.
** But that file was getting too big so this subroutines were split out.
**
** $Id: vdbeaux.c,v 1.435 2009/02/03 16:51:25 danielk1977 Exp $
** $Id: vdbeaux.c,v 1.451 2009/04/10 15:42:36 shane Exp $
*/
#include "sqliteInt.h"
#include "vdbeInt.h"
@ -52,17 +52,22 @@ Vdbe *sqlite3VdbeCreate(sqlite3 *db){
/*
** Remember the SQL string for a prepared statement.
*/
void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n){
void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, int isPrepareV2){
if( p==0 ) return;
#ifdef SQLITE_OMIT_TRACE
if( !isPrepareV2 ) return;
#endif
assert( p->zSql==0 );
p->zSql = sqlite3DbStrNDup(p->db, z, n);
p->isPrepareV2 = isPrepareV2 ? 1 : 0;
}
/*
** Return the SQL associated with a prepared statement
*/
const char *sqlite3_sql(sqlite3_stmt *pStmt){
return ((Vdbe *)pStmt)->zSql;
Vdbe *p = (Vdbe *)pStmt;
return (p->isPrepareV2 ? p->zSql : 0);
}
/*
@ -71,7 +76,6 @@ const char *sqlite3_sql(sqlite3_stmt *pStmt){
void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){
Vdbe tmp, *pTmp;
char *zTmp;
int nTmp;
tmp = *pA;
*pA = *pB;
*pB = tmp;
@ -84,9 +88,7 @@ void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){
zTmp = pA->zSql;
pA->zSql = pB->zSql;
pB->zSql = zTmp;
nTmp = pA->nSql;
pA->nSql = pB->nSql;
pB->nSql = nTmp;
pB->isPrepareV2 = pA->isPrepareV2;
}
#ifdef SQLITE_DEBUG
@ -112,7 +114,7 @@ static int growOpArray(Vdbe *p){
int nNew = (p->nOpAlloc ? p->nOpAlloc*2 : (int)(1024/sizeof(Op)));
pNew = sqlite3DbRealloc(p->db, p->aOp, nNew*sizeof(Op));
if( pNew ){
p->nOpAlloc = nNew;
p->nOpAlloc = sqlite3DbMallocSize(p->db, pNew)/sizeof(Op);
p->aOp = pNew;
}
return (pNew ? SQLITE_OK : SQLITE_NOMEM);
@ -901,8 +903,8 @@ int sqlite3VdbeList(
}
if( sqlite3VdbeMemGrow(pMem, 32, 0) ){ /* P4 */
p->db->mallocFailed = 1;
return SQLITE_NOMEM;
assert( p->db->mallocFailed );
return SQLITE_ERROR;
}
pMem->flags = MEM_Dyn|MEM_Str|MEM_Term;
z = displayP4(pOp, pMem->z, 32);
@ -918,8 +920,8 @@ int sqlite3VdbeList(
if( p->explain==1 ){
if( sqlite3VdbeMemGrow(pMem, 4, 0) ){
p->db->mallocFailed = 1;
return SQLITE_NOMEM;
assert( p->db->mallocFailed );
return SQLITE_ERROR;
}
pMem->flags = MEM_Dyn|MEM_Str|MEM_Term;
pMem->n = 2;
@ -998,6 +1000,40 @@ void sqlite3VdbeIOTraceSql(Vdbe *p){
}
#endif /* !SQLITE_OMIT_TRACE && SQLITE_ENABLE_IOTRACE */
/*
** Allocate space from a fixed size buffer. Make *pp point to the
** allocated space. (Note: pp is a char* rather than a void** to
** work around the pointer aliasing rules of C.) *pp should initially
** be zero. If *pp is not zero, that means that the space has already
** been allocated and this routine is a noop.
**
** nByte is the number of bytes of space needed.
**
** *ppFrom point to available space and pEnd points to the end of the
** available space.
**
** *pnByte is a counter of the number of bytes of space that have failed
** to allocate. If there is insufficient space in *ppFrom to satisfy the
** request, then increment *pnByte by the amount of the request.
*/
static void allocSpace(
char *pp, /* IN/OUT: Set *pp to point to allocated buffer */
int nByte, /* Number of bytes to allocate */
u8 **ppFrom, /* IN/OUT: Allocate from *ppFrom */
u8 *pEnd, /* Pointer to 1 byte past the end of *ppFrom buffer */
int *pnByte /* If allocation cannot be made, increment *pnByte */
){
assert( EIGHT_BYTE_ALIGNMENT(*ppFrom) );
if( (*(void**)pp)==0 ){
nByte = ROUND8(nByte);
if( (pEnd - *ppFrom)>=nByte ){
*(void**)pp = (void *)*ppFrom;
*ppFrom += nByte;
}else{
*pnByte += nByte;
}
}
}
/*
** Prepare a virtual machine for execution. This involves things such
@ -1007,6 +1043,14 @@ void sqlite3VdbeIOTraceSql(Vdbe *p){
**
** This is the only way to move a VDBE from VDBE_MAGIC_INIT to
** VDBE_MAGIC_RUN.
**
** This function may be called more than once on a single virtual machine.
** The first call is made while compiling the SQL statement. Subsequent
** calls are made as part of the process of resetting a statement to be
** re-executed (from a call to sqlite3_reset()). The nVar, nMem, nCursor
** and isExplain parameters are only passed correct values the first time
** the function is called. On subsequent calls, from sqlite3_reset(), nVar
** is passed -1 and nMem, nCursor and isExplain are all passed zero.
*/
void sqlite3VdbeMakeReady(
Vdbe *p, /* The VDBE */
@ -1039,37 +1083,52 @@ void sqlite3VdbeMakeReady(
*/
nMem += nCursor;
/*
** Allocation space for registers.
/* Allocate space for memory registers, SQL variables, VDBE cursors and
** an array to marshal SQL function arguments in. This is only done the
** first time this function is called for a given VDBE, not when it is
** being called from sqlite3_reset() to reset the virtual machine.
*/
if( p->aMem==0 ){
if( nVar>=0 && !db->mallocFailed ){
u8 *zCsr = (u8 *)&p->aOp[p->nOp];
u8 *zEnd = (u8 *)&p->aOp[p->nOpAlloc];
int nByte;
int nArg; /* Maximum number of args passed to a user function. */
resolveP2Values(p, &nArg);
assert( nVar>=0 );
if( isExplain && nMem<10 ){
nMem = 10;
}
p->aMem = sqlite3DbMallocZero(db,
nMem*sizeof(Mem) /* aMem */
+ nVar*sizeof(Mem) /* aVar */
+ nArg*sizeof(Mem*) /* apArg */
+ nVar*sizeof(char*) /* azVar */
+ nCursor*sizeof(VdbeCursor*)+1 /* apCsr */
);
if( !db->mallocFailed ){
p->aMem--; /* aMem[] goes from 1..nMem */
p->nMem = nMem; /* not from 0..nMem-1 */
p->aVar = &p->aMem[nMem+1];
zCsr += (zCsr - (u8*)0)&7;
assert( EIGHT_BYTE_ALIGNMENT(zCsr) );
if( zEnd<zCsr ) zEnd = zCsr;
do {
memset(zCsr, 0, zEnd-zCsr);
nByte = 0;
allocSpace((char*)&p->aMem, nMem*sizeof(Mem), &zCsr, zEnd, &nByte);
allocSpace((char*)&p->aVar, nVar*sizeof(Mem), &zCsr, zEnd, &nByte);
allocSpace((char*)&p->apArg, nArg*sizeof(Mem*), &zCsr, zEnd, &nByte);
allocSpace((char*)&p->azVar, nVar*sizeof(char*), &zCsr, zEnd, &nByte);
allocSpace((char*)&p->apCsr,
nCursor*sizeof(VdbeCursor*), &zCsr, zEnd, &nByte
);
if( nByte ){
p->pFree = sqlite3DbMallocRaw(db, nByte);
}
zCsr = p->pFree;
zEnd = &zCsr[nByte];
}while( nByte && !db->mallocFailed );
p->nCursor = nCursor;
if( p->aVar ){
p->nVar = nVar;
p->okVar = 0;
p->apArg = (Mem**)&p->aVar[nVar];
p->azVar = (char**)&p->apArg[nArg];
p->apCsr = (VdbeCursor**)&p->azVar[nVar];
p->nCursor = nCursor;
for(n=0; n<nVar; n++){
p->aVar[n].flags = MEM_Null;
p->aVar[n].db = db;
}
}
if( p->aMem ){
p->aMem--; /* aMem[] goes from 1..nMem */
p->nMem = nMem; /* not from 0..nMem-1 */
for(n=1; n<=nMem; n++){
p->aMem[n].flags = MEM_Null;
p->aMem[n].db = db;
@ -1084,14 +1143,13 @@ void sqlite3VdbeMakeReady(
p->pc = -1;
p->rc = SQLITE_OK;
p->uniqueCnt = 0;
p->errorAction = OE_Abort;
p->explain |= isExplain;
p->magic = VDBE_MAGIC_RUN;
p->nChange = 0;
p->cacheCtr = 1;
p->minWriteFileFormat = 255;
p->openedStatement = 0;
p->iStatement = 0;
#ifdef VDBE_PROFILE
{
int i;
@ -1405,7 +1463,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
** sqlite3BtreeCommitPhaseOne(), then there is a chance that the
** master journal file will be orphaned. But we cannot delete it,
** in case the master journal file name was written into the journal
** file before the failure occured.
** file before the failure occurred.
*/
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt;
@ -1510,6 +1568,75 @@ static void invalidateCursorsOnModifiedBtrees(sqlite3 *db){
}
}
/*
** If the Vdbe passed as the first argument opened a statement-transaction,
** close it now. Argument eOp must be either SAVEPOINT_ROLLBACK or
** SAVEPOINT_RELEASE. If it is SAVEPOINT_ROLLBACK, then the statement
** transaction is rolled back. If eOp is SAVEPOINT_RELEASE, then the
** statement transaction is commtted.
**
** If an IO error occurs, an SQLITE_IOERR_XXX error code is returned.
** Otherwise SQLITE_OK.
*/
int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){
sqlite3 *const db = p->db;
int rc = SQLITE_OK;
if( p->iStatement && db->nStatement ){
int i;
const int iSavepoint = p->iStatement-1;
assert( eOp==SAVEPOINT_ROLLBACK || eOp==SAVEPOINT_RELEASE);
assert( db->nStatement>0 );
assert( p->iStatement==(db->nStatement+db->nSavepoint) );
for(i=0; i<db->nDb; i++){
int rc2 = SQLITE_OK;
Btree *pBt = db->aDb[i].pBt;
if( pBt ){
if( eOp==SAVEPOINT_ROLLBACK ){
rc2 = sqlite3BtreeSavepoint(pBt, SAVEPOINT_ROLLBACK, iSavepoint);
}
if( rc2==SQLITE_OK ){
rc2 = sqlite3BtreeSavepoint(pBt, SAVEPOINT_RELEASE, iSavepoint);
}
if( rc==SQLITE_OK ){
rc = rc2;
}
}
}
db->nStatement--;
p->iStatement = 0;
}
return rc;
}
/*
** If SQLite is compiled to support shared-cache mode and to be threadsafe,
** this routine obtains the mutex associated with each BtShared structure
** that may be accessed by the VM passed as an argument. In doing so it
** sets the BtShared.db member of each of the BtShared structures, ensuring
** that the correct busy-handler callback is invoked if required.
**
** If SQLite is not threadsafe but does support shared-cache mode, then
** sqlite3BtreeEnterAll() is invoked to set the BtShared.db variables
** of all of BtShared structures accessible via the database handle
** associated with the VM. Of course only a subset of these structures
** will be accessed by the VM, and we could use Vdbe.btreeMask to figure
** that subset out, but there is no advantage to doing so.
**
** If SQLite is not threadsafe and does not support shared-cache mode, this
** function is a no-op.
*/
#ifndef SQLITE_OMIT_SHARED_CACHE
void sqlite3VdbeMutexArrayEnter(Vdbe *p){
#if SQLITE_THREADSAFE
sqlite3BtreeMutexArrayEnter(&p->aMutex);
#else
sqlite3BtreeEnterAll(p->db);
#endif
}
#endif
/*
** This routine is called the when a VDBE tries to halt. If the VDBE
** has made changes and is in autocommit mode, then commit those
@ -1524,10 +1651,8 @@ static void invalidateCursorsOnModifiedBtrees(sqlite3 *db){
** means the close did not happen and needs to be repeated.
*/
int sqlite3VdbeHalt(Vdbe *p){
int rc; /* Used to store transient return codes */
sqlite3 *db = p->db;
int i;
int (*xFunc)(Btree *pBt) = 0; /* Function to call on each btree backend */
int isSpecialError; /* Set to true if SQLITE_NOMEM or IOERR */
/* This function contains the logic that determines if a statement or
** transaction will be committed or rolled back as a result of the
@ -1557,9 +1682,11 @@ int sqlite3VdbeHalt(Vdbe *p){
/* No commit or rollback needed if the program never started */
if( p->pc>=0 ){
int mrc; /* Primary error code from p->rc */
int eStatementOp = 0;
int isSpecialError; /* Set to true if a 'special' error */
/* Lock all btrees used by the statement */
sqlite3BtreeMutexArrayEnter(&p->aMutex);
sqlite3VdbeMutexArrayEnter(p);
/* Check for one of the special errors */
mrc = p->rc & 0xff;
@ -1571,11 +1698,11 @@ int sqlite3VdbeHalt(Vdbe *p){
*/
if( !p->readOnly || mrc!=SQLITE_INTERRUPT ){
if( p->rc==SQLITE_IOERR_BLOCKED && p->usesStmtJournal ){
xFunc = sqlite3BtreeRollbackStmt;
eStatementOp = SAVEPOINT_ROLLBACK;
p->rc = SQLITE_BUSY;
}else if( (mrc==SQLITE_NOMEM || mrc==SQLITE_FULL)
&& p->usesStmtJournal ){
xFunc = sqlite3BtreeRollbackStmt;
eStatementOp = SAVEPOINT_ROLLBACK;
}else{
/* We are forced to roll back the active transaction. Before doing
** so, abort any other statements this handle currently has active.
@ -1588,8 +1715,8 @@ int sqlite3VdbeHalt(Vdbe *p){
}
}
/* If the auto-commit flag is set and this is the only active vdbe, then
** we do either a commit or rollback of the current transaction.
/* If the auto-commit flag is set and this is the only active writer
** VM, then we do either a commit or rollback of the current transaction.
**
** Note: This block also runs if one of the special errors handled
** above has occurred.
@ -1604,7 +1731,7 @@ int sqlite3VdbeHalt(Vdbe *p){
** successful or hit an 'OR FAIL' constraint. This means a commit
** is required.
*/
int rc = vdbeCommit(db, p);
rc = vdbeCommit(db, p);
if( rc==SQLITE_BUSY ){
sqlite3BtreeMutexArrayLeave(&p->aMutex);
return SQLITE_BUSY;
@ -1617,13 +1744,12 @@ int sqlite3VdbeHalt(Vdbe *p){
}else{
sqlite3RollbackAll(db);
}
}else if( !xFunc ){
db->nStatement = 0;
}else if( eStatementOp==0 ){
if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){
if( p->openedStatement ){
xFunc = sqlite3BtreeCommitStmt;
}
eStatementOp = SAVEPOINT_RELEASE;
}else if( p->errorAction==OE_Abort ){
xFunc = sqlite3BtreeRollbackStmt;
eStatementOp = SAVEPOINT_ROLLBACK;
}else{
invalidateCursorsOnModifiedBtrees(db);
sqlite3RollbackAll(db);
@ -1632,33 +1758,26 @@ int sqlite3VdbeHalt(Vdbe *p){
}
}
/* If xFunc is not NULL, then it is one of sqlite3BtreeRollbackStmt or
** sqlite3BtreeCommitStmt. Call it once on each backend. If an error occurs
** and the return code is still SQLITE_OK, set the return code to the new
** error value.
/* If eStatementOp is non-zero, then a statement transaction needs to
** be committed or rolled back. Call sqlite3VdbeCloseStatement() to
** do so. If this operation returns an error, and the current statement
** error code is SQLITE_OK or SQLITE_CONSTRAINT, then set the error
** code to the new value.
*/
assert(!xFunc ||
xFunc==sqlite3BtreeCommitStmt ||
xFunc==sqlite3BtreeRollbackStmt
);
for(i=0; xFunc && i<db->nDb; i++){
int rc;
Btree *pBt = db->aDb[i].pBt;
if( pBt ){
rc = xFunc(pBt);
if( rc && (p->rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT) ){
p->rc = rc;
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = 0;
}
if( eStatementOp ){
rc = sqlite3VdbeCloseStatement(p, eStatementOp);
if( rc && (p->rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT) ){
p->rc = rc;
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = 0;
}
}
/* If this was an INSERT, UPDATE or DELETE and the statement was committed,
** set the change counter.
/* If this was an INSERT, UPDATE or DELETE and no statement transaction
** has been rolled back, update the database connection change-counter.
*/
if( p->changeCntOn && p->pc>=0 ){
if( !xFunc || xFunc==sqlite3BtreeCommitStmt ){
if( eStatementOp!=SAVEPOINT_ROLLBACK ){
sqlite3VdbeSetChanges(db, p->nChange);
}else{
sqlite3VdbeSetChanges(db, 0);
@ -1690,6 +1809,15 @@ int sqlite3VdbeHalt(Vdbe *p){
p->rc = SQLITE_NOMEM;
}
/* If the auto-commit flag is set to true, then any locks that were held
** by connection db have now been released. Call sqlite3ConnectionUnlocked()
** to invoke any required unlock-notify callbacks.
*/
if( db->autoCommit ){
sqlite3ConnectionUnlocked(db);
}
assert( db->activeVdbeCnt>0 || db->autoCommit==0 || db->nStatement==0 );
return SQLITE_OK;
}
@ -1847,17 +1975,15 @@ void sqlite3VdbeDelete(Vdbe *p){
sqlite3DbFree(db, pOp->zComment);
#endif
}
sqlite3DbFree(db, p->aOp);
}
releaseMemArray(p->aVar, p->nVar);
sqlite3DbFree(db, p->aLabel);
if( p->aMem ){
sqlite3DbFree(db, &p->aMem[1]);
}
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
sqlite3DbFree(db, p->aColName);
sqlite3DbFree(db, p->zSql);
p->magic = VDBE_MAGIC_DEAD;
sqlite3DbFree(db, p->aOp);
sqlite3DbFree(db, p->pFree);
sqlite3DbFree(db, p);
}
@ -2221,30 +2347,40 @@ UnpackedRecord *sqlite3VdbeRecordUnpack(
KeyInfo *pKeyInfo, /* Information about the record format */
int nKey, /* Size of the binary record */
const void *pKey, /* The binary record */
UnpackedRecord *pSpace,/* Space available to hold resulting object */
char *pSpace, /* Unaligned space available to hold the object */
int szSpace /* Size of pSpace[] in bytes */
){
const unsigned char *aKey = (const unsigned char *)pKey;
UnpackedRecord *p;
int nByte, d;
UnpackedRecord *p; /* The unpacked record that we will return */
int nByte; /* Memory space needed to hold p, in bytes */
int d;
u32 idx;
u16 u; /* Unsigned loop counter */
u16 u; /* Unsigned loop counter */
u32 szHdr;
Mem *pMem;
int nOff; /* Increase pSpace by this much to 8-byte align it */
assert( sizeof(Mem)>sizeof(*p) );
nByte = sizeof(Mem)*(pKeyInfo->nField+2);
/*
** We want to shift the pointer pSpace up such that it is 8-byte aligned.
** Thus, we need to calculate a value, nOff, between 0 and 7, to shift
** it by. If pSpace is already 8-byte aligned, nOff should be zero.
*/
nOff = (8 - (SQLITE_PTR_TO_INT(pSpace) & 7)) & 7;
pSpace += nOff;
szSpace -= nOff;
nByte = ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nField+1);
if( nByte>szSpace ){
p = sqlite3DbMallocRaw(pKeyInfo->db, nByte);
if( p==0 ) return 0;
p->flags = UNPACKED_NEED_FREE | UNPACKED_NEED_DESTROY;
}else{
p = pSpace;
p = (UnpackedRecord*)pSpace;
p->flags = UNPACKED_NEED_DESTROY;
}
p->pKeyInfo = pKeyInfo;
p->nField = pKeyInfo->nField + 1;
p->aMem = pMem = &((Mem*)p)[1];
p->aMem = pMem = (Mem*)&((char*)p)[ROUND8(sizeof(UnpackedRecord))];
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
idx = getVarint32(aKey, szHdr);
d = szHdr;
u = 0;

View File

@ -12,7 +12,7 @@
**
** This file contains code used to implement incremental BLOB I/O.
**
** $Id: vdbeblob.c,v 1.26 2008/10/02 14:49:02 danielk1977 Exp $
** $Id: vdbeblob.c,v 1.31 2009/03/24 15:08:10 drh Exp $
*/
#include "sqliteInt.h"
@ -70,17 +70,15 @@ int sqlite3_blob_open(
/* One of the following two instructions is replaced by an
** OP_Noop before exection.
*/
{OP_SetNumColumns, 0, 0, 0}, /* 2: Num cols for cursor */
{OP_OpenRead, 0, 0, 0}, /* 3: Open cursor 0 for reading */
{OP_SetNumColumns, 0, 0, 0}, /* 4: Num cols for cursor */
{OP_OpenWrite, 0, 0, 0}, /* 5: Open cursor 0 for read/write */
{OP_OpenRead, 0, 0, 0}, /* 2: Open cursor 0 for reading */
{OP_OpenWrite, 0, 0, 0}, /* 3: Open cursor 0 for read/write */
{OP_Variable, 1, 1, 0}, /* 6: Push the rowid to the stack */
{OP_NotExists, 0, 10, 1}, /* 7: Seek the cursor */
{OP_Column, 0, 0, 1}, /* 8 */
{OP_ResultRow, 1, 0, 0}, /* 9 */
{OP_Close, 0, 0, 0}, /* 10 */
{OP_Halt, 0, 0, 0}, /* 11 */
{OP_Variable, 1, 1, 1}, /* 4: Push the rowid to the stack */
{OP_NotExists, 0, 8, 1}, /* 5: Seek the cursor */
{OP_Column, 0, 0, 1}, /* 6 */
{OP_ResultRow, 1, 0, 0}, /* 7 */
{OP_Close, 0, 0, 0}, /* 8 */
{OP_Halt, 0, 0, 0}, /* 9 */
};
Vdbe *v = 0;
@ -178,19 +176,19 @@ int sqlite3_blob_open(
/* Remove either the OP_OpenWrite or OpenRead. Set the P2
** parameter of the other to pTab->tnum.
*/
sqlite3VdbeChangeToNoop(v, (flags ? 3 : 5), 1);
sqlite3VdbeChangeP2(v, (flags ? 5 : 3), pTab->tnum);
sqlite3VdbeChangeP3(v, (flags ? 5 : 3), iDb);
sqlite3VdbeChangeToNoop(v, (flags ? 2 : 3), 1);
sqlite3VdbeChangeP2(v, (flags ? 3 : 2), pTab->tnum);
sqlite3VdbeChangeP3(v, (flags ? 3 : 2), iDb);
/* Configure the OP_SetNumColumns. Configure the cursor to
/* Configure the number of columns. Configure the cursor to
** think that the table has one more column than it really
** does. An OP_Column to retrieve this imaginary column will
** always return an SQL NULL. This is useful because it means
** we can invoke OP_Column to fill in the vdbe cursors type
** and offset cache without causing any IO.
*/
sqlite3VdbeChangeP2(v, flags ? 4 : 2, pTab->nCol+1);
sqlite3VdbeChangeP2(v, 8, pTab->nCol);
sqlite3VdbeChangeP4(v, flags ? 3 : 2, SQLITE_INT_TO_PTR(pTab->nCol+1), P4_INT32);
sqlite3VdbeChangeP2(v, 6, pTab->nCol);
if( !db->mallocFailed ){
sqlite3VdbeMakeReady(v, 1, 1, 1, 0);
}
@ -250,8 +248,8 @@ int sqlite3_blob_open(
blob_open_out:
zErr[sizeof(zErr)-1] = '\0';
if( rc!=SQLITE_OK || db->mallocFailed ){
sqlite3_finalize((sqlite3_stmt *)v);
if( v && (rc!=SQLITE_OK || db->mallocFailed) ){
sqlite3VdbeFinalize(v);
}
sqlite3Error(db, rc, (rc==SQLITE_OK?0:zErr));
rc = sqlite3ApiExit(db, rc);
@ -266,9 +264,13 @@ blob_open_out:
int sqlite3_blob_close(sqlite3_blob *pBlob){
Incrblob *p = (Incrblob *)pBlob;
int rc;
sqlite3 *db;
db = p->db;
sqlite3_mutex_enter(db->mutex);
rc = sqlite3_finalize(p->pStmt);
sqlite3DbFree(p->db, p);
sqlite3DbFree(db, p);
sqlite3_mutex_leave(db->mutex);
return rc;
}

View File

@ -15,7 +15,7 @@
** only within the VDBE. Interface routines refer to a Mem using the
** name sqlite_value
**
** $Id: vdbemem.c,v 1.137 2009/02/04 03:59:25 shane Exp $
** $Id: vdbemem.c,v 1.140 2009/04/05 12:22:09 drh Exp $
*/
#include "sqliteInt.h"
#include "vdbeInt.h"
@ -209,6 +209,7 @@ int sqlite3VdbeMemStringify(Mem *pMem, int enc){
assert( !(fg&(MEM_Str|MEM_Blob)) );
assert( fg&(MEM_Int|MEM_Real) );
assert( (pMem->flags&MEM_RowSet)==0 );
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
if( sqlite3VdbeMemGrow(pMem, nByte, 0) ){
@ -321,6 +322,10 @@ static i64 doubleToInt64(double r){
if( r<(double)minInt ){
return minInt;
}else if( r>(double)maxInt ){
/* minInt is correct here - not maxInt. It turns out that assigning
** a very large positive number to an integer results in a very large
** negative integer. This makes no sense, but it is what x86 hardware
** does so for compatibility we will do the same in software. */
return minInt;
}else{
return (i64)r;
@ -333,13 +338,15 @@ static i64 doubleToInt64(double r){
** If pMem is an integer, then the value is exact. If pMem is
** a floating-point then the value returned is the integer part.
** If pMem is a string or blob, then we make an attempt to convert
** it into a integer and return that. If pMem is NULL, return 0.
** it into a integer and return that. If pMem represents an
** an SQL-NULL value, return 0.
**
** If pMem is a string, its encoding might be changed.
** If pMem represents a string value, its encoding might be changed.
*/
i64 sqlite3VdbeIntValue(Mem *pMem){
int flags;
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
flags = pMem->flags;
if( flags & MEM_Int ){
return pMem->u.i;
@ -368,6 +375,7 @@ i64 sqlite3VdbeIntValue(Mem *pMem){
*/
double sqlite3VdbeRealValue(Mem *pMem){
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
if( pMem->flags & MEM_Real ){
return pMem->r;
}else if( pMem->flags & MEM_Int ){
@ -398,6 +406,7 @@ void sqlite3VdbeIntegerAffinity(Mem *pMem){
assert( pMem->flags & MEM_Real );
assert( (pMem->flags & MEM_RowSet)==0 );
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
pMem->u.i = doubleToInt64(pMem->r);
if( pMem->r==(double)pMem->u.i ){
@ -411,6 +420,8 @@ void sqlite3VdbeIntegerAffinity(Mem *pMem){
int sqlite3VdbeMemIntegerify(Mem *pMem){
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
assert( (pMem->flags & MEM_RowSet)==0 );
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
pMem->u.i = sqlite3VdbeIntValue(pMem);
MemSetTypeFlag(pMem, MEM_Int);
return SQLITE_OK;
@ -422,6 +433,8 @@ int sqlite3VdbeMemIntegerify(Mem *pMem){
*/
int sqlite3VdbeMemRealify(Mem *pMem){
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
pMem->r = sqlite3VdbeRealValue(pMem);
MemSetTypeFlag(pMem, MEM_Real);
return SQLITE_OK;

View File

@ -11,11 +11,16 @@
*************************************************************************
** This file contains code used to help implement virtual tables.
**
** $Id: vtab.c,v 1.81 2008/12/10 19:26:24 drh Exp $
** $Id: vtab.c,v 1.85 2009/04/11 16:27:20 drh Exp $
*/
#ifndef SQLITE_OMIT_VIRTUALTABLE
#include "sqliteInt.h"
/*
** The actual function that does the work of creating a new module.
** This function implements the sqlite3_create_module() and
** sqlite3_create_module_v2() interfaces.
*/
static int createModule(
sqlite3 *db, /* Database in which module is registered */
const char *zName, /* Name assigned to this module */
@ -97,6 +102,7 @@ void sqlite3VtabLock(sqlite3_vtab *pVtab){
** disconnect the virtual table.
*/
void sqlite3VtabUnlock(sqlite3 *db, sqlite3_vtab *pVtab){
assert( pVtab->nRef>0 );
pVtab->nRef--;
assert(db);
assert( sqlite3SafetyCheckOk(db) );
@ -118,7 +124,8 @@ void sqlite3VtabUnlock(sqlite3 *db, sqlite3_vtab *pVtab){
*/
void sqlite3VtabClear(Table *p){
sqlite3_vtab *pVtab = p->pVtab;
sqlite3 *db = p->db;
Schema *pSchema = p->pSchema;
sqlite3 *db = pSchema ? pSchema->db : 0;
if( pVtab ){
assert( p->pMod && p->pMod->pModule );
sqlite3VtabUnlock(db, pVtab);
@ -571,7 +578,9 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
}
sParse.declareVtab = 0;
sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe);
if( sParse.pVdbe ){
sqlite3VdbeFinalize(sParse.pVdbe);
}
sqlite3DeleteTable(sParse.pNewTable);
sParse.pNewTable = 0;
@ -711,7 +720,7 @@ int sqlite3VtabBegin(sqlite3 *db, sqlite3_vtab *pVtab){
/* Special case: If db->aVTrans is NULL and db->nVTrans is greater
** than zero, then this function is being called from within a
** virtual module xSync() callback. It is illegal to write to
** virtual module tables in this case, so return SQLITE_LOCKED.
** virtual module tables in this case, so return SQLITE_MISUSE.
*/
if( sqlite3VtabInSync(db) ){
return SQLITE_LOCKED;

View File

@ -12,7 +12,7 @@
** This file contains routines used for walking the parser tree for
** an SQL statement.
**
** $Id: walker.c,v 1.1 2008/08/20 16:35:10 drh Exp $
** $Id: walker.c,v 1.4 2009/04/08 13:51:52 drh Exp $
*/
#include "sqliteInt.h"
#include <stdlib.h>
@ -41,13 +41,18 @@
int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){
int rc;
if( pExpr==0 ) return WRC_Continue;
testcase( ExprHasProperty(pExpr, EP_TokenOnly) );
testcase( ExprHasProperty(pExpr, EP_SpanToken) );
testcase( ExprHasProperty(pExpr, EP_Reduced) );
rc = pWalker->xExprCallback(pWalker, pExpr);
if( rc==WRC_Continue ){
if( rc==WRC_Continue
&& !ExprHasAnyProperty(pExpr,EP_TokenOnly|EP_SpanToken) ){
if( sqlite3WalkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort;
if( sqlite3WalkExpr(pWalker, pExpr->pRight) ) return WRC_Abort;
if( sqlite3WalkExprList(pWalker, pExpr->pList) ) return WRC_Abort;
if( sqlite3WalkSelect(pWalker, pExpr->pSelect) ){
return WRC_Abort;
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort;
}else{
if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort;
}
}
return rc & WRC_Abort;

View File

@ -16,7 +16,7 @@
** so is applicable. Because this module is responsible for selecting
** indices, you might also think of this module as the "query optimizer".
**
** $Id: where.c,v 1.368 2009/02/04 03:59:25 shane Exp $
** $Id: where.c,v 1.382 2009/04/07 13:48:12 drh Exp $
*/
#include "sqliteInt.h"
@ -26,7 +26,7 @@
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
int sqlite3WhereTrace = 0;
#endif
#if 0
#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
# define WHERETRACE(X) if(sqlite3WhereTrace) sqlite3DebugPrintf X
#else
# define WHERETRACE(X)
@ -431,8 +431,11 @@ static Bitmask exprTableUsage(WhereMaskSet *pMaskSet, Expr *p){
}
mask = exprTableUsage(pMaskSet, p->pRight);
mask |= exprTableUsage(pMaskSet, p->pLeft);
mask |= exprListTableUsage(pMaskSet, p->pList);
mask |= exprSelectTableUsage(pMaskSet, p->pSelect);
if( ExprHasProperty(p, EP_xIsSelect) ){
mask |= exprSelectTableUsage(pMaskSet, p->x.pSelect);
}else{
mask |= exprListTableUsage(pMaskSet, p->x.pList);
}
return mask;
}
static Bitmask exprListTableUsage(WhereMaskSet *pMaskSet, ExprList *pList){
@ -634,7 +637,7 @@ static int isLikeOrGlob(
#ifdef SQLITE_EBCDIC
if( *pnoCase ) return 0;
#endif
pList = pExpr->pList;
pList = pExpr->x.pList;
pRight = pList->a[0].pExpr;
if( pRight->op!=TK_STRING ){
return 0;
@ -653,7 +656,7 @@ static int isLikeOrGlob(
(pColl->type!=SQLITE_COLL_NOCASE || !*pnoCase) ){
return 0;
}
sqlite3DequoteExpr(db, pRight);
sqlite3DequoteExpr(pRight);
z = (char *)pRight->token.z;
cnt = 0;
if( z ){
@ -689,7 +692,7 @@ static int isMatchOfColumn(
sqlite3StrNICmp((const char*)pExpr->token.z,"match",5)!=0 ){
return 0;
}
pList = pExpr->pList;
pList = pExpr->x.pList;
if( pList->nExpr!=2 ){
return 0;
}
@ -953,17 +956,18 @@ static void exprAnalyzeOrTerm(
assert( pOrTerm->eOperator==WO_EQ );
assert( pOrTerm->leftCursor==iCursor );
assert( pOrTerm->u.leftColumn==iColumn );
pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight);
pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight, 0);
pList = sqlite3ExprListAppend(pWC->pParse, pList, pDup, 0);
pLeft = pOrTerm->pExpr->pLeft;
}
assert( pLeft!=0 );
pDup = sqlite3ExprDup(db, pLeft);
pDup = sqlite3ExprDup(db, pLeft, 0);
pNew = sqlite3Expr(db, TK_IN, pDup, 0, 0);
if( pNew ){
int idxNew;
transferJoinMarkings(pNew, pExpr);
pNew->pList = pList;
assert( !ExprHasProperty(pNew, EP_xIsSelect) );
pNew->x.pList = pList;
idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC);
testcase( idxNew==0 );
exprAnalyze(pSrc, pWC, idxNew);
@ -1026,8 +1030,11 @@ static void exprAnalyze(
op = pExpr->op;
if( op==TK_IN ){
assert( pExpr->pRight==0 );
pTerm->prereqRight = exprListTableUsage(pMaskSet, pExpr->pList)
| exprSelectTableUsage(pMaskSet, pExpr->pSelect);
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
pTerm->prereqRight = exprSelectTableUsage(pMaskSet, pExpr->x.pSelect);
}else{
pTerm->prereqRight = exprListTableUsage(pMaskSet, pExpr->x.pList);
}
}else if( op==TK_ISNULL ){
pTerm->prereqRight = 0;
}else{
@ -1057,7 +1064,7 @@ static void exprAnalyze(
Expr *pDup;
if( pTerm->leftCursor>=0 ){
int idxNew;
pDup = sqlite3ExprDup(db, pExpr);
pDup = sqlite3ExprDup(db, pExpr, 0);
if( db->mallocFailed ){
sqlite3ExprDelete(db, pDup);
return;
@ -1100,7 +1107,7 @@ static void exprAnalyze(
** BETWEEN term is skipped.
*/
else if( pExpr->op==TK_BETWEEN && pWC->op==TK_AND ){
ExprList *pList = pExpr->pList;
ExprList *pList = pExpr->x.pList;
int i;
static const u8 ops[] = {TK_GE, TK_LE};
assert( pList!=0 );
@ -1108,8 +1115,8 @@ static void exprAnalyze(
for(i=0; i<2; i++){
Expr *pNewExpr;
int idxNew;
pNewExpr = sqlite3Expr(db, ops[i], sqlite3ExprDup(db, pExpr->pLeft),
sqlite3ExprDup(db, pList->a[i].pExpr), 0);
pNewExpr = sqlite3Expr(db, ops[i], sqlite3ExprDup(db, pExpr->pLeft, 0),
sqlite3ExprDup(db, pList->a[i].pExpr, 0), 0);
idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
testcase( idxNew==0 );
exprAnalyze(pSrc, pWC, idxNew);
@ -1148,18 +1155,18 @@ static void exprAnalyze(
Expr *pNewExpr1, *pNewExpr2;
int idxNew1, idxNew2;
pLeft = pExpr->pList->a[1].pExpr;
pRight = pExpr->pList->a[0].pExpr;
pLeft = pExpr->x.pList->a[1].pExpr;
pRight = pExpr->x.pList->a[0].pExpr;
pStr1 = sqlite3PExpr(pParse, TK_STRING, 0, 0, 0);
if( pStr1 ){
sqlite3TokenCopy(db, &pStr1->token, &pRight->token);
pStr1->token.n = nPattern;
pStr1->flags = EP_Dequoted;
}
pStr2 = sqlite3ExprDup(db, pStr1);
pStr2 = sqlite3ExprDup(db, pStr1, 0);
if( !db->mallocFailed ){
u8 c, *pC;
assert( pStr2->token.dyn );
/* assert( pStr2->token.dyn ); */
pC = (u8*)&pStr2->token.z[nPattern-1];
c = *pC;
if( noCase ){
@ -1168,11 +1175,11 @@ static void exprAnalyze(
}
*pC = c + 1;
}
pNewExpr1 = sqlite3PExpr(pParse, TK_GE, sqlite3ExprDup(db,pLeft), pStr1, 0);
pNewExpr1 = sqlite3PExpr(pParse, TK_GE, sqlite3ExprDup(db,pLeft,0),pStr1,0);
idxNew1 = whereClauseInsert(pWC, pNewExpr1, TERM_VIRTUAL|TERM_DYNAMIC);
testcase( idxNew1==0 );
exprAnalyze(pSrc, pWC, idxNew1);
pNewExpr2 = sqlite3PExpr(pParse, TK_LT, sqlite3ExprDup(db,pLeft), pStr2, 0);
pNewExpr2 = sqlite3PExpr(pParse, TK_LT, sqlite3ExprDup(db,pLeft,0),pStr2,0);
idxNew2 = whereClauseInsert(pWC, pNewExpr2, TERM_VIRTUAL|TERM_DYNAMIC);
testcase( idxNew2==0 );
exprAnalyze(pSrc, pWC, idxNew2);
@ -1198,13 +1205,13 @@ static void exprAnalyze(
WhereTerm *pNewTerm;
Bitmask prereqColumn, prereqExpr;
pRight = pExpr->pList->a[0].pExpr;
pLeft = pExpr->pList->a[1].pExpr;
pRight = pExpr->x.pList->a[0].pExpr;
pLeft = pExpr->x.pList->a[1].pExpr;
prereqExpr = exprTableUsage(pMaskSet, pRight);
prereqColumn = exprTableUsage(pMaskSet, pLeft);
if( (prereqExpr & prereqColumn)==0 ){
Expr *pNewExpr;
pNewExpr = sqlite3Expr(db, TK_MATCH, 0, sqlite3ExprDup(db, pRight), 0);
pNewExpr = sqlite3Expr(db, TK_MATCH, 0, sqlite3ExprDup(db, pRight, 0), 0);
idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
testcase( idxNew==0 );
pNewTerm = &pWC->a[idxNew];
@ -1708,15 +1715,15 @@ static double bestVirtualIndex(
** * Whether or not there must be separate lookups in the
** index and in the main table.
**
** If there was an INDEXED BY clause attached to the table in the SELECT
** statement, then this function only considers plans using the
** named index. If one cannot be found, then the returned cost is
** SQLITE_BIG_DBL. If a plan can be found that uses the named index,
** If there was an INDEXED BY clause (pSrc->pIndex) attached to the table in
** the SQL statement, then this function only considers plans using the
** named index. If no such plan is found, then the returned cost is
** SQLITE_BIG_DBL. If a plan is found that uses the named index,
** then the cost is calculated in the usual way.
**
** If a NOT INDEXED clause was attached to the table in the SELECT
** statement, then no indexes are considered. However, the selected
** plan may still take advantage of the tables built-in rowid
** If a NOT INDEXED clause (pSrc->notIndexed!=0) was attached to the table
** in the SELECT statement, then no indexes are considered. However, the
** selected plan may still take advantage of the tables built-in rowid
** index.
*/
static void bestIndex(
@ -1755,6 +1762,13 @@ static void bestIndex(
if( pProbe==0 &&
findTerm(pWC, iCur, -1, 0, WO_EQ|WO_IN|WO_LT|WO_LE|WO_GT|WO_GE,0)==0 &&
(pOrderBy==0 || !sortableByRowid(iCur, pOrderBy, pWC->pMaskSet, &rev)) ){
if( pParse->db->flags & SQLITE_ReverseOrder ){
/* For application testing, randomly reverse the output order for
** SELECT statements that omit the ORDER BY clause. This will help
** to find cases where
*/
pCost->plan.wsFlags |= WHERE_REVERSE;
}
return;
}
pCost->rCost = SQLITE_BIG_DBL;
@ -1776,10 +1790,12 @@ static void bestIndex(
pCost->rCost = 0;
pCost->nRow = 1;
return;
}else if( (pExpr = pTerm->pExpr)->pList!=0 ){
}else if( !ExprHasProperty((pExpr = pTerm->pExpr), EP_xIsSelect)
&& pExpr->x.pList
){
/* Rowid IN (LIST): cost is NlogN where N is the number of list
** elements. */
pCost->rCost = pCost->nRow = pExpr->pList->nExpr;
pCost->rCost = pCost->nRow = pExpr->x.pList->nExpr;
pCost->rCost *= estLog(pCost->rCost);
}else{
/* Rowid IN (SELECT): cost is NlogN where N is the number of rows
@ -1828,7 +1844,15 @@ static void bestIndex(
cost += cost*estLog(cost);
WHERETRACE(("... sorting increases cost to %.9g\n", cost));
}
}else if( pParse->db->flags & SQLITE_ReverseOrder ){
/* For application testing, randomly reverse the output order for
** SELECT statements that omit the ORDER BY clause. This will help
** to find cases where
*/
wsFlags |= WHERE_REVERSE;
}
/* Remember this case if it is the best so far */
if( cost<pCost->rCost ){
pCost->rCost = cost;
pCost->nRow = nRow;
@ -1909,12 +1933,18 @@ static void bestIndex(
pProbe = pSrc->pIndex;
}
for(; pProbe; pProbe=(pSrc->pIndex ? 0 : pProbe->pNext)){
double inMultiplier = 1;
double inMultiplier = 1; /* Number of equality look-ups needed */
int inMultIsEst = 0; /* True if inMultiplier is an estimate */
WHERETRACE(("... index %s:\n", pProbe->zName));
/* Count the number of columns in the index that are satisfied
** by x=EXPR constraints or x IN (...) constraints.
** by x=EXPR constraints or x IN (...) constraints. For a term
** of the form x=EXPR we only have to do a single binary search.
** But for x IN (...) we have to do a number of binary searched
** equal to the number of entries on the RHS of the IN operator.
** The inMultipler variable with try to estimate the number of
** binary searches needed.
*/
wsFlags = 0;
for(i=0; i<pProbe->nColumn; i++){
@ -1925,23 +1955,33 @@ static void bestIndex(
if( pTerm->eOperator & WO_IN ){
Expr *pExpr = pTerm->pExpr;
wsFlags |= WHERE_COLUMN_IN;
if( pExpr->pSelect!=0 ){
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
inMultiplier *= 25;
}else if( pExpr->pList ){
inMultiplier *= pExpr->pList->nExpr + 1;
inMultIsEst = 1;
}else if( pExpr->x.pList ){
inMultiplier *= pExpr->x.pList->nExpr + 1;
}
}
}
nRow = pProbe->aiRowEst[i] * inMultiplier;
cost = nRow * estLog(inMultiplier);
/* If inMultiplier is an estimate and that estimate results in an
** nRow it that is more than half number of rows in the table,
** then reduce inMultipler */
if( inMultIsEst && nRow*2 > pProbe->aiRowEst[0] ){
nRow = pProbe->aiRowEst[0]/2;
inMultiplier = nRow/pProbe->aiRowEst[i];
}
cost = nRow + inMultiplier*estLog(pProbe->aiRowEst[0]);
nEq = i;
if( pProbe->onError!=OE_None && (wsFlags & WHERE_COLUMN_IN)==0
&& nEq==pProbe->nColumn ){
wsFlags |= WHERE_UNIQUE;
}
WHERETRACE(("...... nEq=%d inMult=%.9g cost=%.9g\n",nEq,inMultiplier,cost));
WHERETRACE(("...... nEq=%d inMult=%.9g nRow=%.9g cost=%.9g\n",
nEq, inMultiplier, nRow, cost));
/* Look for range constraints
/* Look for range constraints. Assume that each range constraint
** makes the search space 1/3rd smaller.
*/
if( nEq<pProbe->nColumn ){
int j = pProbe->aiColumn[nEq];
@ -1958,7 +1998,8 @@ static void bestIndex(
cost /= 3;
nRow /= 3;
}
WHERETRACE(("...... range reduces cost to %.9g\n", cost));
WHERETRACE(("...... range reduces nRow to %.9g and cost to %.9g\n",
nRow, cost));
}
}
@ -1978,6 +2019,12 @@ static void bestIndex(
cost += cost*estLog(cost);
WHERETRACE(("...... orderby increases cost to %.9g\n", cost));
}
}else if( pParse->db->flags & SQLITE_ReverseOrder ){
/* For application testing, randomly reverse the output order for
** SELECT statements that omit the ORDER BY clause. This will help
** to find cases where
*/
wsFlags |= WHERE_REVERSE;
}
/* Check to see if we can get away with using just the index without
@ -2738,11 +2785,13 @@ static Bitmask codeOneLoopStart(
/* Case 5: There is no usable index. We must do a complete
** scan of the entire table.
*/
static const u8 aStep[] = { OP_Next, OP_Prev };
static const u8 aStart[] = { OP_Rewind, OP_Last };
assert( bRev==0 || bRev==1 );
assert( omitTable==0 );
assert( bRev==0 );
pLevel->op = OP_Next;
pLevel->op = aStep[bRev];
pLevel->p1 = iCur;
pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, OP_Rewind, iCur, addrBrk);
pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk);
pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
codeRowSetEarly = 0;
}
@ -2836,7 +2885,7 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
assert( pInfo->needToFreeIdxStr==0 || db->mallocFailed );
if( pInfo->needToFreeIdxStr ){
sqlite3_free(pInfo->idxStr);
}
}
sqlite3DbFree(db, pInfo);
}
}
@ -2943,6 +2992,7 @@ WhereInfo *sqlite3WhereBegin(
int regRowSet /* Register hold RowSet if WHERE_FILL_ROWSET is set */
){
int i; /* Loop counter */
int nByteWInfo; /* Num. bytes allocated for WhereInfo struct */
WhereInfo *pWInfo; /* Will become the return value of this function */
Vdbe *v = pParse->pVdbe; /* The virtual database engine */
Bitmask notReady; /* Cursors that are not yet positioned */
@ -2968,15 +3018,19 @@ WhereInfo *sqlite3WhereBegin(
}
/* Allocate and initialize the WhereInfo structure that will become the
** return value.
** return value. A single allocation is used to store the WhereInfo
** struct, the contents of WhereInfo.a[], the WhereClause structure
** and the WhereMaskSet structure. Since WhereClause contains an 8-byte
** field (type Bitmask) it must be aligned on an 8-byte boundary on
** some architectures. Hence the ROUND8() below.
*/
db = pParse->db;
pWInfo = sqlite3DbMallocZero(db,
sizeof(WhereInfo)
+ (pTabList->nSrc-1)*sizeof(WhereLevel)
+ sizeof(WhereClause)
+ sizeof(WhereMaskSet)
);
nByteWInfo = ROUND8(sizeof(WhereInfo)+(pTabList->nSrc-1)*sizeof(WhereLevel));
pWInfo = sqlite3DbMallocZero(db,
nByteWInfo +
sizeof(WhereClause) +
sizeof(WhereMaskSet)
);
if( db->mallocFailed ){
goto whereBeginError;
}
@ -2985,7 +3039,7 @@ WhereInfo *sqlite3WhereBegin(
pWInfo->pTabList = pTabList;
pWInfo->iBreak = sqlite3VdbeMakeLabel(v);
pWInfo->regRowSet = (wctrlFlags & WHERE_FILL_ROWSET) ? regRowSet : -1;
pWInfo->pWC = pWC = (WhereClause*)&pWInfo->a[pWInfo->nLevel];
pWInfo->pWC = pWC = (WhereClause *)&((u8 *)pWInfo)[nByteWInfo];
pWInfo->wctrlFlags = wctrlFlags;
pMaskSet = (WhereMaskSet*)&pWC[1];
@ -3231,7 +3285,7 @@ WhereInfo *sqlite3WhereBegin(
Bitmask b = pTabItem->colUsed;
int n = 0;
for(; b; b=b>>1, n++){}
sqlite3VdbeChangeP2(v, sqlite3VdbeCurrentAddr(v)-2, n);
sqlite3VdbeChangeP4(v, sqlite3VdbeCurrentAddr(v)-1, SQLITE_INT_TO_PTR(n), P4_INT32);
assert( n<=pTab->nCol );
}
}else{
@ -3244,7 +3298,6 @@ WhereInfo *sqlite3WhereBegin(
int iIdxCur = pLevel->iIdxCur;
assert( pIx->pSchema==pTab->pSchema );
assert( iIdxCur>=0 );
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, pIx->nColumn+1);
sqlite3VdbeAddOp4(v, OP_OpenRead, iIdxCur, pIx->tnum, iDb,
(char*)pKey, P4_KEYINFO_HANDOFF);
VdbeComment((v, "%s", pIx->zName));

View File

@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The
# focus of this script is testing the ALTER TABLE statement.
#
# $Id: alter.test,v 1.31 2009/02/13 03:43:32 drh Exp $
# $Id: alter.test,v 1.32 2009/03/24 15:08:10 drh Exp $
#
set testdir [file dirname $argv0]
@ -677,7 +677,7 @@ do_test alter-9.2 {
execsql {
SELECT SQLITE_RENAME_TABLE(0,0);
SELECT SQLITE_RENAME_TABLE(10,20);
SELECT SQLITE_RENAME_TABLE("foo", "foo");
SELECT SQLITE_RENAME_TABLE('foo', 'foo');
}
} {{} {} {}}

View File

@ -13,7 +13,7 @@
# file format change that may be used in the future to implement
# "ALTER TABLE ... ADD COLUMN".
#
# $Id: alter2.test,v 1.13 2008/03/19 00:21:31 drh Exp $
# $Id: alter2.test,v 1.14 2009/04/07 14:14:22 danielk1977 Exp $
#
set testdir [file dirname $argv0]
@ -220,6 +220,8 @@ ifcapable trigger {
SELECT * FROM clog;
}
} {{} 2 {} 6 {} 10}
} else {
execsql { CREATE TABLE abc3(a, b); }
}
#---------------------------------------------------------------------
@ -276,9 +278,7 @@ ifcapable vacuum {
get_file_format
} {2}
do_test alter2-5.2 {
execsql {
VACUUM;
}
execsql { VACUUM }
} {}
do_test alter2-5.3 {
get_file_format

View File

@ -6,7 +6,7 @@
#***********************************************************************
# This file runs all tests.
#
# $Id: async.test,v 1.14 2008/09/15 14:47:21 danielk1977 Exp $
# $Id: async.test,v 1.19 2009/04/11 10:25:04 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@ -17,15 +17,16 @@ if {[catch {sqlite3async_enable}]} {
return
}
rename finish_test really_finish_test
rename finish_test async_really_finish_test
proc finish_test {} {
catch {db close}
catch {db2 close}
catch {db3 close}
}
if {[info exists ISQUICK]} { set ASYNC_SAVE_ISQUICK $ISQUICK }
set ISQUICK 1
set INCLUDE {
set ASYNC_INCLUDE {
insert.test
insert2.test
insert3.test
@ -42,9 +43,9 @@ set INCLUDE {
# Enable asynchronous IO.
sqlite3async_enable 1
rename do_test really_do_test
rename do_test async_really_do_test
proc do_test {name args} {
uplevel really_do_test async_io-$name $args
uplevel async_really_do_test async_io-$name $args
sqlite3async_start
sqlite3async_halt idle
sqlite3async_wait
@ -53,7 +54,7 @@ proc do_test {name args} {
foreach testfile [lsort -dictionary [glob $testdir/*.test]] {
set tail [file tail $testfile]
if {[lsearch -exact $INCLUDE $tail]<0} continue
if {[lsearch -exact $ASYNC_INCLUDE $tail]<0} continue
source $testfile
# Make sure everything is flushed through. This is because [source]ing
@ -77,6 +78,11 @@ sqlite3async_halt never
sqlite3async_enable 0
set sqlite3async_trace 0
really_finish_test
rename really_do_test do_test
rename really_finish_test finish_test
rename do_test {}
rename async_really_do_test do_test
rename finish_test {}
rename async_really_finish_test finish_test
if {[info exists ASYNC_SAVE_ISQUICK]} { set ISQUICK $ASYNC_SAVE_ISQUICK }
finish_test

View File

@ -5,7 +5,7 @@
#
#***********************************************************************
#
# $Id: async2.test,v 1.9 2007/11/05 17:01:08 danielk1977 Exp $
# $Id: async2.test,v 1.10 2009/03/24 17:43:57 drh Exp $
set testdir [file dirname $argv0]
@ -47,7 +47,7 @@ set sql_script {
db close
foreach err [list ioerr malloc-transient malloc-persistent] {
set ::go 1
set ::go 10
for {set n 1} {$::go} {incr n} {
set ::sqlite_io_error_pending 0
sqlite3_memdebug_fail -1
@ -58,6 +58,7 @@ foreach err [list ioerr malloc-transient malloc-persistent] {
sqlite3async_enable 1
sqlite3 db test.db
sqlite3_db_config_lookaside db 0 0 0
switch -- $err {
ioerr { set ::sqlite_io_error_pending $n }
@ -78,7 +79,7 @@ foreach err [list ioerr malloc-transient malloc-persistent] {
sqlite3_memdebug_fail -1
sqlite3 db test.db
set c [db eval {SELECT c FROM counter LIMIT 1}]
set c [db one {SELECT c FROM counter LIMIT 1}]
switch -- $c {
1 {
do_test async-$err-1.1.$n {
@ -112,7 +113,7 @@ foreach err [list ioerr malloc-transient malloc-persistent] {
} {klmnopqrst and seven}
}
FIN {
set ::go 0
incr ::go -1
}
}

View File

@ -13,7 +13,7 @@
# Specifically, it tests that the xFullPathname() method of
# of the asynchronous vfs works correctly.
#
# $Id: async3.test,v 1.3 2007/11/05 17:01:08 danielk1977 Exp $
# $Id: async3.test,v 1.4 2009/03/28 18:56:14 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@ -27,6 +27,7 @@ if { [info commands sqlite3async_enable]=="" } {
db close
sqlite3async_enable 1
#set sqlite3async_trace 1
sqlite3async_start
set paths {
@ -67,6 +68,7 @@ foreach p $paths {
}
db close
sqlite3async_halt idle
sqlite3async_wait
sqlite3async_halt never

View File

@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The
# focus of this file is testing the SELECT statement.
#
# $Id: autovacuum.test,v 1.28 2008/09/10 10:57:28 danielk1977 Exp $
# $Id: autovacuum.test,v 1.29 2009/04/06 17:50:03 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@ -660,6 +660,37 @@ do_test autovacuum-8.2 {
} {1 {database is locked}}
catch {db2 close}
catch {db eval {COMMIT}}
do_test autovacuum-9.1 {
execsql {
DROP TABLE t1;
DROP TABLE t2;
DROP TABLE t3;
DROP TABLE t4;
DROP TABLE t5;
PRAGMA page_count;
}
} {1}
do_test autovacuum-9.2 {
file size test.db
} 1024
do_test autovacuum-9.3 {
execsql {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
INSERT INTO t1 VALUES(NULL, randstr(50,50));
}
for {set ii 0} {$ii < 10} {incr ii} {
db eval { INSERT INTO t1 SELECT NULL, randstr(50,50) FROM t1 }
}
file size test.db
} $::sqlite_pending_byte
do_test autovacuum-9.4 {
execsql { INSERT INTO t1 SELECT NULL, randstr(50,50) FROM t1 }
} {}
do_test autovacuum-9.5 {
execsql { DELETE FROM t1 WHERE rowid > (SELECT max(a)/2 FROM t1) }
file size test.db
} $::sqlite_pending_byte
finish_test

View File

@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The
# focus of this file is testing the sqlite3_backup_XXX API.
#
# $Id: backup.test,v 1.8 2009/02/12 17:01:50 danielk1977 Exp $
# $Id: backup.test,v 1.9 2009/03/16 13:19:36 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@ -736,7 +736,7 @@ do_test backup-7.2.1 {
} {}
do_test backup-7.2.2 {
B step 5000
} {SQLITE_LOCKED}
} {SQLITE_BUSY}
do_test backup-7.2.3 {
execsql { ROLLBACK }
B step 5000

View File

@ -13,11 +13,13 @@
# of the TCL interface - methods which are based on the
# sqlite3_backup_XXX API.
#
# $Id: backup2.test,v 1.2 2009/02/11 16:06:19 shane Exp $
# $Id: backup2.test,v 1.4 2009/04/07 14:14:23 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !trigger||!view { finish_test ; return }
# Fill a database with test data.
#
do_test backup2-1 {
@ -111,8 +113,8 @@ do_test backup2-6 {
# Try to backup to something that is not a database file.
#
do_test backup2-7 {
catch {file attributes bu2.db -permissions rw-------}
catch {file attributes bu2.db -readonly 0}
catch {file attributes bu2.db -permissions rw-------}
set out [open bu2.db w]
puts $out "This is not a valid database file"
close $out

View File

@ -12,7 +12,7 @@
# focus of this file is testing the handling of IO errors by the
# sqlite3_backup_XXX APIs.
#
# $Id: backup_ioerr.test,v 1.2 2009/02/04 22:46:47 drh Exp $
# $Id: backup_ioerr.test,v 1.3 2009/04/10 18:41:01 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@ -53,7 +53,7 @@ proc populate_database {db {xtra_large 0}} {
do_test backup_ioerr-1.1 {
populate_database db
set nPage [expr {[file size test.db] / 1024}]
expr {$nPage>140 && $nPage<150}
expr {$nPage>130 && $nPage<160}
} {1}
do_test backup_ioerr-1.2 {
expr {[file size test.db] > $sqlite_pending_byte}

View File

@ -12,7 +12,7 @@
# focus of this script testing the ability of SQLite to handle database
# files larger than 4GB.
#
# $Id: bigfile.test,v 1.11 2008/11/21 22:21:51 drh Exp $
# $Id: bigfile.test,v 1.12 2009/03/05 04:27:08 shane Exp $
#
set testdir [file dirname $argv0]
@ -66,7 +66,6 @@ do_test bigfile-1.1 {
db close
if {[catch {fake_big_file 4096 [pwd]/test.db} msg]} {
puts "**** Unable to create a file larger than 4096 MB. *****"
puts "$msg"
finish_test
return
}
@ -83,7 +82,11 @@ do_test bigfile-1.2 {
# tests. We will know the above test failed because the "db" command
# does not exist.
#
if {[llength [info command db]]>0} {
if {[llength [info command db]]<=0} {
puts "**** Large file support appears to be broken. *****"
finish_test
return
}
do_test bigfile-1.3 {
execsql {
@ -98,11 +101,6 @@ do_test bigfile-1.4 {
SELECT md5sum(x) FROM t1;
}
} $::MAGIC_SUM
do_test bigfile-1.5 {
execsql {
SELECT md5sum(x) FROM t2;
}
} $::MAGIC_SUM
db close
if {[catch {fake_big_file 8192 [pwd]/test.db}]} {
@ -111,12 +109,18 @@ if {[catch {fake_big_file 8192 [pwd]/test.db}]} {
return
}
do_test bigfile-1.6 {
do_test bigfile-1.5 {
sqlite3 db test.db
execsql {
SELECT md5sum(x) FROM t1;
}
} $::MAGIC_SUM
do_test bigfile-1.6 {
sqlite3 db test.db
execsql {
SELECT md5sum(x) FROM t2;
}
} $::MAGIC_SUM
do_test bigfile-1.7 {
execsql {
CREATE TABLE t3 AS SELECT * FROM t1;
@ -135,11 +139,6 @@ do_test bigfile-1.9 {
SELECT md5sum(x) FROM t2;
}
} $::MAGIC_SUM
do_test bigfile-1.10 {
execsql {
SELECT md5sum(x) FROM t3;
}
} $::MAGIC_SUM
db close
if {[catch {fake_big_file 16384 [pwd]/test.db}]} {
@ -148,33 +147,40 @@ if {[catch {fake_big_file 16384 [pwd]/test.db}]} {
return
}
do_test bigfile-1.11 {
do_test bigfile-1.10 {
sqlite3 db test.db
execsql {
SELECT md5sum(x) FROM t1;
}
} $::MAGIC_SUM
do_test bigfile-1.11 {
sqlite3 db test.db
execsql {
SELECT md5sum(x) FROM t2;
}
} $::MAGIC_SUM
do_test bigfile-1.12 {
sqlite3 db test.db
execsql {
SELECT md5sum(x) FROM t3;
}
} $::MAGIC_SUM
do_test bigfile-1.13 {
execsql {
CREATE TABLE t4 AS SELECT * FROM t1;
SELECT md5sum(x) FROM t4;
}
} $::MAGIC_SUM
do_test bigfile-1.13 {
do_test bigfile-1.14 {
db close
sqlite3 db test.db
execsql {
SELECT md5sum(x) FROM t1;
}
} $::MAGIC_SUM
do_test bigfile-1.14 {
execsql {
SELECT md5sum(x) FROM t2;
}
} $::MAGIC_SUM
do_test bigfile-1.15 {
execsql {
SELECT md5sum(x) FROM t3;
SELECT md5sum(x) FROM t2;
}
} $::MAGIC_SUM
do_test bigfile-1.16 {
@ -182,12 +188,5 @@ do_test bigfile-1.16 {
SELECT md5sum(x) FROM t3;
}
} $::MAGIC_SUM
do_test bigfile-1.17 {
execsql {
SELECT md5sum(x) FROM t4;
}
} $::MAGIC_SUM
} ;# End of the "if( db command exists )"
finish_test

View File

@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The
# focus of this script testing the sqlite_bind API.
#
# $Id: bind.test,v 1.46 2009/02/09 05:18:33 danielk1977 Exp $
# $Id: bind.test,v 1.47 2009/02/20 03:55:05 drh Exp $
#
set testdir [file dirname $argv0]
@ -683,4 +683,76 @@ do_test bind-14.4 {
param_names db { SELECT @a, @b FROM (SELECT NULL) }
} {@a @b}
#--------------------------------------------------------------------------
# Tests of the OP_Variable opcode where P3>1
#
do_test bind-15.1 {
db eval {CREATE TABLE t4(a,b,c,d,e,f,g,h);}
set VM [sqlite3_prepare db {
INSERT INTO t4(a,b,c,d,f,g,h,e) VALUES(?,?,?,?,?,?,?,?)
} -1 TAIL]
sqlite3_bind_int $VM 1 1
sqlite3_bind_int $VM 2 2
sqlite3_bind_int $VM 3 3
sqlite3_bind_int $VM 4 4
sqlite3_bind_int $VM 5 5
sqlite3_bind_int $VM 6 6
sqlite3_bind_int $VM 7 7
sqlite3_bind_int $VM 8 8
sqlite3_step $VM
sqlite3_finalize $VM
db eval {SELECT * FROM t4}
} {1 2 3 4 8 5 6 7}
do_test bind-15.2 {
db eval {DELETE FROM t4}
set VM [sqlite3_prepare db {
INSERT INTO t4(a,b,c,d,e,f,g,h) VALUES(?,?,?,?,?,?,?,?)
} -1 TAIL]
sqlite3_bind_int $VM 1 1
sqlite3_bind_int $VM 2 2
sqlite3_bind_int $VM 3 3
sqlite3_bind_int $VM 4 4
sqlite3_bind_int $VM 5 5
sqlite3_bind_int $VM 6 6
sqlite3_bind_int $VM 7 7
sqlite3_bind_int $VM 8 8
sqlite3_step $VM
sqlite3_finalize $VM
db eval {SELECT * FROM t4}
} {1 2 3 4 5 6 7 8}
do_test bind-15.3 {
db eval {DELETE FROM t4}
set VM [sqlite3_prepare db {
INSERT INTO t4(h,g,f,e,d,c,b,a) VALUES(?,?,?,?,?,?,?,?)
} -1 TAIL]
sqlite3_bind_int $VM 1 1
sqlite3_bind_int $VM 2 2
sqlite3_bind_int $VM 3 3
sqlite3_bind_int $VM 4 4
sqlite3_bind_int $VM 5 5
sqlite3_bind_int $VM 6 6
sqlite3_bind_int $VM 7 7
sqlite3_bind_int $VM 8 8
sqlite3_step $VM
sqlite3_finalize $VM
db eval {SELECT * FROM t4}
} {8 7 6 5 4 3 2 1}
do_test bind-15.4 {
db eval {DELETE FROM t4}
set VM [sqlite3_prepare db {
INSERT INTO t4(a,b,c,d,e,f,g,h) VALUES(?,?,?,?4,?,?6,?,?)
} -1 TAIL]
sqlite3_bind_int $VM 1 1
sqlite3_bind_int $VM 2 2
sqlite3_bind_int $VM 3 3
sqlite3_bind_int $VM 4 4
sqlite3_bind_int $VM 5 5
sqlite3_bind_int $VM 6 6
sqlite3_bind_int $VM 7 7
sqlite3_bind_int $VM 8 8
sqlite3_step $VM
sqlite3_finalize $VM
db eval {SELECT * FROM t4}
} {1 2 3 4 5 6 7 8}
finish_test

View File

@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The
# focus of this script testing the sqlite_transfer_bindings() API.
#
# $Id: bindxfer.test,v 1.6 2008/10/12 00:27:54 shane Exp $
# $Id: bindxfer.test,v 1.7 2009/04/09 14:02:44 drh Exp $
#
set testdir [file dirname $argv0]
@ -68,11 +68,8 @@ ifcapable deprecated {
do_test bindxfer-1.8 {
set VALUES
} {one two {}}
do_test bindxfer-1.9-misuse {
catch {sqlite3_finalize $VM1}
catch {sqlite3_finalize $VM2}
sqlite3_transfer_bindings $VM1 $VM2
} 21 ;# SQLITE_MISUSE
catch {sqlite3_finalize $VM1}
catch {sqlite3_finalize $VM2}
do_test bindxfer-1.10 {
set VM1 [sqlite3_prepare $DB {SELECT ?, ?, ?} -1 TAIL]
set VM2 [sqlite3_prepare $DB {SELECT ?, ?, ?, ?} -1 TAIL]

View File

@ -11,7 +11,7 @@
#
# Unit testing of the Bitvec object.
#
# $Id: bitvec.test,v 1.3 2008/11/19 18:30:35 shane Exp $
# $Id: bitvec.test,v 1.4 2009/04/01 23:49:04 drh Exp $
#
set testdir [file dirname $argv0]
@ -140,6 +140,14 @@ do_test bitvec-2.5 {
do_test bitvec-2.6 {
sqlite3BitvecBuiltinTest 50000 {3 60 2 50000 1 1 0}
} 0
do_test bitvec-2.7 {
sqlite3BitvecBuiltinTest 5000 {
1 25 121 125
1 50 121 125
2 25 121 125
0
}
} 0
# This procedure runs sqlite3BitvecBuiltinTest with argments "n" and
# "program". But it also causes a malloc error to occur after the

View File

@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The
# focus of this file is testing CHECK constraints
#
# $Id: check.test,v 1.11 2007/07/23 19:39:47 drh Exp $
# $Id: check.test,v 1.12 2009/03/24 15:08:10 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@ -115,11 +115,12 @@ do_test check-1.17 {
} {4 11.0}
do_test check-2.1 {
breakpoint
execsql {
CREATE TABLE t2(
x INTEGER CHECK( typeof(coalesce(x,0))=="integer" ),
y REAL CHECK( typeof(coalesce(y,0.1))=="real" ),
z TEXT CHECK( typeof(coalesce(z,''))=="text" )
y REAL CHECK( typeof(coalesce(y,0.1))=='real' ),
z TEXT CHECK( typeof(coalesce(z,''))=='text' )
);
}
} {}
@ -129,6 +130,8 @@ do_test check-2.2 {
SELECT * FROM t2;
}
} {1 2.2 three}
db close
sqlite3 db test.db
do_test check-2.3 {
execsql {
INSERT INTO t2 VALUES(NULL, NULL, NULL);

View File

@ -13,7 +13,7 @@
# This file implements tests to make sure SQLite does not crash or
# segfault if it sees a corrupt database file.
#
# $Id: corrupt2.test,v 1.18 2008/09/29 11:49:48 danielk1977 Exp $
# $Id: corrupt2.test,v 1.20 2009/04/06 17:50:03 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@ -233,6 +233,8 @@ db2 close
proc corruption_test {args} {
set A(-corrupt) {}
set A(-sqlprep) {}
set A(-tclprep) {}
array set A $args
catch {db close}
@ -240,6 +242,7 @@ proc corruption_test {args} {
file delete -force corrupt.db-journal
sqlite3 db corrupt.db
eval $A(-tclprep)
db eval $A(-sqlprep)
db close
@ -455,4 +458,78 @@ corruption_test -sqlprep {
} {SQLITE_CORRUPT}
}
corruption_test -sqlprep {
PRAGMA auto_vacuum = incremental;
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
CREATE TABLE t2(a INTEGER PRIMARY KEY, b);
INSERT INTO t1 VALUES(1, randstr(100,100));
INSERT INTO t1 SELECT NULL, randstr(100,100) FROM t1;
INSERT INTO t1 SELECT NULL, randstr(100,100) FROM t1;
INSERT INTO t1 SELECT NULL, randstr(100,100) FROM t1;
INSERT INTO t1 SELECT NULL, randstr(100,100) FROM t1;
INSERT INTO t1 SELECT NULL, randstr(100,100) FROM t1;
INSERT INTO t2 SELECT * FROM t1;
DELETE FROM t1;
} -corrupt {
set offset [expr [file size corrupt.db] - 1024]
hexio_write corrupt.db $offset FF
hexio_write corrupt.db 24 12345678
} -test {
do_test corrupt2-11.1 {
catchsql { PRAGMA incremental_vacuum }
} {1 {database disk image is malformed}}
}
corruption_test -sqlprep {
PRAGMA auto_vacuum = incremental;
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
CREATE TABLE t2(a INTEGER PRIMARY KEY, b);
INSERT INTO t1 VALUES(1, randstr(100,100));
INSERT INTO t1 SELECT NULL, randstr(100,100) FROM t1;
INSERT INTO t1 SELECT NULL, randstr(100,100) FROM t1;
INSERT INTO t1 SELECT NULL, randstr(100,100) FROM t1;
INSERT INTO t1 SELECT NULL, randstr(100,100) FROM t1;
INSERT INTO t1 SELECT NULL, randstr(100,100) FROM t1;
INSERT INTO t2 SELECT * FROM t1;
DELETE FROM t1;
} -corrupt {
set pgno [expr [file size corrupt.db] / 1024]
hexio_write corrupt.db [expr 1024+5*($pgno-3)] 03
hexio_write corrupt.db 24 12345678
} -test {
do_test corrupt2-12.1 {
catchsql { PRAGMA incremental_vacuum }
} {1 {database disk image is malformed}}
}
ifcapable autovacuum {
# It is not possible for the last page in a database file to be the
# pending-byte page (AKA the locking page). This test verifies that if
# an attempt is made to commit a transaction to such an auto-vacuum
# database SQLITE_CORRUPT is returned.
#
corruption_test -tclprep {
db eval {
PRAGMA auto_vacuum = full;
PRAGMA page_size = 1024;
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
INSERT INTO t1 VALUES(NULL, randstr(50,50));
}
for {set ii 0} {$ii < 10} {incr ii} {
db eval { INSERT INTO t1 SELECT NULL, randstr(50,50) FROM t1 }
}
} -corrupt {
do_test corrupt2-13.1 {
file size corrupt.db
} $::sqlite_pending_byte
hexio_write corrupt.db [expr $::sqlite_pending_byte+1023] 00
} -test {
do_test corrupt2-13.2 {
file size corrupt.db
} [expr $::sqlite_pending_byte + 1024]
do_test corrupt2-13.3 {
catchsql { DELETE FROM t1 WHERE rowid < 30; }
} {1 {database disk image is malformed}}
}
}
finish_test

Some files were not shown because too many files have changed in this diff Show More