update baseline to sqlite version 3.6.1

This commit is contained in:
Stephen Lombardo 2008-08-19 01:05:45 -04:00
parent 617ed01e77
commit 2893a5d0b2
139 changed files with 7730 additions and 2211 deletions

View File

@ -0,0 +1,138 @@
#!/usr/make
#
# Makefile for SQLITE
#
# This is a template makefile for SQLite. Most people prefer to
# use the autoconf generated "configure" script to generate the
# makefile automatically. But that does not work for everybody
# and in every situation. If you are having problems with the
# "configure" script, you might want to try this makefile as an
# alternative. Create a copy of this file, edit the parameters
# below and type "make".
#
#### The directory where to find the mingw32ce tools
MINGW32CE = /opt/mingw32ce/bin
#### The target prefix of the mingw32ce tools
TARGET = arm-wince-mingw32ce
#### The toplevel directory of the source tree. This is the directory
# that contains this "Makefile.in" and the "configure.in" script.
#
TOP = ../sqlite
#### C Compiler and options for use in building executables that
# will run on the platform that is doing the build.
#
BCC = gcc -g -O2
#BCC = /opt/ancic/bin/c89 -0
#### If the target operating system supports the "usleep()" system
# call, then define the HAVE_USLEEP macro for all C modules.
#
USLEEP =
#USLEEP = -DHAVE_USLEEP=1
#### If you want the SQLite library to be safe for use within a
# multi-threaded program, then define the following macro
# appropriately:
#
THREADSAFE = -DTHREADSAFE=1
#THREADSAFE = -DTHREADSAFE=0
#### Specify any extra linker options needed to make the library
# thread safe
#
#THREADLIB = -lpthread
THREADLIB =
#### Specify any extra libraries needed to access required functions.
#
#TLIBS = -lrt # fdatasync on Solaris 8
TLIBS =
#### Leave SQLITE_DEBUG undefined for maximum speed. Use SQLITE_DEBUG=1
# to check for memory leaks. Use SQLITE_DEBUG=2 to print a log of all
# malloc()s and free()s in order to track down memory leaks.
#
# SQLite uses some expensive assert() statements in the inner loop.
# You can make the library go almost twice as fast if you compile
# with -DNDEBUG=1
#
#OPTS = -DSQLITE_DEBUG=2
#OPTS = -DSQLITE_DEBUG=1
#OPTS =
OPTS = -DNDEBUG=1 -DSQLITE_OS_WIN=1 -D_WIN32_WCE=1
#OPTS += -DHAVE_FDATASYNC=1
#### The suffix to add to executable files. ".exe" for windows.
# Nothing for unix.
#
EXE = .exe
#EXE =
#### C Compile and options for use in building executables that
# will run on the target platform. This is usually the same
# as BCC, unless you are cross-compiling.
#
#TCC = gcc -O6
#TCC = gcc -g -O0 -Wall
#TCC = gcc -g -O0 -Wall -fprofile-arcs -ftest-coverage
#TCC = /opt/mingw/bin/i386-mingw32-gcc -O6
TCC = $(MINGW32CE)/$(TARGET)-gcc -O2
#TCC = /opt/ansic/bin/c89 -O +z -Wl,-a,archive
#### Tools used to build a static library.
#
#AR = ar cr
#AR = /opt/mingw/bin/i386-mingw32-ar cr
AR = $(MINGW32CE)/$(TARGET)-ar cr
#RANLIB = ranlib
#RANLIB = /opt/mingw/bin/i386-mingw32-ranlib
RANLIB = $(MINGW32CE)/$(TARGET)-ranlib
#MKSHLIB = gcc -shared
#SO = so
#SHPREFIX = lib
MKSHLIB = $(MINGW32CE)/$(TARGET)-gcc -shared
SO = dll
SHPREFIX =
#### Extra compiler options needed for programs that use the TCL library.
#
#TCL_FLAGS =
#TCL_FLAGS = -DSTATIC_BUILD=1
TCL_FLAGS = -I/home/drh/tcltk/8.4linux
#TCL_FLAGS = -I/home/drh/tcltk/8.4win -DSTATIC_BUILD=1
#TCL_FLAGS = -I/home/drh/tcltk/8.3hpux
#### Linker options needed to link against the TCL library.
#
#LIBTCL = -ltcl -lm -ldl
LIBTCL = /home/drh/tcltk/8.4linux/libtcl8.4g.a -lm -ldl
#LIBTCL = /home/drh/tcltk/8.4win/libtcl84s.a -lmsvcrt
#LIBTCL = /home/drh/tcltk/8.3hpux/libtcl8.3.a -ldld -lm -lc
#### Additional objects for SQLite library when TCL support is enabled.
TCLOBJ =
#TCLOBJ = tclsqlite.o
#### Compiler options needed for programs that use the readline() library.
#
READLINE_FLAGS =
#READLINE_FLAGS = -DHAVE_READLINE=1 -I/usr/include/readline
#### Linker options needed by programs using readline() must link against.
#
LIBREADLINE =
#LIBREADLINE = -static -lreadline -ltermcap
#### Which "awk" program provides nawk compatibilty
#
# NAWK = nawk
NAWK = awk
# You should not have to change anything below this line
###############################################################################
include $(TOP)/main.mk

View File

@ -75,8 +75,13 @@ TLIBS = @LIBS@
#
TEMP_STORE = -DSQLITE_TEMP_STORE=@TEMP_STORE@
# Enable/disable loadable extensions based on configuration
TCC += @LOADEXTENSION_FLAGS@
# Enable/disable loadable extensions, and other optional features
# based on configuration. (-DSQLITE_OMIT*). The same set of OMIT
# flags should be passed to the LEMON parser generator and the
# mkkeywordhash tool as well.
OPT_FEATURE_FLAGS = @OPT_FEATURE_FLAGS@
TCC += $(OPT_FEATURE_FLAGS)
# Version numbers and release number for the SQLite being compiled.
#
@ -130,6 +135,7 @@ LTLINK_EXTRAS += $(GCOV_LDFLAGS$(USE_GCOV))
prefix = @prefix@
exec_prefix = @exec_prefix@
libdir = @libdir@
pkgconfigdir = $(libdir)/pkgconfig
bindir = @bindir@
includedir = @includedir@
INSTALL = @INSTALL@
@ -153,8 +159,8 @@ OBJS0 = alter.lo analyze.lo attach.lo auth.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 loadext.lo \
main.lo malloc.lo mem1.lo mem2.lo mem3.lo mem4.lo mem5.lo mutex.lo \
mutex_os2.lo mutex_unix.lo mutex_w32.lo \
main.lo malloc.lo mem1.lo mem2.lo mem3.lo mem4.lo mem5.lo mem6.lo \
mutex.lo mutex_os2.lo mutex_unix.lo mutex_w32.lo \
opcodes.lo os.lo os_unix.lo os_win.lo os_os2.lo \
pager.lo parse.lo pragma.lo prepare.lo printf.lo random.lo \
select.lo status.lo table.lo tokenize.lo trigger.lo update.lo \
@ -207,6 +213,7 @@ SRC = \
$(TOP)/src/mem3.c \
$(TOP)/src/mem4.c \
$(TOP)/src/mem5.c \
$(TOP)/src/mem6.c \
$(TOP)/src/mutex.c \
$(TOP)/src/mutex.h \
$(TOP)/src/mutex_os2.c \
@ -427,7 +434,7 @@ libsqlite3.la: $(LIBOBJ)
libtclsqlite3.la: tclsqlite.lo libsqlite3.la
$(LTLINK) -o $@ tclsqlite.lo \
$(LIBOBJ) @TCL_STUB_LIB_SPEC@ $(TLIBS) \
libsqlite3.la @TCL_STUB_LIB_SPEC@ $(TLIBS) \
-rpath "$(libdir)/sqlite" \
-version-info "8:6:8"
@ -550,6 +557,9 @@ mem4.lo: $(TOP)/src/mem4.c $(HDR)
mem5.lo: $(TOP)/src/mem5.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/mem5.c
mem6.lo: $(TOP)/src/mem6.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/mem6.c
mutex.lo: $(TOP)/src/mutex.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/mutex.c
@ -593,7 +603,7 @@ parse.h: parse.c
parse.c: $(TOP)/src/parse.y lemon$(BEXE) $(TOP)/addopcodes.awk
cp $(TOP)/src/parse.y .
./lemon$(BEXE) $(OPTS) parse.y
./lemon$(BEXE) $(OPTS) $(OPT_FEATURE_FLAGS) parse.y
mv parse.h parse.h.temp
$(NAWK) -f $(TOP)/addopcodes.awk parse.h.temp >parse.h
@ -623,13 +633,13 @@ table.lo: $(TOP)/src/table.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/table.c
tclsqlite.lo: $(TOP)/src/tclsqlite.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/tclsqlite.c
$(LTCOMPILE) -DUSE_TCL_STUBS=1 -c $(TOP)/src/tclsqlite.c
tokenize.lo: $(TOP)/src/tokenize.c keywordhash.h $(HDR)
$(LTCOMPILE) -c $(TOP)/src/tokenize.c
keywordhash.h: $(TOP)/tool/mkkeywordhash.c
$(BCC) -o mkkeywordhash$(BEXE) $(OPTS) $(TOP)/tool/mkkeywordhash.c
$(BCC) -o mkkeywordhash$(BEXE) $(OPTS) $(OPT_FEATURE_FLAGS) $(TOP)/tool/mkkeywordhash.c
./mkkeywordhash$(BEXE) >keywordhash.h
trigger.lo: $(TOP)/src/trigger.c $(HDR)
@ -715,8 +725,8 @@ install: sqlite3$(BEXE) libsqlite3.la sqlite3.h ${HAVE_TCL:1=tcl_install}
$(INSTALL) -d $(DESTDIR)$(includedir)
$(INSTALL) -m 0644 sqlite3.h $(DESTDIR)$(includedir)
$(INSTALL) -m 0644 $(TOP)/src/sqlite3ext.h $(DESTDIR)$(includedir)
$(INSTALL) -d $(DESTDIR)$(libdir)/pkgconfig;
$(INSTALL) -m 0644 sqlite3.pc $(DESTDIR)$(libdir)/pkgconfig;
$(INSTALL) -d $(DESTDIR)$(pkgconfigdir)
$(INSTALL) -m 0644 sqlite3.pc $(DESTDIR)$(pkgconfigdir)
tcl_install: libtclsqlite3.la
$(TCLSH_CMD) $(TOP)/tclinstaller.tcl $(VERSION)

View File

@ -1 +1 @@
3.6.0
3.6.1

View File

@ -11,7 +11,7 @@
*************************************************************************
** Configuration header template to be filled in by 'configure' script
**
** @(#) $Id: config.h.in,v 1.2 2008/05/06 02:28:06 mlcreech Exp $
** @(#) $Id: config.h.in,v 1.3 2008/07/22 05:05:02 shane Exp $
*/
#ifndef _CONFIG_H_
#define _CONFIG_H_
@ -33,9 +33,6 @@
/* Define as 1 if you have the int64_t type */
#undef HAVE_INT64_T
/* Define as 1 if you have the intptr_t type */
#undef HAVE_INTPTR_T
/* Define as 1 if you have the uint8_t type */
#undef HAVE_UINT8_T
@ -48,9 +45,6 @@
/* Define as 1 if you have the uint64_t type */
#undef HAVE_UINT64_T
/* Define as 1 if you have the uintptr_t type */
#undef HAVE_UINTPTR_T
/*****************************
** Header Files
@ -85,6 +79,9 @@
/* Define as 1 if you have the localtime_r() function */
#undef HAVE_LOCALTIME_R
/* Define as 1 if you have the localtime_s() function */
#undef HAVE_LOCALTIME_S
/*****************************
** Large file support

81
configure vendored
View File

@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.59 for sqlite 3.6.0.
# Generated by GNU Autoconf 2.59 for sqlite 3.6.1.
#
# Copyright (C) 2003 Free Software Foundation, Inc.
# This configure script is free software; the Free Software Foundation
@ -416,8 +416,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
# Identity of this package.
PACKAGE_NAME='sqlite'
PACKAGE_TARNAME='sqlite'
PACKAGE_VERSION='3.6.0'
PACKAGE_STRING='sqlite 3.6.0'
PACKAGE_VERSION='3.6.1'
PACKAGE_STRING='sqlite 3.6.1'
PACKAGE_BUGREPORT=''
# Factoring default headers for most tests.
@ -457,7 +457,7 @@ ac_includes_default="\
# include <unistd.h>
#endif"
ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS LIBTOOL build build_cpu build_vendor build_os host host_cpu host_vendor host_os CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT SED EGREP FGREP GREP LD DUMPBIN ac_ct_DUMPBIN NM LN_S AR ac_ct_AR STRIP ac_ct_STRIP RANLIB ac_ct_RANLIB lt_ECHO DSYMUTIL ac_ct_DSYMUTIL NMEDIT ac_ct_NMEDIT LIPO ac_ct_LIPO OTOOL ac_ct_OTOOL OTOOL64 ac_ct_OTOOL64 CPP INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA AWK TCLSH_CMD program_prefix VERSION RELEASE VERSION_NUMBER BUILD_CC SQLITE_THREADSAFE XTHREADCONNECT THREADSOVERRIDELOCKS ALLOWRELEASE TEMP_STORE BUILD_EXEEXT SQLITE_OS_UNIX SQLITE_OS_WIN SQLITE_OS_OS2 TARGET_EXEEXT TCL_VERSION TCL_BIN_DIR TCL_SRC_DIR TCL_LIBS TCL_INCLUDE_SPEC TCL_LIB_FILE TCL_LIB_FLAG TCL_LIB_SPEC TCL_STUB_LIB_FILE TCL_STUB_LIB_FLAG TCL_STUB_LIB_SPEC HAVE_TCL TARGET_READLINE_LIBS TARGET_READLINE_INC TARGET_HAVE_READLINE TARGET_DEBUG USE_AMALGAMATION LOADEXTENSION_FLAGS USE_GCOV BUILD_CFLAGS LIBOBJS LTLIBOBJS'
ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS LIBTOOL build build_cpu build_vendor build_os host host_cpu host_vendor host_os CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT SED EGREP FGREP GREP LD DUMPBIN ac_ct_DUMPBIN NM LN_S AR ac_ct_AR STRIP ac_ct_STRIP RANLIB ac_ct_RANLIB lt_ECHO DSYMUTIL ac_ct_DSYMUTIL NMEDIT ac_ct_NMEDIT LIPO ac_ct_LIPO OTOOL ac_ct_OTOOL OTOOL64 ac_ct_OTOOL64 CPP INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA AWK TCLSH_CMD program_prefix VERSION RELEASE VERSION_NUMBER BUILD_CC SQLITE_THREADSAFE XTHREADCONNECT THREADSOVERRIDELOCKS ALLOWRELEASE TEMP_STORE BUILD_EXEEXT SQLITE_OS_UNIX SQLITE_OS_WIN SQLITE_OS_OS2 TARGET_EXEEXT TCL_VERSION TCL_BIN_DIR TCL_SRC_DIR TCL_LIBS TCL_INCLUDE_SPEC TCL_LIB_FILE TCL_LIB_FLAG TCL_LIB_SPEC TCL_STUB_LIB_FILE TCL_STUB_LIB_FLAG TCL_STUB_LIB_SPEC HAVE_TCL TARGET_READLINE_LIBS TARGET_READLINE_INC TARGET_HAVE_READLINE TARGET_DEBUG USE_AMALGAMATION OPT_FEATURE_FLAGS USE_GCOV BUILD_CFLAGS LIBOBJS LTLIBOBJS'
ac_subst_files=''
# Initialize some variables set by options.
@ -926,7 +926,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures sqlite 3.6.0 to adapt to many kinds of systems.
\`configure' configures sqlite 3.6.1 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@ -987,7 +987,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of sqlite 3.6.0:";;
short | recursive ) echo "Configuration of sqlite 3.6.1:";;
esac
cat <<\_ACEOF
@ -1137,7 +1137,7 @@ fi
test -n "$ac_init_help" && exit 0
if $ac_init_version; then
cat <<\_ACEOF
sqlite configure 3.6.0
sqlite configure 3.6.1
generated by GNU Autoconf 2.59
Copyright (C) 2003 Free Software Foundation, Inc.
@ -1151,7 +1151,7 @@ cat >&5 <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by sqlite $as_me 3.6.0, which was
It was created by sqlite $as_me 3.6.1, which was
generated by GNU Autoconf 2.59. Invocation command line was
$ $0 $@
@ -1489,7 +1489,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
# The following RCS revision string applies to configure.in
# $Revision: 1.61 $
# $Revision: 1.64 $
#########
# Programs needed
@ -10680,7 +10680,8 @@ done
for ac_func in usleep fdatasync localtime_r gmtime_r
for ac_func in usleep fdatasync localtime_r gmtime_r localtime_s
do
as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
echo "$as_me:$LINENO: checking for $ac_func" >&5
@ -11273,14 +11274,12 @@ if test "$TARGET_EXEEXT" = ".exe"; then
SQLITE_OS_UNIX=0
SQLITE_OS_WIN=1
SQLITE_OS_OS2=0
tclsubdir=win
CFLAGS="$CFLAGS -DSQLITE_OS_WIN=1"
fi
else
SQLITE_OS_UNIX=1
SQLITE_OS_WIN=0
SQLITE_OS_OS2=0
tclsubdir=unix
CFLAGS="$CFLAGS -DSQLITE_OS_UNIX=1"
fi
@ -12066,14 +12065,60 @@ else
use_loadextension=no
fi;
if test "${use_loadextension}" = "yes" ; then
LOADEXTENSION_FLAGS=""
OPT_FEATURE_FLAGS=""
else
LOADEXTENSION_FLAGS="-DSQLITE_OMIT_LOAD_EXTENSION=1"
OPT_FEATURE_FLAGS="-DSQLITE_OMIT_LOAD_EXTENSION=1"
fi
#########
# attempt to duplicate any OMITS into the $(OPT_FEATURE_FLAGS) parameter
for option in $CFLAGS $CPPFLAGS
do
case $option in
-DSQLITE_OMIT*) OPT_FEATURE_FLAGS="$OPT_FEATURE_FLAGS $option";;
esac
done
# attempt to remove any OMITS from the $(CFLAGS) parameter
ac_temp_CFLAGS=""
for option in $CFLAGS
do
case $option in
-DSQLITE_OMIT*) ;;
*) ac_temp_CFLAGS="$ac_temp_CFLAGS $option";;
esac
done
CFLAGS=$ac_temp_CFLAGS
# attempt to remove any OMITS from the $(CPPFLAGS) parameter
ac_temp_CPPFLAGS=""
for option in $CPPFLAGS
do
case $option in
-DSQLITE_OMIT*) ;;
*) ac_temp_CPPFLAGS="$ac_temp_CPPFLAGS $option";;
esac
done
CPPFLAGS=$ac_temp_CPPFLAGS
# attempt to remove any OMITS from the $(BUILD_CFLAGS) parameter
ac_temp_BUILD_CFLAGS=""
for option in $BUILD_CFLAGS
do
case $option in
-DSQLITE_OMIT*) ;;
*) ac_temp_BUILD_CFLAGS="$ac_temp_BUILD_CFLAGS $option";;
esac
done
BUILD_CFLAGS=$ac_temp_BUILD_CFLAGS
#########
# See whether we should allow loadable extensions
# See whether we should use GCOV
# Check whether --enable-gcov or --disable-gcov was given.
if test "${enable_gcov+set}" = set; then
enableval="$enable_gcov"
@ -12461,7 +12506,7 @@ _ASBOX
} >&5
cat >&5 <<_CSEOF
This file was extended by sqlite $as_me 3.6.0, which was
This file was extended by sqlite $as_me 3.6.1, which was
generated by GNU Autoconf 2.59. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@ -12524,7 +12569,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF
ac_cs_version="\\
sqlite config.status 3.6.0
sqlite config.status 3.6.1
configured by $0, generated by GNU Autoconf 2.59,
with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
@ -13055,7 +13100,7 @@ s,@TARGET_READLINE_INC@,$TARGET_READLINE_INC,;t t
s,@TARGET_HAVE_READLINE@,$TARGET_HAVE_READLINE,;t t
s,@TARGET_DEBUG@,$TARGET_DEBUG,;t t
s,@USE_AMALGAMATION@,$USE_AMALGAMATION,;t t
s,@LOADEXTENSION_FLAGS@,$LOADEXTENSION_FLAGS,;t t
s,@OPT_FEATURE_FLAGS@,$OPT_FEATURE_FLAGS,;t t
s,@USE_GCOV@,$USE_GCOV,;t t
s,@BUILD_CFLAGS@,$BUILD_CFLAGS,;t t
s,@LIBOBJS@,$LIBOBJS,;t t

View File

@ -92,7 +92,7 @@ AC_INIT(sqlite, m4_esyscmd([cat VERSION | tr -d '\n']))
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.46 $
# $Revision: 1.48 $
#########
# Programs needed
@ -118,7 +118,7 @@ AC_CHECK_HEADERS([sys/types.h stdlib.h stdint.h inttypes.h])
#########
# Figure out whether or not we have these functions
#
AC_CHECK_FUNCS([usleep fdatasync localtime_r gmtime_r])
AC_CHECK_FUNCS([usleep fdatasync localtime_r gmtime_r localtime_s])
#########
# By default, we use the amalgamation (this may be changed below...)
@ -352,14 +352,12 @@ if test "$TARGET_EXEEXT" = ".exe"; then
SQLITE_OS_UNIX=0
SQLITE_OS_WIN=1
SQLITE_OS_OS2=0
tclsubdir=win
CFLAGS="$CFLAGS -DSQLITE_OS_WIN=1"
fi
else
SQLITE_OS_UNIX=1
SQLITE_OS_WIN=0
SQLITE_OS_OS2=0
tclsubdir=unix
CFLAGS="$CFLAGS -DSQLITE_OS_UNIX=1"
fi
@ -611,14 +609,60 @@ AC_ARG_ENABLE(load-extension, AC_HELP_STRING([--enable-load-extension],
[Enable loading of external extensions]),
[use_loadextension=$enableval],[use_loadextension=no])
if test "${use_loadextension}" = "yes" ; then
LOADEXTENSION_FLAGS=""
OPT_FEATURE_FLAGS=""
else
LOADEXTENSION_FLAGS="-DSQLITE_OMIT_LOAD_EXTENSION=1"
OPT_FEATURE_FLAGS="-DSQLITE_OMIT_LOAD_EXTENSION=1"
fi
AC_SUBST(LOADEXTENSION_FLAGS)
#########
# See whether we should allow loadable extensions
# attempt to duplicate any OMITS into the $(OPT_FEATURE_FLAGS) parameter
for option in $CFLAGS $CPPFLAGS
do
case $option in
-DSQLITE_OMIT*) OPT_FEATURE_FLAGS="$OPT_FEATURE_FLAGS $option";;
esac
done
AC_SUBST(OPT_FEATURE_FLAGS)
# attempt to remove any OMITS from the $(CFLAGS) parameter
ac_temp_CFLAGS=""
for option in $CFLAGS
do
case $option in
-DSQLITE_OMIT*) ;;
*) ac_temp_CFLAGS="$ac_temp_CFLAGS $option";;
esac
done
CFLAGS=$ac_temp_CFLAGS
# attempt to remove any OMITS from the $(CPPFLAGS) parameter
ac_temp_CPPFLAGS=""
for option in $CPPFLAGS
do
case $option in
-DSQLITE_OMIT*) ;;
*) ac_temp_CPPFLAGS="$ac_temp_CPPFLAGS $option";;
esac
done
CPPFLAGS=$ac_temp_CPPFLAGS
# attempt to remove any OMITS from the $(BUILD_CFLAGS) parameter
ac_temp_BUILD_CFLAGS=""
for option in $BUILD_CFLAGS
do
case $option in
-DSQLITE_OMIT*) ;;
*) ac_temp_BUILD_CFLAGS="$ac_temp_BUILD_CFLAGS $option";;
esac
done
BUILD_CFLAGS=$ac_temp_BUILD_CFLAGS
#########
# See whether we should use GCOV
AC_ARG_ENABLE(gcov, AC_HELP_STRING([--enable-gcov],
[Enable coverage testing using gcov]),
[use_gcov=$enableval],[use_gcov=no])

File diff suppressed because it is too large Load Diff

View File

@ -29,15 +29,22 @@
#include <stdlib.h>
#include <string.h>
#include "sqlite3.h"
#include "fts2_hash.h"
static void *malloc_and_zero(int n){
void *p = malloc(n);
/*
** Malloc and Free functions
*/
static void *fts2HashMalloc(int n){
void *p = sqlite3_malloc(n);
if( p ){
memset(p, 0, n);
}
return p;
}
static void fts2HashFree(void *p){
sqlite3_free(p);
}
/* Turn bulk memory into a hash table object by initializing the
** fields of the Hash structure.
@ -58,8 +65,6 @@ void sqlite3Fts2HashInit(fts2Hash *pNew, int keyClass, int copyKey){
pNew->count = 0;
pNew->htsize = 0;
pNew->ht = 0;
pNew->xMalloc = malloc_and_zero;
pNew->xFree = free;
}
/* Remove all entries from a hash table. Reclaim all memory.
@ -72,15 +77,15 @@ void sqlite3Fts2HashClear(fts2Hash *pH){
assert( pH!=0 );
elem = pH->first;
pH->first = 0;
if( pH->ht ) pH->xFree(pH->ht);
fts2HashFree(pH->ht);
pH->ht = 0;
pH->htsize = 0;
while( elem ){
fts2HashElem *next_elem = elem->next;
if( pH->copyKey && elem->pKey ){
pH->xFree(elem->pKey);
fts2HashFree(elem->pKey);
}
pH->xFree(elem);
fts2HashFree(elem);
elem = next_elem;
}
pH->count = 0;
@ -192,9 +197,9 @@ static void rehash(fts2Hash *pH, int new_size){
int (*xHash)(const void*,int); /* The hash function */
assert( (new_size & (new_size-1))==0 );
new_ht = (struct _fts2ht *)pH->xMalloc( new_size*sizeof(struct _fts2ht) );
new_ht = (struct _fts2ht *)fts2HashMalloc( new_size*sizeof(struct _fts2ht) );
if( new_ht==0 ) return;
if( pH->ht ) pH->xFree(pH->ht);
fts2HashFree(pH->ht);
pH->ht = new_ht;
pH->htsize = new_size;
xHash = hashFunction(pH->keyClass);
@ -260,9 +265,9 @@ static void removeElementGivenHash(
pEntry->chain = 0;
}
if( pH->copyKey && elem->pKey ){
pH->xFree(elem->pKey);
fts2HashFree(elem->pKey);
}
pH->xFree( elem );
fts2HashFree( elem );
pH->count--;
if( pH->count<=0 ){
assert( pH->first==0 );
@ -333,12 +338,12 @@ void *sqlite3Fts2HashInsert(
return old_data;
}
if( data==0 ) return 0;
new_elem = (fts2HashElem*)pH->xMalloc( sizeof(fts2HashElem) );
new_elem = (fts2HashElem*)fts2HashMalloc( sizeof(fts2HashElem) );
if( new_elem==0 ) return data;
if( pH->copyKey && pKey!=0 ){
new_elem->pKey = pH->xMalloc( nKey );
new_elem->pKey = fts2HashMalloc( nKey );
if( new_elem->pKey==0 ){
pH->xFree(new_elem);
fts2HashFree(new_elem);
return data;
}
memcpy((void*)new_elem->pKey, pKey, nKey);
@ -351,7 +356,7 @@ void *sqlite3Fts2HashInsert(
rehash(pH,8);
if( pH->htsize==0 ){
pH->count = 0;
pH->xFree(new_elem);
fts2HashFree(new_elem);
return data;
}
}

View File

@ -34,8 +34,6 @@ struct fts2Hash {
char copyKey; /* True if copy of key made on insert */
int count; /* Number of entries in this table */
fts2HashElem *first; /* The first element of the array */
void *(*xMalloc)(int); /* malloc() function to use */
void (*xFree)(void *); /* free() function to use */
int htsize; /* Number of buckets in the hash table */
struct _fts2ht { /* the hash table */
int count; /* Number of entries with this hash */

View File

@ -11,7 +11,7 @@
*************************************************************************
** This file implements a tokenizer for fts2 based on the ICU library.
**
** $Id: fts2_icu.c,v 1.1 2007/06/22 15:21:16 danielk1977 Exp $
** $Id: fts2_icu.c,v 1.2 2008/07/22 22:20:50 shess Exp $
*/
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS2)
@ -112,6 +112,7 @@ static int icuOpen(
*ppCursor = 0;
if( -1 == nInput ) nInput = strlen(nInput);
nChar = nInput+1;
pCsr = (IcuCursor *)sqlite3_malloc(
sizeof(IcuCursor) + /* IcuCursor */

View File

@ -66,9 +66,9 @@ static int porterCreate(
sqlite3_tokenizer **ppTokenizer
){
porter_tokenizer *t;
t = (porter_tokenizer *) calloc(sizeof(*t), 1);
t = (porter_tokenizer *) sqlite3_malloc(sizeof(*t));
if( t==NULL ) return SQLITE_NOMEM;
memset(t, 0, sizeof(*t));
*ppTokenizer = &t->base;
return SQLITE_OK;
}
@ -77,7 +77,7 @@ static int porterCreate(
** Destroy a tokenizer
*/
static int porterDestroy(sqlite3_tokenizer *pTokenizer){
free(pTokenizer);
sqlite3_free(pTokenizer);
return SQLITE_OK;
}
@ -94,7 +94,7 @@ static int porterOpen(
){
porter_tokenizer_cursor *c;
c = (porter_tokenizer_cursor *) malloc(sizeof(*c));
c = (porter_tokenizer_cursor *) sqlite3_malloc(sizeof(*c));
if( c==NULL ) return SQLITE_NOMEM;
c->zInput = zInput;
@ -120,8 +120,8 @@ static int porterOpen(
*/
static int porterClose(sqlite3_tokenizer_cursor *pCursor){
porter_tokenizer_cursor *c = (porter_tokenizer_cursor *) pCursor;
free(c->zToken);
free(c);
sqlite3_free(c->zToken);
sqlite3_free(c);
return SQLITE_OK;
}
/*
@ -603,7 +603,7 @@ static int porterNext(
int n = c->iOffset-iStartOffset;
if( n>c->nAllocated ){
c->nAllocated = n+20;
c->zToken = realloc(c->zToken, c->nAllocated);
c->zToken = sqlite3_realloc(c->zToken, c->nAllocated);
if( c->zToken==NULL ) return SQLITE_NOMEM;
}
porter_stemmer(&z[iStartOffset], n, c->zToken, pnBytes);

View File

@ -65,8 +65,9 @@ static int simpleCreate(
){
simple_tokenizer *t;
t = (simple_tokenizer *) calloc(sizeof(*t), 1);
t = (simple_tokenizer *) sqlite3_malloc(sizeof(*t));
if( t==NULL ) return SQLITE_NOMEM;
memset(t, 0, sizeof(*t));
/* TODO(shess) Delimiters need to remain the same from run to run,
** else we need to reindex. One solution would be a meta-table to
@ -79,7 +80,7 @@ static int simpleCreate(
unsigned char ch = argv[1][i];
/* We explicitly don't support UTF-8 delimiters for now. */
if( ch>=0x80 ){
free(t);
sqlite3_free(t);
return SQLITE_ERROR;
}
t->delim[ch] = 1;
@ -100,7 +101,7 @@ static int simpleCreate(
** Destroy a tokenizer
*/
static int simpleDestroy(sqlite3_tokenizer *pTokenizer){
free(pTokenizer);
sqlite3_free(pTokenizer);
return SQLITE_OK;
}
@ -117,7 +118,7 @@ static int simpleOpen(
){
simple_tokenizer_cursor *c;
c = (simple_tokenizer_cursor *) malloc(sizeof(*c));
c = (simple_tokenizer_cursor *) sqlite3_malloc(sizeof(*c));
if( c==NULL ) return SQLITE_NOMEM;
c->pInput = pInput;
@ -143,8 +144,8 @@ static int simpleOpen(
*/
static int simpleClose(sqlite3_tokenizer_cursor *pCursor){
simple_tokenizer_cursor *c = (simple_tokenizer_cursor *) pCursor;
free(c->pToken);
free(c);
sqlite3_free(c->pToken);
sqlite3_free(c);
return SQLITE_OK;
}
@ -182,7 +183,7 @@ static int simpleNext(
int i, n = c->iOffset-iStartOffset;
if( n>c->nTokenAllocated ){
c->nTokenAllocated = n+20;
c->pToken = realloc(c->pToken, c->nTokenAllocated);
c->pToken = sqlite3_realloc(c->pToken, c->nTokenAllocated);
if( c->pToken==NULL ) return SQLITE_NOMEM;
}
for(i=0; i<n; i++){

View File

@ -4102,21 +4102,43 @@ static int fulltextFilter(
fulltext_cursor *c = (fulltext_cursor *) pCursor;
fulltext_vtab *v = cursor_vtab(c);
int rc;
StringBuffer sb;
FTSTRACE(("FTS3 Filter %p\n",pCursor));
initStringBuffer(&sb);
append(&sb, "SELECT docid, ");
appendList(&sb, v->nColumn, v->azContentColumn);
append(&sb, " FROM %_content");
if( idxNum!=QUERY_GENERIC ) append(&sb, " WHERE docid = ?");
sqlite3_finalize(c->pStmt);
rc = sql_prepare(v->db, v->zDb, v->zName, &c->pStmt, stringBufferData(&sb));
stringBufferDestroy(&sb);
if( rc!=SQLITE_OK ) return rc;
/* If the cursor has a statement that was not prepared according to
** idxNum, clear it. I believe all calls to fulltextFilter with a
** given cursor will have the same idxNum , but in this case it's
** easy to be safe.
*/
if( c->pStmt && c->iCursorType!=idxNum ){
sqlite3_finalize(c->pStmt);
c->pStmt = NULL;
}
/* Get a fresh statement appropriate to idxNum. */
/* TODO(shess): Add a prepared-statement cache in the vt structure.
** The cache must handle multiple open cursors. Easier to cache the
** statement variants at the vt to reduce malloc/realloc/free here.
** Or we could have a StringBuffer variant which allowed stack
** construction for small values.
*/
if( !c->pStmt ){
StringBuffer sb;
initStringBuffer(&sb);
append(&sb, "SELECT docid, ");
appendList(&sb, v->nColumn, v->azContentColumn);
append(&sb, " FROM %_content");
if( idxNum!=QUERY_GENERIC ) append(&sb, " WHERE docid = ?");
rc = sql_prepare(v->db, v->zDb, v->zName, &c->pStmt,
stringBufferData(&sb));
stringBufferDestroy(&sb);
if( rc!=SQLITE_OK ) return rc;
c->iCursorType = idxNum;
}else{
sqlite3_reset(c->pStmt);
assert( c->iCursorType==idxNum );
}
c->iCursorType = idxNum;
switch( idxNum ){
case QUERY_GENERIC:
break;

View File

@ -51,14 +51,14 @@ TCCX = $(TCC) $(OPTS) -I. -I$(TOP)/src -I$(TOP) -I$(TOP)/ext/rtree
LIBOBJ+= alter.o analyze.o attach.o auth.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 insert.o journal.o loadext.o \
main.o malloc.o mem1.o mem2.o mem3.o mem4.o mem5.o \
main.o malloc.o mem1.o mem2.o mem3.o mem4.o mem5.o mem6.o \
mutex.o mutex_os2.o mutex_unix.o mutex_w32.o \
opcodes.o os.o os_os2.o os_unix.o os_win.o \
pager.o parse.o pragma.o prepare.o printf.o random.o \
select.o status.o table.o $(TCLOBJ) tokenize.o trigger.o \
update.o util.o vacuum.o \
vdbe.o vdbeapi.o vdbeaux.o vdbeblob.o vdbefifo.o vdbemem.o \
where.o utf.o legacy.o vtab.o rtree.o
where.o utf.o legacy.o vtab.o rtree.o icu.o
EXTOBJ = icu.o
EXTOBJ += fts1.o \
@ -114,6 +114,7 @@ SRC = \
$(TOP)/src/mem3.c \
$(TOP)/src/mem4.c \
$(TOP)/src/mem5.c \
$(TOP)/src/mem6.c \
$(TOP)/src/mutex.c \
$(TOP)/src/mutex.h \
$(TOP)/src/mutex_os2.c \

View File

@ -10,8 +10,10 @@ make sqlite3.c
PATH=$PATH:/opt/mingw/bin
TCLDIR=/home/drh/tcltk/846/win/846win
TCLSTUBLIB=$TCLDIR/libtcl84stub.a
OPTS='-DUSE_TCL_STUBS=1 -DSQLITE_THREADSAFE=1 -DBUILD_sqlite=1 -DSQLITE_OS_WIN=1'
OPTS='-DUSE_TCL_STUBS=1 -DBUILD_sqlite=1 -DSQLITE_OS_WIN=1'
OPTS="$OPTS -DSQLITE_THREADSAFE=1"
OPTS="$OPTS -DSQLITE_ENABLE_FTS3=1"
OPTS="$OPTS -DSQLITE_ENABLE_COLUMN_METADATA=1"
CC="i386-mingw32msvc-gcc -Os $OPTS -Itsrc -I$TCLDIR"
NM="i386-mingw32msvc-nm"
CMD="$CC -c sqlite3.c"

View File

@ -12,6 +12,9 @@ rm shell.c
TCLDIR=/home/drh/tcltk/846/linux/846linux
TCLSTUBLIB=$TCLDIR/libtclstub8.4g.a
OPTS='-DUSE_TCL_STUBS=1 -DNDEBUG=1 -DHAVE_DLOPEN=1'
OPTS="$OPTS -DSQLITE_THREADSAFE=1"
OPTS="$OPTS -DSQLITE_ENABLE_FTS3=1"
OPTS="$OPTS -DSQLITE_ENABLE_COLUMN_METADATA=1"
for i in *.c; do
if test $i != 'keywordhash.c'; then
CMD="cc -fPIC $OPTS -O2 -I. -I$TCLDIR -c $i"

View File

@ -54,6 +54,7 @@ TCLDIR=/home/drh/tcltk/846/linux/846linux
TCLSTUBLIB=$TCLDIR/libtclstub8.4g.a
CFLAGS="-Os -DSQLITE_ENABLE_FTS3=3 -DSQLITE_ENABLE_RTREE=1"
CFLAGS="$CFLAGS -DHAVE_LOCALTIME_R=1 -DHAVE_GMTIME_R=1"
CFLAGS="$CFLAGS -DSQLITE_ENABLE_COLUMN_METADATA=1"
echo '***** BUILDING shared libraries for linux'
gcc $CFLAGS -shared tclsqlite3.c $TCLSTUBLIB -o tclsqlite3.so -lpthread
strip tclsqlite3.so
@ -93,8 +94,8 @@ ORIGIN=`pwd`
cd $srcdir
cd ..
mv sqlite sqlite-$VERS
EXCLUDE=`find sqlite-$VERS -print | egrep '(CVS|www/|art/|doc/|contrib/)' | sed 's,^, --exclude ,'`
#echo EXCLUDE=$EXCLUDE
EXCLUDE=`find sqlite-$VERS -print | egrep '(CVS|www/|art/|doc/|contrib/|_FOSSIL_|manifest)' | sed 's,^, --exclude ,'`
echo "tar czf $ORIGIN/doc/sqlite-$VERS.tar.gz $EXCLUDE sqlite-$VERS"
tar czf $ORIGIN/doc/sqlite-$VERS.tar.gz $EXCLUDE sqlite-$VERS
mv sqlite-$VERS sqlite
cd $ORIGIN

1254
src/.#vdbeapi.c.1.130 Normal file

File diff suppressed because it is too large Load Diff

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.46 2008/07/15 14:47:19 drh Exp $
** $Id: alter.c,v 1.47 2008/07/28 19:34:53 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@ -80,7 +80,7 @@ static void renameTableFunc(
zRet = sqlite3MPrintf(db, "%.*s\"%w\"%s", tname.z - zSql, zSql,
zTableName, tname.z+tname.n);
sqlite3_result_text(context, zRet, -1, sqlite3_free);
sqlite3_result_text(context, zRet, -1, SQLITE_DYNAMIC);
}
}
@ -155,7 +155,7 @@ static void renameTriggerFunc(
*/
zRet = sqlite3MPrintf(db, "%.*s\"%w\"%s", tname.z - zSql, zSql,
zTableName, tname.z+tname.n);
sqlite3_result_text(context, zRet, -1, sqlite3_free);
sqlite3_result_text(context, zRet, -1, SQLITE_DYNAMIC);
}
}
#endif /* !SQLITE_OMIT_TRIGGER */
@ -198,7 +198,7 @@ static char *whereTempTriggers(Parse *pParse, Table *pTab){
}else{
tmp = zWhere;
zWhere = sqlite3MPrintf(db, "%s OR name=%Q", zWhere, pTrig->name);
sqlite3_free(tmp);
sqlite3DbFree(db, tmp);
}
}
}
@ -409,7 +409,7 @@ void sqlite3AlterRenameTable(
"sql = sqlite_rename_trigger(sql, %Q), "
"tbl_name = %Q "
"WHERE %s;", zName, zName, zWhere);
sqlite3_free(zWhere);
sqlite3DbFree(db, zWhere);
}
#endif
@ -417,8 +417,8 @@ void sqlite3AlterRenameTable(
reloadTableSchema(pParse, pTab, zName);
exit_rename_table:
sqlite3SrcListDelete(pSrc);
sqlite3_free(zName);
sqlite3SrcListDelete(db, pSrc);
sqlite3DbFree(db, zName);
}
@ -518,7 +518,7 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
zDb, SCHEMA_TABLE(iDb), pNew->addColOffset, zCol, pNew->addColOffset+1,
zTab
);
sqlite3_free(zCol);
sqlite3DbFree(db, zCol);
}
/* If the default value of the new column is NULL, then set the file
@ -585,6 +585,7 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
if( !pNew ) goto exit_begin_add_column;
pParse->pNewTable = pNew;
pNew->nRef = 1;
pNew->db = db;
pNew->nCol = pTab->nCol;
assert( pNew->nCol>0 );
nAlloc = (((pNew->nCol-1)/8)*8)+8;
@ -614,7 +615,7 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
sqlite3ChangeCookie(pParse, iDb);
exit_begin_add_column:
sqlite3SrcListDelete(pSrc);
sqlite3SrcListDelete(db, pSrc);
return;
}
#endif /* SQLITE_ALTER_TABLE */

View File

@ -11,7 +11,7 @@
*************************************************************************
** This file contains code associated with the ANALYZE command.
**
** @(#) $Id: analyze.c,v 1.42 2008/03/25 09:47:35 danielk1977 Exp $
** @(#) $Id: analyze.c,v 1.43 2008/07/28 19:34:53 drh Exp $
*/
#ifndef SQLITE_OMIT_ANALYZE
#include "sqliteInt.h"
@ -316,7 +316,7 @@ void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){
z = sqlite3NameFromToken(db, pName1);
if( z ){
pTab = sqlite3LocateTable(pParse, 0, z, 0);
sqlite3_free(z);
sqlite3DbFree(db, z);
if( pTab ){
analyzeTable(pParse, pTab);
}
@ -330,7 +330,7 @@ void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){
z = sqlite3NameFromToken(db, pTableName);
if( z ){
pTab = sqlite3LocateTable(pParse, 0, z, zDb);
sqlite3_free(z);
sqlite3DbFree(db, z);
if( pTab ){
analyzeTable(pParse, pTab);
}
@ -417,7 +417,7 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
(void)sqlite3SafetyOff(db);
rc = sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0);
(void)sqlite3SafetyOn(db);
sqlite3_free(zSql);
sqlite3DbFree(db, zSql);
return rc;
}

View File

@ -11,7 +11,7 @@
*************************************************************************
** This file contains code used to implement the ATTACH and DETACH commands.
**
** $Id: attach.c,v 1.76 2008/06/15 02:51:47 drh Exp $
** $Id: attach.c,v 1.77 2008/07/28 19:34:53 drh Exp $
*/
#include "sqliteInt.h"
@ -214,7 +214,7 @@ attach_error:
/* Return an error if we get here */
if( zErrDyn ){
sqlite3_result_error(context, zErrDyn, -1);
sqlite3_free(zErrDyn);
sqlite3DbFree(db, zErrDyn);
}else{
zErr[sizeof(zErr)-1] = 0;
sqlite3_result_error(context, zErr, -1);
@ -305,7 +305,7 @@ static void codeAttach(
goto attach_end;
}
rc = sqlite3AuthCheck(pParse, type, zAuthArg, 0, 0);
sqlite3_free(zAuthArg);
sqlite3DbFree(db, zAuthArg);
if(rc!=SQLITE_OK ){
goto attach_end;
}
@ -345,9 +345,9 @@ static void codeAttach(
}
attach_end:
sqlite3ExprDelete(pFilename);
sqlite3ExprDelete(pDbname);
sqlite3ExprDelete(pKey);
sqlite3ExprDelete(db, pFilename);
sqlite3ExprDelete(db, pDbname);
sqlite3ExprDelete(db, pKey);
}
/*

View File

@ -9,7 +9,7 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
** $Id: btree.c,v 1.482 2008/07/12 14:52:20 drh Exp $
** $Id: btree.c,v 1.495 2008/08/02 17:36:46 danielk1977 Exp $
**
** This file implements a external (disk-based) database using BTrees.
** See the header comment on "btreeInt.h" for additional information.
@ -458,7 +458,7 @@ static int ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent){
if( rc!=SQLITE_OK ){
return rc;
}
offset = PTRMAP_PTROFFSET(pBt, key);
offset = PTRMAP_PTROFFSET(iPtrmap, key);
pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage);
if( eType!=pPtrmap[offset] || get4byte(&pPtrmap[offset+1])!=parent ){
@ -497,7 +497,7 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){
}
pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage);
offset = PTRMAP_PTROFFSET(pBt, key);
offset = PTRMAP_PTROFFSET(iPtrmap, key);
assert( pEType!=0 );
*pEType = pPtrmap[offset];
if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]);
@ -507,7 +507,11 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){
return SQLITE_OK;
}
#endif /* SQLITE_OMIT_AUTOVACUUM */
#else /* if defined SQLITE_OMIT_AUTOVACUUM */
#define ptrmapPut(w,x,y,z) SQLITE_OK
#define ptrmapGet(w,x,y,z) SQLITE_OK
#define ptrmapPutOvfl(y,z) SQLITE_OK
#endif
/*
** Given a btree page and a cell index (0 means the first cell on
@ -516,8 +520,8 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){
**
** This routine works only for pages that do not contain overflow cells.
*/
#define findCell(pPage, iCell) \
((pPage)->aData + get2byte(&(pPage)->aData[(pPage)->cellOffset+2*(iCell)]))
#define findCell(P,I) \
((P)->aData + ((P)->maskPage & get2byte(&(P)->aData[(P)->cellOffset+2*(I)])))
/*
** This a more complex version of findCell() that works for
@ -564,31 +568,30 @@ void sqlite3BtreeParseCellPtr(
assert( pPage->leaf==0 || pPage->leaf==1 );
n = pPage->childPtrSize;
assert( n==4-4*pPage->leaf );
if( pPage->hasData ){
n += getVarint32(&pCell[n], nPayload);
}else{
nPayload = 0;
}
pInfo->nData = nPayload;
if( pPage->intKey ){
n += getVarint(&pCell[n], (u64 *)&pInfo->nKey);
if( pPage->hasData ){
n += getVarint32(&pCell[n], nPayload);
}else{
nPayload = 0;
}
n += getVarint(&pCell[n], (u64*)&pInfo->nKey);
pInfo->nData = nPayload;
}else{
u32 x;
n += getVarint32(&pCell[n], x);
pInfo->nKey = x;
nPayload += x;
pInfo->nData = 0;
n += getVarint32(&pCell[n], nPayload);
pInfo->nKey = nPayload;
}
pInfo->nPayload = nPayload;
pInfo->nHeader = n;
if( nPayload<=pPage->maxLocal ){
if( likely(nPayload<=pPage->maxLocal) ){
/* This is the (easy) common case where the entire payload fits
** on the local page. No overflow is required.
*/
int nSize; /* Total size of cell content in bytes */
nSize = nPayload + n;
pInfo->nLocal = nPayload;
pInfo->iOverflow = 0;
nSize = nPayload + n;
if( nSize<4 ){
if( (nSize & ~3)==0 ){
nSize = 4; /* Minimum cell size is 4 */
}
pInfo->nSize = nSize;
@ -871,27 +874,38 @@ static void freeSpace(MemPage *pPage, int start, int size){
/*
** Decode the flags byte (the first byte of the header) for a page
** and initialize fields of the MemPage structure accordingly.
**
** Only the following combinations are supported. Anything different
** indicates a corrupt database files:
**
** PTF_ZERODATA
** PTF_ZERODATA | PTF_LEAF
** PTF_LEAFDATA | PTF_INTKEY
** PTF_LEAFDATA | PTF_INTKEY | PTF_LEAF
*/
static void decodeFlags(MemPage *pPage, int flagByte){
static int decodeFlags(MemPage *pPage, int flagByte){
BtShared *pBt; /* A copy of pPage->pBt */
assert( pPage->hdrOffset==(pPage->pgno==1 ? 100 : 0) );
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
pPage->intKey = (flagByte & (PTF_INTKEY|PTF_LEAFDATA))!=0;
pPage->zeroData = (flagByte & PTF_ZERODATA)!=0;
pPage->leaf = (flagByte & PTF_LEAF)!=0;
pPage->childPtrSize = 4*(pPage->leaf==0);
pPage->leaf = flagByte>>3; assert( PTF_LEAF == 1<<3 );
flagByte &= ~PTF_LEAF;
pPage->childPtrSize = 4-4*pPage->leaf;
pBt = pPage->pBt;
if( flagByte & PTF_LEAFDATA ){
pPage->leafData = 1;
if( flagByte==(PTF_LEAFDATA | PTF_INTKEY) ){
pPage->intKey = 1;
pPage->hasData = pPage->leaf;
pPage->maxLocal = pBt->maxLeaf;
pPage->minLocal = pBt->minLeaf;
}else{
pPage->leafData = 0;
}else if( flagByte==PTF_ZERODATA ){
pPage->intKey = 0;
pPage->hasData = 0;
pPage->maxLocal = pBt->maxLocal;
pPage->minLocal = pBt->minLocal;
}else{
return SQLITE_CORRUPT_BKPT;
}
pPage->hasData = !(pPage->zeroData || (!pPage->leaf && pPage->leafData));
return SQLITE_OK;
}
/*
@ -919,9 +933,6 @@ int sqlite3BtreeInitPage(
int cellOffset; /* Offset from start of page to first cell pointer */
int nFree; /* Number of unused bytes on the page */
int top; /* First byte of the cell content area */
u8 *pOff; /* Iterator used to check all cell offsets are in range */
u8 *pEnd; /* Pointer to end of cell offset array */
u8 mask; /* Mask of bits that must be zero in MSB of cell offsets */
pBt = pPage->pBt;
assert( pBt!=0 );
@ -941,7 +952,9 @@ int sqlite3BtreeInitPage(
}
hdr = pPage->hdrOffset;
data = pPage->aData;
decodeFlags(pPage, data[hdr]);
if( decodeFlags(pPage, data[hdr]) ) return SQLITE_CORRUPT_BKPT;
assert( pBt->pageSize>=512 && pBt->pageSize<=32768 );
pPage->maskPage = pBt->pageSize - 1;
pPage->nOverflow = 0;
pPage->idxShift = 0;
usableSize = pBt->usableSize;
@ -981,13 +994,25 @@ int sqlite3BtreeInitPage(
return SQLITE_CORRUPT_BKPT;
}
/* Check that all the offsets in the cell offset array are within range. */
mask = ~(((u8)(pBt->pageSize>>8))-1);
pEnd = &data[cellOffset + pPage->nCell*2];
for(pOff=&data[cellOffset]; pOff!=pEnd && !((*pOff)&mask); pOff+=2);
if( pOff!=pEnd ){
return SQLITE_CORRUPT_BKPT;
#if 0
/* Check that all the offsets in the cell offset array are within range.
**
** Omitting this consistency check and using the pPage->maskPage mask
** to prevent overrunning the page buffer in findCell() results in a
** 2.5% performance gain.
*/
{
u8 *pOff; /* Iterator used to check all cell offsets are in range */
u8 *pEnd; /* Pointer to end of cell offset array */
u8 mask; /* Mask of bits that must be zero in MSB of cell offsets */
mask = ~(((u8)(pBt->pageSize>>8))-1);
pEnd = &data[cellOffset + pPage->nCell*2];
for(pOff=&data[cellOffset]; pOff!=pEnd && !((*pOff)&mask); pOff+=2);
if( pOff!=pEnd ){
return SQLITE_CORRUPT_BKPT;
}
}
#endif
pPage->isInit = 1;
return SQLITE_OK;
@ -1008,7 +1033,7 @@ static void zeroPage(MemPage *pPage, int flags){
assert( sqlite3PagerGetData(pPage->pDbPage) == data );
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
assert( sqlite3_mutex_held(pBt->mutex) );
memset(&data[hdr], 0, pBt->usableSize - hdr);
/*memset(&data[hdr], 0, pBt->usableSize - hdr);*/
data[hdr] = flags;
first = hdr + 8 + 4*((flags&PTF_LEAF)==0);
memset(&data[hdr+1], 0, 4);
@ -1019,6 +1044,8 @@ static void zeroPage(MemPage *pPage, int flags){
pPage->hdrOffset = hdr;
pPage->cellOffset = first;
pPage->nOverflow = 0;
assert( pBt->pageSize>=512 && pBt->pageSize<=32768 );
pPage->maskPage = pBt->pageSize - 1;
pPage->idxShift = 0;
pPage->nCell = 0;
pPage->isInit = 1;
@ -1992,6 +2019,18 @@ trans_begun:
return rc;
}
/*
** Return the size of the database file in pages. Or return -1 if
** there is any kind of error.
*/
static int pagerPagecount(Pager *pPager){
int rc;
int nPage;
rc = sqlite3PagerPagecount(pPager, &nPage);
return (rc==SQLITE_OK?nPage:-1);
}
#ifndef SQLITE_OMIT_AUTOVACUUM
/*
@ -2112,7 +2151,8 @@ static int relocatePage(
MemPage *pDbPage, /* Open page to move */
u8 eType, /* Pointer map 'type' entry for pDbPage */
Pgno iPtrPage, /* Pointer map 'page-no' entry for pDbPage */
Pgno iFreePage /* The location to move pDbPage to */
Pgno iFreePage, /* The location to move pDbPage to */
int isCommit
){
MemPage *pPtrPage; /* The page that contains a pointer to pDbPage */
Pgno iDbPage = pDbPage->pgno;
@ -2127,7 +2167,7 @@ static int relocatePage(
/* Move page iDbPage from its current location to page number iFreePage */
TRACE(("AUTOVACUUM: Moving %d to free page %d (ptr page %d type %d)\n",
iDbPage, iFreePage, iPtrPage, eType));
rc = sqlite3PagerMovepage(pPager, pDbPage->pDbPage, iFreePage);
rc = sqlite3PagerMovepage(pPager, pDbPage->pDbPage, iFreePage, isCommit);
if( rc!=SQLITE_OK ){
return rc;
}
@ -2179,13 +2219,6 @@ static int relocatePage(
return rc;
}
static int pagerPagecount(Pager *pPager){
int rc;
int nPage;
rc = sqlite3PagerPagecount(pPager, &nPage);
return (rc==SQLITE_OK?nPage:-1);
}
/* Forward declaration required by incrVacuumStep(). */
static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8);
@ -2277,7 +2310,7 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin){
rc = sqlite3PagerWrite(pLastPg->pDbPage);
if( rc==SQLITE_OK ){
rc = relocatePage(pBt, pLastPg, eType, iPtrPage, iFreePg);
rc = relocatePage(pBt, pLastPg, eType, iPtrPage, iFreePg, nFin!=0);
}
releasePage(pLastPg);
if( rc!=SQLITE_OK ){
@ -3756,7 +3789,7 @@ int sqlite3BtreeMoveto(
}
if( c==0 ){
pCur->info.nKey = nCellKey;
if( pPage->leafData && !pPage->leaf ){
if( pPage->intKey && !pPage->leaf ){
lwr = pCur->idx;
upr = lwr - 1;
break;
@ -3883,7 +3916,7 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
pPage = pCur->pPage;
}while( pCur->idx>=pPage->nCell );
*pRes = 0;
if( pPage->leafData ){
if( pPage->intKey ){
rc = sqlite3BtreeNext(pCur, pRes);
}else{
rc = SQLITE_OK;
@ -3950,7 +3983,7 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
pCur->idx--;
pCur->info.nSize = 0;
pCur->validNKey = 0;
if( pPage->leafData && !pPage->leaf ){
if( pPage->intKey && !pPage->leaf ){
rc = sqlite3BtreePrevious(pCur, pRes);
}else{
rc = SQLITE_OK;
@ -4254,15 +4287,13 @@ static int freePage(MemPage *pPage){
memset(pPage->aData, 0, pPage->pBt->pageSize);
#endif
#ifndef SQLITE_OMIT_AUTOVACUUM
/* If the database supports auto-vacuum, write an entry in the pointer-map
** to indicate that the page is free.
*/
if( pBt->autoVacuum ){
if( ISAUTOVACUUM ){
rc = ptrmapPut(pBt, pPage->pgno, PTRMAP_FREEPAGE, 0);
if( rc ) return rc;
}
#endif
if( n==0 ){
/* This is the first free page */
@ -4493,12 +4524,23 @@ static int fillInCell(
return SQLITE_OK;
}
/*
** Change the MemPage.pParent pointer on the page whose number is
** given in the second argument so that MemPage.pParent holds the
** pointer in the third argument.
**
** If the final argument, updatePtrmap, is non-zero and the database
** is an auto-vacuum database, then the pointer-map entry for pgno
** is updated.
*/
static int reparentPage(BtShared *pBt, Pgno pgno, MemPage *pNewParent, int idx){
static int reparentPage(
BtShared *pBt, /* B-Tree structure */
Pgno pgno, /* Page number of child being adopted */
MemPage *pNewParent, /* New parent of pgno */
int idx, /* Index of child page pgno in pNewParent */
int updatePtrmap /* If true, update pointer-map for pgno */
){
MemPage *pThis;
DbPage *pDbPage;
@ -4521,11 +4563,26 @@ static int reparentPage(BtShared *pBt, Pgno pgno, MemPage *pNewParent, int idx){
sqlite3PagerUnref(pDbPage);
}
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->autoVacuum ){
if( ISAUTOVACUUM && updatePtrmap ){
return ptrmapPut(pBt, pgno, PTRMAP_BTREE, pNewParent->pgno);
}
#ifndef NDEBUG
/* If the updatePtrmap flag was clear, assert that the entry in the
** pointer-map is already correct.
*/
if( ISAUTOVACUUM ){
pDbPage = sqlite3PagerLookup(pBt->pPager,PTRMAP_PAGENO(pBt,pgno));
if( pDbPage ){
u8 eType;
Pgno ii;
int rc = ptrmapGet(pBt, pgno, &eType, &ii);
assert( rc==SQLITE_OK && ii==pNewParent->pgno && eType==PTRMAP_BTREE );
sqlite3PagerUnref(pDbPage);
}
}
#endif
return SQLITE_OK;
}
@ -4540,23 +4597,26 @@ static int reparentPage(BtShared *pBt, Pgno pgno, MemPage *pNewParent, int idx){
**
** This routine gets called after you memcpy() one page into
** another.
**
** If updatePtrmap is true, then the pointer-map entries for all child
** pages of pPage are updated.
*/
static int reparentChildPages(MemPage *pPage){
int i;
BtShared *pBt = pPage->pBt;
static int reparentChildPages(MemPage *pPage, int updatePtrmap){
int rc = SQLITE_OK;
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
if( pPage->leaf ) return SQLITE_OK;
if( !pPage->leaf ){
int i;
BtShared *pBt = pPage->pBt;
Pgno iRight = get4byte(&pPage->aData[pPage->hdrOffset+8]);
for(i=0; i<pPage->nCell; i++){
u8 *pCell = findCell(pPage, i);
rc = reparentPage(pBt, get4byte(pCell), pPage, i);
if( rc!=SQLITE_OK ) return rc;
for(i=0; i<pPage->nCell; i++){
u8 *pCell = findCell(pPage, i);
rc = reparentPage(pBt, get4byte(pCell), pPage, i, updatePtrmap);
if( rc!=SQLITE_OK ) return rc;
}
rc = reparentPage(pBt, iRight, pPage, i, updatePtrmap);
pPage->idxShift = 0;
}
rc = reparentPage(pBt, get4byte(&pPage->aData[pPage->hdrOffset+8]),
pPage, i);
pPage->idxShift = 0;
return rc;
}
@ -4827,12 +4887,11 @@ static int balance_quick(MemPage *pPage, MemPage *pParent){
put4byte(findOverflowCell(pParent,parentIdx), pPage->pgno);
put4byte(&pParent->aData[pParent->hdrOffset+8], pgnoNew);
#ifndef SQLITE_OMIT_AUTOVACUUM
/* If this is an auto-vacuum database, update the pointer map
** with entries for the new page, and any pointer from the
** cell on the page to an overflow page.
*/
if( pBt->autoVacuum ){
if( ISAUTOVACUUM ){
rc = ptrmapPut(pBt, pgnoNew, PTRMAP_BTREE, pParent->pgno);
if( rc==SQLITE_OK ){
rc = ptrmapPutOvfl(pNew, 0);
@ -4842,7 +4901,6 @@ static int balance_quick(MemPage *pPage, MemPage *pParent){
return rc;
}
}
#endif
/* Release the reference to the new page and balance the parent page,
** in case the divider cell inserted caused it to become overfull.
@ -4914,9 +4972,7 @@ static int balance_nonroot(MemPage *pPage){
u8 *aCopy[NB]; /* Space for holding data of apCopy[] */
u8 *aSpace1; /* Space for copies of dividers cells before balance */
u8 *aSpace2 = 0; /* Space for overflow dividers cells after balance */
#ifndef SQLITE_OMIT_AUTOVACUUM
u8 *aFrom = 0;
#endif
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
@ -4945,12 +5001,12 @@ static int balance_nonroot(MemPage *pPage){
*/
if( pPage->leaf &&
pPage->intKey &&
pPage->leafData &&
pPage->nOverflow==1 &&
pPage->aOvfl[0].idx==pPage->nCell &&
pPage->pParent->pgno!=1 &&
get4byte(&pParent->aData[pParent->hdrOffset+8])==pPage->pgno
){
assert( pPage->intKey );
/*
** TODO: Check the siblings to the left of pPage. It may be that
** they are not full and no new page is required.
@ -5052,11 +5108,9 @@ static int balance_nonroot(MemPage *pPage){
}
aSpace1 = &aCopy[NB-1][pBt->pageSize+ROUND8(sizeof(MemPage))];
assert( ((aSpace1 - (u8*)apCell) & 7)==0 ); /* 8-byte alignment required */
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->autoVacuum ){
if( ISAUTOVACUUM ){
aFrom = &aSpace1[pBt->pageSize];
}
#endif
aSpace2 = sqlite3PageMalloc(pBt->pageSize);
if( aSpace2==0 ){
rc = SQLITE_NOMEM;
@ -5094,7 +5148,7 @@ static int balance_nonroot(MemPage *pPage){
*/
nCell = 0;
leafCorrection = pPage->leaf*4;
leafData = pPage->leafData && pPage->leaf;
leafData = pPage->hasData;
for(i=0; i<nOld; i++){
MemPage *pOld = apCopy[i];
int limit = pOld->nCell+pOld->nOverflow;
@ -5102,8 +5156,7 @@ static int balance_nonroot(MemPage *pPage){
assert( nCell<nMaxCells );
apCell[nCell] = findOverflowCell(pOld, j);
szCell[nCell] = cellSizePtr(pOld, apCell[nCell]);
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->autoVacuum ){
if( ISAUTOVACUUM ){
int a;
aFrom[nCell] = i;
for(a=0; a<pOld->nOverflow; a++){
@ -5113,7 +5166,6 @@ static int balance_nonroot(MemPage *pPage){
}
}
}
#endif
nCell++;
}
if( i<nOld-1 ){
@ -5135,11 +5187,9 @@ static int balance_nonroot(MemPage *pPage){
assert( iSpace1<=pBt->pageSize );
memcpy(pTemp, apDiv[i], sz);
apCell[nCell] = pTemp+leafCorrection;
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->autoVacuum ){
if( ISAUTOVACUUM ){
aFrom[nCell] = 0xFF;
}
#endif
dropCell(pParent, nxDiv, sz);
szCell[nCell] -= leafCorrection;
assert( get4byte(pTemp)==pgnoOld[i] );
@ -5321,24 +5371,25 @@ static int balance_nonroot(MemPage *pPage){
assert( pNew->nCell>0 || (nNew==1 && cntNew[0]==0) );
assert( pNew->nOverflow==0 );
#ifndef SQLITE_OMIT_AUTOVACUUM
/* If this is an auto-vacuum database, update the pointer map entries
** that point to the siblings that were rearranged. These can be: left
** children of cells, the right-child of the page, or overflow pages
** pointed to by cells.
*/
if( pBt->autoVacuum ){
if( ISAUTOVACUUM ){
for(k=j; k<cntNew[i]; k++){
assert( k<nMaxCells );
if( aFrom[k]==0xFF || apCopy[aFrom[k]]->pgno!=pNew->pgno ){
rc = ptrmapPutOvfl(pNew, k-j);
if( rc==SQLITE_OK && leafCorrection==0 ){
rc = ptrmapPut(pBt, get4byte(apCell[k]), PTRMAP_BTREE, pNew->pgno);
}
if( rc!=SQLITE_OK ){
goto balance_cleanup;
}
}
}
}
#endif
j = cntNew[i];
@ -5356,6 +5407,14 @@ static int balance_nonroot(MemPage *pPage){
pTemp = &aSpace2[iSpace2];
if( !pNew->leaf ){
memcpy(&pNew->aData[8], pCell, 4);
if( ISAUTOVACUUM
&& (aFrom[j]==0xFF || apCopy[aFrom[j]]->pgno!=pNew->pgno)
){
rc = ptrmapPut(pBt, get4byte(pCell), PTRMAP_BTREE, pNew->pgno);
if( rc!=SQLITE_OK ){
goto balance_cleanup;
}
}
}else if( leafData ){
/* If the tree is a leaf-data tree, and the siblings are leaves,
** then there is no divider cell in apCell[]. Instead, the divider
@ -5392,27 +5451,41 @@ static int balance_nonroot(MemPage *pPage){
rc = insertCell(pParent, nxDiv, pCell, sz, pTemp, 4);
if( rc!=SQLITE_OK ) goto balance_cleanup;
put4byte(findOverflowCell(pParent,nxDiv), pNew->pgno);
#ifndef SQLITE_OMIT_AUTOVACUUM
/* If this is an auto-vacuum database, and not a leaf-data tree,
** then update the pointer map with an entry for the overflow page
** that the cell just inserted points to (if any).
*/
if( pBt->autoVacuum && !leafData ){
if( ISAUTOVACUUM && !leafData ){
rc = ptrmapPutOvfl(pParent, nxDiv);
if( rc!=SQLITE_OK ){
goto balance_cleanup;
}
}
#endif
j++;
nxDiv++;
}
/* Set the pointer-map entry for the new sibling page. */
if( ISAUTOVACUUM ){
rc = ptrmapPut(pBt, pNew->pgno, PTRMAP_BTREE, pParent->pgno);
if( rc!=SQLITE_OK ){
goto balance_cleanup;
}
}
}
assert( j==nCell );
assert( nOld>0 );
assert( nNew>0 );
if( (pageFlags & PTF_LEAF)==0 ){
memcpy(&apNew[nNew-1]->aData[8], &apCopy[nOld-1]->aData[8], 4);
u8 *zChild = &apCopy[nOld-1]->aData[8];
memcpy(&apNew[nNew-1]->aData[8], zChild, 4);
if( ISAUTOVACUUM ){
rc = ptrmapPut(pBt, get4byte(zChild), PTRMAP_BTREE, apNew[nNew-1]->pgno);
if( rc!=SQLITE_OK ){
goto balance_cleanup;
}
}
}
if( nxDiv==pParent->nCell+pParent->nOverflow ){
/* Right-most sibling is the right-most child of pParent */
@ -5427,10 +5500,10 @@ static int balance_nonroot(MemPage *pPage){
** Reparent children of all cells.
*/
for(i=0; i<nNew; i++){
rc = reparentChildPages(apNew[i]);
rc = reparentChildPages(apNew[i], 0);
if( rc!=SQLITE_OK ) goto balance_cleanup;
}
rc = reparentChildPages(pParent);
rc = reparentChildPages(pParent, 0);
if( rc!=SQLITE_OK ) goto balance_cleanup;
/*
@ -5538,10 +5611,9 @@ static int balance_shallower(MemPage *pPage){
TRACE(("BALANCE: transfer child %d into root %d\n",
pChild->pgno, pPage->pgno));
}
rc = reparentChildPages(pPage);
rc = reparentChildPages(pPage, 1);
assert( pPage->nOverflow==0 );
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->autoVacuum ){
if( ISAUTOVACUUM ){
int i;
for(i=0; i<pPage->nCell; i++){
rc = ptrmapPutOvfl(pPage, i);
@ -5550,7 +5622,6 @@ static int balance_shallower(MemPage *pPage){
}
}
}
#endif
releasePage(pChild);
}
end_shallow_balance:
@ -5605,8 +5676,7 @@ static int balance_deeper(MemPage *pPage){
zeroPage(pPage, pChild->aData[0] & ~PTF_LEAF);
put4byte(&pPage->aData[pPage->hdrOffset+8], pgnoChild);
TRACE(("BALANCE: copy root %d into %d\n", pPage->pgno, pChild->pgno));
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->autoVacuum ){
if( ISAUTOVACUUM ){
int i;
rc = ptrmapPut(pBt, pChild->pgno, PTRMAP_BTREE, pPage->pgno);
if( rc ) goto balancedeeper_out;
@ -5616,9 +5686,11 @@ static int balance_deeper(MemPage *pPage){
goto balancedeeper_out;
}
}
rc = reparentChildPages(pChild, 1);
}
if( rc==SQLITE_OK ){
rc = balance_nonroot(pChild);
}
#endif
rc = balance_nonroot(pChild);
balancedeeper_out:
releasePage(pChild);
@ -5771,7 +5843,7 @@ int sqlite3BtreeInsert(
pPage = pCur->pPage;
assert( pPage->intKey || nKey>=0 );
assert( pPage->leaf || !pPage->leafData );
assert( pPage->leaf || !pPage->intKey );
TRACE(("INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n",
pCur->pgnoRoot, nKey, nData, pPage->pgno,
loc==0 ? "overwrite" : "new entry"));
@ -5887,7 +5959,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){
unsigned char *pNext;
int notUsed;
unsigned char *tempCell = 0;
assert( !pPage->leafData );
assert( !pPage->intKey );
sqlite3BtreeGetTempCursor(pCur, &leafCur);
rc = sqlite3BtreeNext(&leafCur, &notUsed);
if( rc==SQLITE_OK ){
@ -6030,7 +6102,7 @@ static int btreeCreateTable(Btree *p, int *piTable, int flags){
releasePage(pRoot);
return rc;
}
rc = relocatePage(pBt, pRoot, eType, iPtrPage, pgnoMove);
rc = relocatePage(pBt, pRoot, eType, iPtrPage, pgnoMove, 0);
releasePage(pRoot);
/* Obtain the page at pgnoRoot */
@ -6238,7 +6310,7 @@ static int btreeDropTable(Btree *p, int iTable, int *piMoved){
if( rc!=SQLITE_OK ){
return rc;
}
rc = relocatePage(pBt, pMove, PTRMAP_ROOTPAGE, 0, iTable);
rc = relocatePage(pBt, pMove, PTRMAP_ROOTPAGE, 0, iTable, 0);
releasePage(pMove);
if( rc!=SQLITE_OK ){
return rc;
@ -6425,6 +6497,9 @@ static void checkAppendMsg(
}
sqlite3VXPrintf(&pCheck->errMsg, 1, zFormat, ap);
va_end(ap);
if( pCheck->errMsg.mallocFailed ){
pCheck->mallocFailed = 1;
}
}
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
@ -6668,7 +6743,9 @@ static int checkTreePage(
data = pPage->aData;
hdr = pPage->hdrOffset;
hit = sqlite3PageMalloc( pBt->pageSize );
if( hit ){
if( hit==0 ){
pCheck->mallocFailed = 1;
}else{
memset(hit, 0, usableSize );
memset(hit, 1, get2byte(&data[hdr+5]));
nCell = get2byte(&data[hdr+3]);
@ -6724,10 +6801,10 @@ static int checkTreePage(
** an array of pages numbers were each page number is the root page of
** a table. nRoot is the number of entries in aRoot.
**
** If everything checks out, this routine returns NULL. If something is
** amiss, an error message is written into memory obtained from malloc()
** and a pointer to that error message is returned. The calling function
** is responsible for freeing the error message when it is done.
** Write the number of error seen in *pnErr. Except for some memory
** allocation errors, nn error message is held in memory obtained from
** malloc is returned if *pnErr is non-zero. If *pnErr==0 then NULL is
** returned.
*/
char *sqlite3BtreeIntegrityCheck(
Btree *p, /* The btree to be checked */
@ -6746,14 +6823,16 @@ char *sqlite3BtreeIntegrityCheck(
pBt->db = p->db;
nRef = sqlite3PagerRefcount(pBt->pPager);
if( lockBtreeWithRetry(p)!=SQLITE_OK ){
*pnErr = 1;
sqlite3BtreeLeave(p);
return sqlite3StrDup("Unable to acquire a read lock on the database");
return sqlite3DbStrDup(0, "cannot acquire a read lock on the database");
}
sCheck.pBt = pBt;
sCheck.pPager = pBt->pPager;
sCheck.nPage = pagerPagecount(sCheck.pPager);
sCheck.mxErr = mxErr;
sCheck.nErr = 0;
sCheck.mallocFailed = 0;
*pnErr = 0;
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->nTrunc!=0 ){
@ -6770,8 +6849,7 @@ char *sqlite3BtreeIntegrityCheck(
unlockBtreeIfUnused(pBt);
*pnErr = 1;
sqlite3BtreeLeave(p);
return sqlite3MPrintf(p->db, "Unable to malloc %d bytes",
(sCheck.nPage+1)*sizeof(sCheck.anRef[0]));
return 0;
}
for(i=0; i<=sCheck.nPage; i++){ sCheck.anRef[i] = 0; }
i = PENDING_BYTE_PAGE(pBt);
@ -6833,6 +6911,11 @@ char *sqlite3BtreeIntegrityCheck(
*/
sqlite3BtreeLeave(p);
sqlite3_free(sCheck.anRef);
if( sCheck.mallocFailed ){
sqlite3StrAccumReset(&sCheck.errMsg);
*pnErr = sCheck.nErr+1;
return 0;
}
*pnErr = sCheck.nErr;
if( sCheck.nErr==0 ) sqlite3StrAccumReset(&sCheck.errMsg);
return sqlite3StrAccumFinish(&sCheck.errMsg);

View File

@ -9,7 +9,7 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
** $Id: btreeInt.h,v 1.26 2008/07/12 14:52:20 drh Exp $
** $Id: btreeInt.h,v 1.30 2008/08/01 20:10:08 drh Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
@ -275,8 +275,6 @@ struct MemPage {
u8 nOverflow; /* Number of overflow cell bodies in aCell[] */
u8 intKey; /* True if intkey flag is set */
u8 leaf; /* True if leaf flag is set */
u8 zeroData; /* True if table stores keys only */
u8 leafData; /* True if tables stores data on leaves only */
u8 hasData; /* True if this page stores data */
u8 hdrOffset; /* 100 for page 1. 0 otherwise */
u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */
@ -286,6 +284,7 @@ struct MemPage {
u16 idxParent; /* Index in parent of this node */
u16 nFree; /* Number of free bytes on the page */
u16 nCell; /* Number of cells on this page, local and ovfl */
u16 maskPage; /* Mask for page offset */
struct _OvflCell { /* Cells that will not fit on aData[] */
u8 *pCell; /* Pointers to the body of the overflow cell */
u16 idx; /* Insert this cell before idx-th non-overflow cell */
@ -528,7 +527,7 @@ struct BtLock {
** this test.
*/
#define PTRMAP_PAGENO(pBt, pgno) ptrmapPageno(pBt, pgno)
#define PTRMAP_PTROFFSET(pBt, pgno) (5*(pgno-ptrmapPageno(pBt, pgno)-1))
#define PTRMAP_PTROFFSET(pgptrmap, pgno) (5*(pgno-pgptrmap-1))
#define PTRMAP_ISPAGE(pBt, pgno) (PTRMAP_PAGENO((pBt),(pgno))==(pgno))
/*
@ -602,6 +601,7 @@ struct IntegrityCk {
int *anRef; /* Number of times each page is referenced */
int mxErr; /* Stop accumulating errors when this reaches zero */
int nErr; /* Number of messages written to zErrMsg so far */
int mallocFailed; /* A memory allocation error has occurred */
StrAccum errMsg; /* Accumulate the error message text here */
};

View File

@ -22,7 +22,7 @@
** COMMIT
** ROLLBACK
**
** $Id: build.c,v 1.490 2008/07/08 23:40:20 drh Exp $
** $Id: build.c,v 1.493 2008/08/04 04:39:49 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@ -137,12 +137,6 @@ void sqlite3FinishCoding(Parse *pParse){
if( db->mallocFailed ) return;
if( pParse->nested ) return;
if( pParse->nErr ) return;
if( !pParse->pVdbe ){
if( pParse->rc==SQLITE_OK && pParse->nErr ){
pParse->rc = SQLITE_ERROR;
return;
}
}
/* Begin by generating some termination code at the end of the
** vdbe program
@ -239,24 +233,24 @@ void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
va_list ap;
char *zSql;
char *zErrMsg = 0;
sqlite3 *db = pParse->db;
# define SAVE_SZ (sizeof(Parse) - offsetof(Parse,nVar))
char saveBuf[SAVE_SZ];
if( pParse->nErr ) return;
assert( pParse->nested<10 ); /* Nesting should only be of limited depth */
va_start(ap, zFormat);
zSql = sqlite3VMPrintf(pParse->db, zFormat, ap);
zSql = sqlite3VMPrintf(db, zFormat, ap);
va_end(ap);
if( zSql==0 ){
pParse->db->mallocFailed = 1;
return; /* A malloc must have failed */
}
pParse->nested++;
memcpy(saveBuf, &pParse->nVar, SAVE_SZ);
memset(&pParse->nVar, 0, SAVE_SZ);
sqlite3RunParser(pParse, zSql, &zErrMsg);
sqlite3_free(zErrMsg);
sqlite3_free(zSql);
sqlite3DbFree(db, zErrMsg);
sqlite3DbFree(db, zSql);
memcpy(&pParse->nVar, saveBuf, SAVE_SZ);
pParse->nested--;
}
@ -358,8 +352,9 @@ Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const char *zDb){
** Reclaim the memory used by an index
*/
static void freeIndex(Index *p){
sqlite3_free(p->zColAff);
sqlite3_free(p);
sqlite3 *db = p->pTable->db;
sqlite3DbFree(db, p->zColAff);
sqlite3DbFree(db, p);
}
/*
@ -453,7 +448,7 @@ void sqlite3ResetInternalSchema(sqlite3 *db, int iDb){
for(i=j=2; i<db->nDb; i++){
struct Db *pDb = &db->aDb[i];
if( pDb->pBt==0 ){
sqlite3_free(pDb->zName);
sqlite3DbFree(db, pDb->zName);
pDb->zName = 0;
continue;
}
@ -466,7 +461,7 @@ void sqlite3ResetInternalSchema(sqlite3 *db, int iDb){
db->nDb = j;
if( db->nDb<=2 && db->aDb!=db->aDbStatic ){
memcpy(db->aDbStatic, db->aDb, 2*sizeof(db->aDb[0]));
sqlite3_free(db->aDb);
sqlite3DbFree(db, db->aDb);
db->aDb = db->aDbStatic;
}
}
@ -484,15 +479,16 @@ void sqlite3CommitInternalChanges(sqlite3 *db){
static void sqliteResetColumnNames(Table *pTable){
int i;
Column *pCol;
sqlite3 *db = pTable->db;
assert( pTable!=0 );
if( (pCol = pTable->aCol)!=0 ){
for(i=0; i<pTable->nCol; i++, pCol++){
sqlite3_free(pCol->zName);
sqlite3ExprDelete(pCol->pDflt);
sqlite3_free(pCol->zType);
sqlite3_free(pCol->zColl);
sqlite3DbFree(db, pCol->zName);
sqlite3ExprDelete(db, pCol->pDflt);
sqlite3DbFree(db, pCol->zType);
sqlite3DbFree(db, pCol->zColl);
}
sqlite3_free(pTable->aCol);
sqlite3DbFree(db, pTable->aCol);
}
pTable->aCol = 0;
pTable->nCol = 0;
@ -511,8 +507,10 @@ static void sqliteResetColumnNames(Table *pTable){
void sqlite3DeleteTable(Table *pTable){
Index *pIndex, *pNext;
FKey *pFKey, *pNextFKey;
sqlite3 *db;
if( pTable==0 ) return;
db = pTable->db;
/* Do not delete the table until the reference count reaches zero. */
pTable->nRef--;
@ -537,21 +535,21 @@ void sqlite3DeleteTable(Table *pTable){
pNextFKey = pFKey->pNextFrom;
assert( sqlite3HashFind(&pTable->pSchema->aFKey,
pFKey->zTo, strlen(pFKey->zTo)+1)!=pFKey );
sqlite3_free(pFKey);
sqlite3DbFree(db, pFKey);
}
#endif
/* Delete the Table structure itself.
*/
sqliteResetColumnNames(pTable);
sqlite3_free(pTable->zName);
sqlite3_free(pTable->zColAff);
sqlite3SelectDelete(pTable->pSelect);
sqlite3DbFree(db, pTable->zName);
sqlite3DbFree(db, pTable->zColAff);
sqlite3SelectDelete(db, pTable->pSelect);
#ifndef SQLITE_OMIT_CHECK
sqlite3ExprDelete(pTable->pCheck);
sqlite3ExprDelete(db, pTable->pCheck);
#endif
sqlite3VtabClear(pTable);
sqlite3_free(pTable);
sqlite3DbFree(db, pTable);
}
/*
@ -641,7 +639,7 @@ int sqlite3FindDb(sqlite3 *db, Token *pName){
break;
}
}
sqlite3_free(zName);
sqlite3DbFree(db, zName);
}
return i;
}
@ -832,6 +830,7 @@ void sqlite3StartTable(
pTable->iPKey = -1;
pTable->pSchema = db->aDb[iDb].pSchema;
pTable->nRef = 1;
pTable->db = db;
if( pParse->pNewTable ) sqlite3DeleteTable(pParse->pNewTable);
pParse->pNewTable = pTable;
@ -911,7 +910,7 @@ void sqlite3StartTable(
/* If an error occurs, we jump here */
begin_table_error:
sqlite3_free(zName);
sqlite3DbFree(db, zName);
return;
}
@ -954,7 +953,7 @@ void sqlite3AddColumn(Parse *pParse, Token *pName){
for(i=0; i<p->nCol; i++){
if( STRICMP(z, p->aCol[i].zName) ){
sqlite3ErrorMsg(pParse, "duplicate column name: %s", z);
sqlite3_free(z);
sqlite3DbFree(db, z);
return;
}
}
@ -962,7 +961,7 @@ void sqlite3AddColumn(Parse *pParse, Token *pName){
Column *aNew;
aNew = sqlite3DbRealloc(pParse->db,p->aCol,(p->nCol+8)*sizeof(p->aCol[0]));
if( aNew==0 ){
sqlite3_free(z);
sqlite3DbFree(db, z);
return;
}
p->aCol = aNew;
@ -1069,13 +1068,15 @@ void sqlite3AddColumnType(Parse *pParse, Token *pType){
Table *p;
int i;
Column *pCol;
sqlite3 *db;
if( (p = pParse->pNewTable)==0 ) return;
i = p->nCol-1;
if( i<0 ) return;
pCol = &p->aCol[i];
sqlite3_free(pCol->zType);
pCol->zType = sqlite3NameFromToken(pParse->db, pType);
db = pParse->db;
sqlite3DbFree(db, pCol->zType);
pCol->zType = sqlite3NameFromToken(db, pType);
pCol->affinity = sqlite3AffinityType(pType);
}
@ -1092,6 +1093,7 @@ void sqlite3AddColumnType(Parse *pParse, Token *pType){
void sqlite3AddDefaultValue(Parse *pParse, Expr *pExpr){
Table *p;
Column *pCol;
sqlite3 *db = pParse->db;
if( (p = pParse->pNewTable)!=0 ){
pCol = &(p->aCol[p->nCol-1]);
if( !sqlite3ExprIsConstantOrFunction(pExpr) ){
@ -1099,15 +1101,14 @@ void sqlite3AddDefaultValue(Parse *pParse, Expr *pExpr){
pCol->zName);
}else{
Expr *pCopy;
sqlite3 *db = pParse->db;
sqlite3ExprDelete(pCol->pDflt);
sqlite3ExprDelete(db, pCol->pDflt);
pCol->pDflt = pCopy = sqlite3ExprDup(db, pExpr);
if( pCopy ){
sqlite3TokenCopy(db, &pCopy->span, &pExpr->span);
}
}
}
sqlite3ExprDelete(pExpr);
sqlite3ExprDelete(db, pExpr);
}
/*
@ -1180,7 +1181,7 @@ void sqlite3AddPrimaryKey(
}
primary_key_exit:
sqlite3ExprListDelete(pList);
sqlite3ExprListDelete(pParse->db, pList);
return;
}
@ -1191,9 +1192,9 @@ void sqlite3AddCheckConstraint(
Parse *pParse, /* Parsing context */
Expr *pCheckExpr /* The check expression */
){
sqlite3 *db = pParse->db;
#ifndef SQLITE_OMIT_CHECK
Table *pTab = pParse->pNewTable;
sqlite3 *db = pParse->db;
if( pTab && !IN_DECLARE_VTAB ){
/* The CHECK expression must be duplicated so that tokens refer
** to malloced space and not the (ephemeral) text of the CREATE TABLE
@ -1202,7 +1203,7 @@ void sqlite3AddCheckConstraint(
sqlite3ExprDup(db, pCheckExpr));
}
#endif
sqlite3ExprDelete(pCheckExpr);
sqlite3ExprDelete(db, pCheckExpr);
}
/*
@ -1213,11 +1214,12 @@ void sqlite3AddCollateType(Parse *pParse, Token *pToken){
Table *p;
int i;
char *zColl; /* Dequoted name of collation sequence */
sqlite3 *db;
if( (p = pParse->pNewTable)==0 ) return;
i = p->nCol-1;
zColl = sqlite3NameFromToken(pParse->db, pToken);
db = pParse->db;
zColl = sqlite3NameFromToken(db, pToken);
if( !zColl ) return;
if( sqlite3LocateCollSeq(pParse, zColl, -1) ){
@ -1235,7 +1237,7 @@ void sqlite3AddCollateType(Parse *pParse, Token *pToken){
}
}
}else{
sqlite3_free(zColl);
sqlite3DbFree(db, zColl);
}
}
@ -1522,6 +1524,7 @@ void sqlite3EndTable(
SelectDest dest;
Table *pSelTab;
assert(pParse->nTab==0);
sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, pParse->regRoot, iDb);
sqlite3VdbeChangeP5(v, 1);
pParse->nTab = 2;
@ -1568,7 +1571,7 @@ void sqlite3EndTable(
zStmt,
pParse->regRowid
);
sqlite3_free(zStmt);
sqlite3DbFree(db, zStmt);
sqlite3ChangeCookie(pParse, iDb);
#ifndef SQLITE_OMIT_AUTOINCREMENT
@ -1658,13 +1661,13 @@ void sqlite3CreateView(
if( pParse->nVar>0 ){
sqlite3ErrorMsg(pParse, "parameters are not allowed in views");
sqlite3SelectDelete(pSelect);
sqlite3SelectDelete(db, pSelect);
return;
}
sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0, noErr);
p = pParse->pNewTable;
if( p==0 || pParse->nErr ){
sqlite3SelectDelete(pSelect);
sqlite3SelectDelete(db, pSelect);
return;
}
sqlite3TwoPartName(pParse, pName1, pName2, &pName);
@ -1672,7 +1675,7 @@ void sqlite3CreateView(
if( sqlite3FixInit(&sFix, pParse, iDb, "view", pName)
&& sqlite3FixSelect(&sFix, pSelect)
){
sqlite3SelectDelete(pSelect);
sqlite3SelectDelete(db, pSelect);
return;
}
@ -1682,7 +1685,7 @@ void sqlite3CreateView(
** they will persist after the current sqlite3_exec() call returns.
*/
p->pSelect = sqlite3SelectDup(db, pSelect);
sqlite3SelectDelete(pSelect);
sqlite3SelectDelete(db, pSelect);
if( db->mallocFailed ){
return;
}
@ -1789,7 +1792,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
pTable->nCol = 0;
nErr++;
}
sqlite3SelectDelete(pSel);
sqlite3SelectDelete(db, pSel);
} else {
nErr++;
}
@ -2105,7 +2108,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
sqliteViewResetAll(db, iDb);
exit_drop_table:
sqlite3SrcListDelete(pName);
sqlite3SrcListDelete(db, pName);
}
/*
@ -2140,8 +2143,10 @@ void sqlite3CreateForeignKey(
int i;
int nCol;
char *z;
sqlite3 *db;
assert( pTo!=0 );
db = pParse->db;
if( p==0 || pParse->nErr || IN_DECLARE_VTAB ) goto fk_end;
if( pFromCol==0 ){
int iCol = p->nCol-1;
@ -2167,7 +2172,7 @@ void sqlite3CreateForeignKey(
nByte += strlen(pToCol->a[i].zName) + 1;
}
}
pFKey = sqlite3DbMallocZero(pParse->db, nByte );
pFKey = sqlite3DbMallocZero(db, nByte );
if( pFKey==0 ){
goto fk_end;
}
@ -2221,10 +2226,10 @@ void sqlite3CreateForeignKey(
pFKey = 0;
fk_end:
sqlite3_free(pFKey);
sqlite3DbFree(db, pFKey);
#endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */
sqlite3ExprListDelete(pFromCol);
sqlite3ExprListDelete(pToCol);
sqlite3ExprListDelete(db, pFromCol);
sqlite3ExprListDelete(db, pToCol);
}
/*
@ -2711,7 +2716,7 @@ void sqlite3CreateIndex(
iMem,
zStmt
);
sqlite3_free(zStmt);
sqlite3DbFree(db, zStmt);
/* Fill the index with data and reparse the schema. Code an OP_Expire
** to invalidate all pre-compiled statements.
@ -2751,9 +2756,9 @@ exit_create_index:
if( pIndex ){
freeIndex(pIndex);
}
sqlite3ExprListDelete(pList);
sqlite3SrcListDelete(pTblName);
sqlite3_free(zName);
sqlite3ExprListDelete(db, pList);
sqlite3SrcListDelete(db, pTblName);
sqlite3DbFree(db, zName);
return;
}
@ -2882,7 +2887,7 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){
}
exit_drop_index:
sqlite3SrcListDelete(pName);
sqlite3SrcListDelete(db, pName);
}
/*
@ -2952,7 +2957,7 @@ IdList *sqlite3IdListAppend(sqlite3 *db, IdList *pList, Token *pToken){
&i
);
if( i<0 ){
sqlite3IdListDelete(pList);
sqlite3IdListDelete(db, pList);
return 0;
}
pList->a[i].zName = sqlite3NameFromToken(db, pToken);
@ -2962,14 +2967,14 @@ IdList *sqlite3IdListAppend(sqlite3 *db, IdList *pList, Token *pToken){
/*
** Delete an IdList.
*/
void sqlite3IdListDelete(IdList *pList){
void sqlite3IdListDelete(sqlite3 *db, IdList *pList){
int i;
if( pList==0 ) return;
for(i=0; i<pList->nId; i++){
sqlite3_free(pList->a[i].zName);
sqlite3DbFree(db, pList->a[i].zName);
}
sqlite3_free(pList->a);
sqlite3_free(pList);
sqlite3DbFree(db, pList->a);
sqlite3DbFree(db, pList);
}
/*
@ -3028,7 +3033,7 @@ SrcList *sqlite3SrcListAppend(
pNew = sqlite3DbRealloc(db, pList,
sizeof(*pList) + (pList->nAlloc-1)*sizeof(pList->a[0]) );
if( pNew==0 ){
sqlite3SrcListDelete(pList);
sqlite3SrcListDelete(db, pList);
return 0;
}
pList = pNew;
@ -3072,20 +3077,20 @@ void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){
/*
** Delete an entire SrcList including all its substructure.
*/
void sqlite3SrcListDelete(SrcList *pList){
void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
int i;
struct SrcList_item *pItem;
if( pList==0 ) return;
for(pItem=pList->a, i=0; i<pList->nSrc; i++, pItem++){
sqlite3_free(pItem->zDatabase);
sqlite3_free(pItem->zName);
sqlite3_free(pItem->zAlias);
sqlite3DbFree(db, pItem->zDatabase);
sqlite3DbFree(db, pItem->zName);
sqlite3DbFree(db, pItem->zAlias);
sqlite3DeleteTable(pItem->pTab);
sqlite3SelectDelete(pItem->pSelect);
sqlite3ExprDelete(pItem->pOn);
sqlite3IdListDelete(pItem->pUsing);
sqlite3SelectDelete(db, pItem->pSelect);
sqlite3ExprDelete(db, pItem->pOn);
sqlite3IdListDelete(db, pItem->pUsing);
}
sqlite3_free(pList);
sqlite3DbFree(db, pList);
}
/*
@ -3118,9 +3123,9 @@ SrcList *sqlite3SrcListAppendFromTerm(
sqlite3 *db = pParse->db;
p = sqlite3SrcListAppend(db, p, pTable, pDatabase);
if( p==0 || p->nSrc==0 ){
sqlite3ExprDelete(pOn);
sqlite3IdListDelete(pUsing);
sqlite3SelectDelete(pSubquery);
sqlite3ExprDelete(db, pOn);
sqlite3IdListDelete(db, pUsing);
sqlite3SelectDelete(db, pSubquery);
return p;
}
pItem = &p->a[p->nSrc-1];
@ -3425,11 +3430,11 @@ void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
if( pColl ){
if( zColl ){
reindexDatabases(pParse, zColl);
sqlite3_free(zColl);
sqlite3DbFree(db, zColl);
}
return;
}
sqlite3_free(zColl);
sqlite3DbFree(db, zColl);
}
iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pObjName);
if( iDb<0 ) return;
@ -3439,11 +3444,11 @@ void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
pTab = sqlite3FindTable(db, z, zDb);
if( pTab ){
reindexTable(pParse, pTab, 0);
sqlite3_free(z);
sqlite3DbFree(db, z);
return;
}
pIndex = sqlite3FindIndex(db, z, zDb);
sqlite3_free(z);
sqlite3DbFree(db, z);
if( pIndex ){
sqlite3BeginWriteOperation(pParse, 0, iDb);
sqlite3RefillIndex(pParse, pIndex, -1);
@ -3458,7 +3463,7 @@ void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
** with OP_OpenRead or OP_OpenWrite to access database index pIdx.
**
** If successful, a pointer to the new structure is returned. In this case
** the caller is responsible for calling sqlite3_free() on the returned
** the caller is responsible for calling sqlite3DbFree(db, ) on the returned
** pointer. If an error occurs (out of memory or missing collation
** sequence), NULL is returned and the state of pParse updated to reflect
** the error.
@ -3467,7 +3472,8 @@ KeyInfo *sqlite3IndexKeyinfo(Parse *pParse, Index *pIdx){
int i;
int nCol = pIdx->nColumn;
int nBytes = sizeof(KeyInfo) + (nCol-1)*sizeof(CollSeq*) + nCol;
KeyInfo *pKey = (KeyInfo *)sqlite3DbMallocZero(pParse->db, nBytes);
sqlite3 *db = pParse->db;
KeyInfo *pKey = (KeyInfo *)sqlite3DbMallocZero(db, nBytes);
if( pKey ){
pKey->db = pParse->db;
@ -3483,7 +3489,7 @@ KeyInfo *sqlite3IndexKeyinfo(Parse *pParse, Index *pIdx){
}
if( pParse->nErr ){
sqlite3_free(pKey);
sqlite3DbFree(db, pKey);
pKey = 0;
}
return pKey;

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.25 2008/07/08 14:52:10 drh Exp $
** $Id: callback.c,v 1.26 2008/07/28 19:34:53 drh Exp $
*/
#include "sqliteInt.h"
@ -30,7 +30,7 @@ static void callCollNeeded(sqlite3 *db, const char *zName, int nName){
char *zExternal = sqlite3DbStrNDup(db, zName, nName);
if( !zExternal ) return;
db->xCollNeeded(db->pCollNeededArg, db, (int)ENC(db), zExternal);
sqlite3_free(zExternal);
sqlite3DbFree(db, zExternal);
}
#ifndef SQLITE_OMIT_UTF16
if( db->xCollNeeded16 ){
@ -182,7 +182,7 @@ static CollSeq *findCollSeqEntry(
assert( pDel==0 || pDel==pColl );
if( pDel!=0 ){
db->mallocFailed = 1;
sqlite3_free(pDel);
sqlite3DbFree(db, pDel);
pColl = 0;
}
}
@ -312,7 +312,7 @@ FuncDef *sqlite3FindFunction(
pBest->zName[nName] = 0;
if( pBest==sqlite3HashInsert(&db->aFunc,pBest->zName,nName,(void*)pBest) ){
db->mallocFailed = 1;
sqlite3_free(pBest);
sqlite3DbFree(db, pBest);
return 0;
}
}
@ -325,7 +325,7 @@ FuncDef *sqlite3FindFunction(
/*
** Free all resources held by the schema structure. The void* argument points
** at a Schema struct. This function does not call sqlite3_free() on the
** at a Schema struct. This function does not call sqlite3DbFree(db, ) on the
** pointer itself, it just cleans up subsiduary resources (i.e. the contents
** of the schema hash tables).
**
@ -343,7 +343,7 @@ void sqlite3SchemaFree(void *p){
sqlite3HashClear(&pSchema->aFKey);
sqlite3HashClear(&pSchema->idxHash);
for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){
sqlite3DeleteTrigger((Trigger*)sqliteHashData(pElem));
sqlite3DeleteTrigger(0, (Trigger*)sqliteHashData(pElem));
}
sqlite3HashClear(&temp2);
sqlite3HashInit(&pSchema->tblHash, SQLITE_HASH_STRING, 0);

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.85 2008/06/18 17:09:10 danielk1977 Exp $
** $Id: date.c,v 1.87 2008/07/28 19:34:53 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
@ -553,7 +553,9 @@ static int parseModifier(const char *zMod, DateTime *p){
p->iJD = p->iJD/86400.0 + 2440587.5*86400000.0;
clearYMD_HMS_TZ(p);
rc = 0;
}else if( strcmp(z, "utc")==0 ){
}
#ifndef SQLITE_OMIT_LOCALTIME
else if( strcmp(z, "utc")==0 ){
double c1;
computeJD(p);
c1 = localtimeOffset(p);
@ -562,6 +564,7 @@ static int parseModifier(const char *zMod, DateTime *p){
p->iJD += c1 - localtimeOffset(p);
rc = 0;
}
#endif
break;
}
case 'w': {
@ -846,9 +849,11 @@ static void strftimeFunc(
u64 n;
int i, j;
char *z;
sqlite3 *db;
const char *zFmt = (const char*)sqlite3_value_text(argv[0]);
char zBuf[100];
if( zFmt==0 || isDate(context, argc-1, argv+1, &x) ) return;
db = sqlite3_context_db_handle(context);
for(i=0, n=1; zFmt[i]; i++, n++){
if( zFmt[i]=='%' ){
switch( zFmt[i+1] ){
@ -884,11 +889,11 @@ static void strftimeFunc(
}
if( n<sizeof(zBuf) ){
z = zBuf;
}else if( n>sqlite3_context_db_handle(context)->aLimit[SQLITE_LIMIT_LENGTH] ){
}else if( n>db->aLimit[SQLITE_LIMIT_LENGTH] ){
sqlite3_result_error_toobig(context);
return;
}else{
z = sqlite3Malloc( n );
z = sqlite3DbMallocRaw(db, n);
if( z==0 ){
sqlite3_result_error_nomem(context);
return;
@ -953,7 +958,7 @@ static void strftimeFunc(
}
z[j] = 0;
sqlite3_result_text(context, z, -1,
z==zBuf ? SQLITE_TRANSIENT : sqlite3_free);
z==zBuf ? SQLITE_TRANSIENT : SQLITE_DYNAMIC);
}
/*

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.170 2008/07/08 23:40:20 drh Exp $
** $Id: delete.c,v 1.171 2008/07/28 19:34:53 drh Exp $
*/
#include "sqliteInt.h"
@ -107,7 +107,7 @@ void sqlite3MaterializeView(
}
sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur);
sqlite3Select(pParse, pDup, &dest, 0, 0, 0);
sqlite3SelectDelete(pDup);
sqlite3SelectDelete(db, pDup);
}
#endif /* !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) */
@ -415,8 +415,8 @@ void sqlite3DeleteFrom(
delete_from_cleanup:
sqlite3AuthContextPop(&sContext);
sqlite3SrcListDelete(pTabList);
sqlite3ExprDelete(pWhere);
sqlite3SrcListDelete(db, pTabList);
sqlite3ExprDelete(db, pWhere);
return;
}

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.385 2008/07/09 01:39:44 drh Exp $
** $Id: expr.c,v 1.387 2008/07/28 19:34:53 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@ -56,7 +56,8 @@ char sqlite3ExprAffinity(Expr *pExpr){
Expr *sqlite3ExprSetColl(Parse *pParse, Expr *pExpr, Token *pName){
char *zColl = 0; /* Dequoted name of collation sequence */
CollSeq *pColl;
zColl = sqlite3NameFromToken(pParse->db, pName);
sqlite3 *db = pParse->db;
zColl = sqlite3NameFromToken(db, pName);
if( pExpr && zColl ){
pColl = sqlite3LocateCollSeq(pParse, zColl, -1);
if( pColl ){
@ -64,7 +65,7 @@ Expr *sqlite3ExprSetColl(Parse *pParse, Expr *pExpr, Token *pName){
pExpr->flags |= EP_ExpCollate;
}
}
sqlite3_free(zColl);
sqlite3DbFree(db, zColl);
return pExpr;
}
@ -367,8 +368,8 @@ Expr *sqlite3Expr(
** this function must always be allocated with sqlite3Expr() for this
** reason.
*/
sqlite3ExprDelete(pLeft);
sqlite3ExprDelete(pRight);
sqlite3ExprDelete(db, pLeft);
sqlite3ExprDelete(db, pRight);
return 0;
}
pNew->op = op;
@ -465,7 +466,7 @@ Expr *sqlite3ExprAnd(sqlite3 *db, Expr *pLeft, Expr *pRight){
void sqlite3ExprSpan(Expr *pExpr, Token *pLeft, Token *pRight){
assert( pRight!=0 );
assert( pLeft!=0 );
if( pExpr && pRight->z && pLeft->z ){
if( pExpr ){
pExpr->span.z = pLeft->z;
pExpr->span.n = pRight->n + (pRight->z - pLeft->z);
}
@ -477,10 +478,11 @@ void sqlite3ExprSpan(Expr *pExpr, Token *pLeft, Token *pRight){
*/
Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token *pToken){
Expr *pNew;
sqlite3 *db = pParse->db;
assert( pToken );
pNew = sqlite3DbMallocZero(pParse->db, sizeof(Expr) );
pNew = sqlite3DbMallocZero(db, sizeof(Expr) );
if( pNew==0 ){
sqlite3ExprListDelete(pList); /* Avoid leaking memory when malloc fails */
sqlite3ExprListDelete(db, pList); /* Avoid leaking memory when malloc fails */
return 0;
}
pNew->op = TK_FUNCTION;
@ -578,15 +580,15 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
/*
** Recursively delete an expression tree.
*/
void sqlite3ExprDelete(Expr *p){
void sqlite3ExprDelete(sqlite3 *db, Expr *p){
if( p==0 ) return;
if( p->span.dyn ) sqlite3_free((char*)p->span.z);
if( p->token.dyn ) sqlite3_free((char*)p->token.z);
sqlite3ExprDelete(p->pLeft);
sqlite3ExprDelete(p->pRight);
sqlite3ExprListDelete(p->pList);
sqlite3SelectDelete(p->pSelect);
sqlite3_free(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);
sqlite3DbFree(db, p);
}
/*
@ -637,7 +639,7 @@ Expr *sqlite3ExprDup(sqlite3 *db, Expr *p){
return pNew;
}
void sqlite3TokenCopy(sqlite3 *db, Token *pTo, Token *pFrom){
if( pTo->dyn ) sqlite3_free((char*)pTo->z);
if( pTo->dyn ) sqlite3DbFree(db, (char*)pTo->z);
if( pFrom->z ){
pTo->n = pFrom->n;
pTo->z = (u8*)sqlite3DbStrNDup(db, (char*)pFrom->z, pFrom->n);
@ -657,7 +659,7 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p){
pNew->nExpr = pNew->nAlloc = p->nExpr;
pNew->a = pItem = sqlite3DbMallocRaw(db, p->nExpr*sizeof(p->a[0]) );
if( pItem==0 ){
sqlite3_free(pNew);
sqlite3DbFree(db, pNew);
return 0;
}
pOldItem = p->a;
@ -728,7 +730,7 @@ IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){
pNew->nId = pNew->nAlloc = p->nId;
pNew->a = sqlite3DbMallocRaw(db, p->nId*sizeof(p->a[0]) );
if( pNew->a==0 ){
sqlite3_free(pNew);
sqlite3DbFree(db, pNew);
return 0;
}
for(i=0; i<p->nId; i++){
@ -814,8 +816,8 @@ ExprList *sqlite3ExprListAppend(
no_mem:
/* Avoid leaking memory if malloc has failed. */
sqlite3ExprDelete(pExpr);
sqlite3ExprListDelete(pList);
sqlite3ExprDelete(db, pExpr);
sqlite3ExprListDelete(db, pList);
return 0;
}
@ -839,18 +841,18 @@ void sqlite3ExprListCheckLength(
/*
** Delete an entire expression list.
*/
void sqlite3ExprListDelete(ExprList *pList){
void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
int i;
struct ExprList_item *pItem;
if( pList==0 ) return;
assert( pList->a!=0 || (pList->nExpr==0 && pList->nAlloc==0) );
assert( pList->nExpr<=pList->nAlloc );
for(pItem=pList->a, i=0; i<pList->nExpr; i++, pItem++){
sqlite3ExprDelete(pItem->pExpr);
sqlite3_free(pItem->zName);
sqlite3ExprDelete(db, pItem->pExpr);
sqlite3DbFree(db, pItem->zName);
}
sqlite3_free(pList->a);
sqlite3_free(pList);
sqlite3DbFree(db, pList->a);
sqlite3DbFree(db, pList);
}
/*
@ -1264,7 +1266,7 @@ static int lookupName(
pOrig = pEList->a[j].pExpr;
if( !pNC->allowAgg && ExprHasProperty(pOrig, EP_Agg) ){
sqlite3ErrorMsg(pParse, "misuse of aliased aggregate %s", zAs);
sqlite3_free(zCol);
sqlite3DbFree(db, zCol);
return 2;
}
pDup = sqlite3ExprDup(db, pOrig);
@ -1272,10 +1274,10 @@ static int lookupName(
pDup->pColl = pExpr->pColl;
pDup->flags |= EP_ExpCollate;
}
if( pExpr->span.dyn ) sqlite3_free((char*)pExpr->span.z);
if( pExpr->token.dyn ) sqlite3_free((char*)pExpr->token.z);
if( pExpr->span.dyn ) sqlite3DbFree(db, (char*)pExpr->span.z);
if( pExpr->token.dyn ) sqlite3DbFree(db, (char*)pExpr->token.z);
memcpy(pExpr, pDup, sizeof(*pExpr));
sqlite3_free(pDup);
sqlite3DbFree(db, pDup);
cnt = 1;
pMatch = 0;
assert( zTab==0 && zDb==0 );
@ -1303,7 +1305,7 @@ static int lookupName(
** fields are not changed in any context.
*/
if( cnt==0 && zTab==0 && pColumnToken->z[0]=='"' ){
sqlite3_free(zCol);
sqlite3DbFree(db, zCol);
return 0;
}
@ -1343,15 +1345,15 @@ static int lookupName(
lookupname_end:
/* Clean up and return
*/
sqlite3_free(zDb);
sqlite3_free(zTab);
sqlite3ExprDelete(pExpr->pLeft);
sqlite3DbFree(db, zDb);
sqlite3DbFree(db, zTab);
sqlite3ExprDelete(db, pExpr->pLeft);
pExpr->pLeft = 0;
sqlite3ExprDelete(pExpr->pRight);
sqlite3ExprDelete(db, pExpr->pRight);
pExpr->pRight = 0;
pExpr->op = TK_COLUMN;
lookupname_end_2:
sqlite3_free(zCol);
sqlite3DbFree(db, zCol);
if( cnt==1 ){
assert( pNC!=0 );
sqlite3AuthRead(pParse, pExpr, pSchema, pNC->pSrcList);
@ -1966,7 +1968,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr, int rMayHaveNull){
sqlite3VdbeAddOp2(v, OP_Integer, 0, dest.iParm);
VdbeComment((v, "Init EXISTS result"));
}
sqlite3ExprDelete(pSel->pLimit);
sqlite3ExprDelete(pParse->db, pSel->pLimit);
pSel->pLimit = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &one);
if( sqlite3Select(pParse, pSel, &dest, 0, 0, 0) ){
return;

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.195 2008/07/08 22:28:49 shane Exp $
** $Id: func.c,v 1.196 2008/07/28 19:34:53 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@ -832,14 +832,14 @@ static void replaceFunc(
nOut += nRep - nPattern;
if( nOut>=db->aLimit[SQLITE_LIMIT_LENGTH] ){
sqlite3_result_error_toobig(context);
sqlite3_free(zOut);
sqlite3DbFree(db, zOut);
return;
}
zOld = zOut;
zOut = sqlite3_realloc(zOut, (int)nOut);
if( zOut==0 ){
sqlite3_result_error_nomem(context);
sqlite3_free(zOld);
sqlite3DbFree(db, zOld);
return;
}
memcpy(&zOut[j], zRep, nRep);

View File

@ -12,7 +12,7 @@
**
** This file contains definitions of global variables and contants.
**
** $Id: global.c,v 1.3 2008/07/08 14:52:10 drh Exp $
** $Id: global.c,v 1.4 2008/07/28 19:34:53 drh Exp $
*/
#include "sqliteInt.h"
@ -66,4 +66,12 @@ const unsigned char sqlite3UpperToLower[] = {
** The following singleton contains the global configuration for
** the SQLite library.
*/
struct Sqlite3Config sqlite3Config = { 1, 1, 1, 0x7ffffffe };
struct Sqlite3Config sqlite3Config = {
1, /* bMemstat */
1, /* bCoreMutex */
1, /* bFullMutex */
0x7ffffffe, /* mxStrlen */
100, /* szLookaside */
500, /* nLookaside */
/* Other fields all default to zero */
};

View File

@ -13,7 +13,7 @@
** This file contains inline asm code for retrieving "high-performance"
** counters for x86 class CPUs.
**
** $Id: hwtime.h,v 1.2 2008/06/12 02:24:39 shane Exp $
** $Id: hwtime.h,v 1.3 2008/08/01 14:33:15 shane Exp $
*/
#ifndef _HWTIME_H_
#define _HWTIME_H_
@ -54,6 +54,21 @@
return val;
}
#elif (defined(__GNUC__) && defined(__ppc__))
__inline__ sqlite_uint64 sqlite3Hwtime(void){
unsigned long long retval;
unsigned long junk;
__asm__ __volatile__ ("\n\
1: mftbu %1\n\
mftb %L0\n\
mftbu %0\n\
cmpw %0,%1\n\
bne 1b"
: "=r" (retval), "=r" (junk));
return retval;
}
#else
#error Need implementation of sqlite3Hwtime() for your platform.

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.247 2008/07/08 23:40:20 drh Exp $
** $Id: insert.c,v 1.248 2008/07/28 19:34:53 drh Exp $
*/
#include "sqliteInt.h"
@ -45,8 +45,9 @@ void sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
int n;
Table *pTab = pIdx->pTable;
sqlite3 *db = sqlite3VdbeDb(v);
pIdx->zColAff = (char *)sqlite3DbMallocRaw(db, pIdx->nColumn+2);
pIdx->zColAff = (char *)sqlite3Malloc(pIdx->nColumn+2);
if( !pIdx->zColAff ){
db->mallocFailed = 1;
return;
}
for(n=0; n<pIdx->nColumn; n++){
@ -86,8 +87,9 @@ void sqlite3TableAffinityStr(Vdbe *v, Table *pTab){
int i;
sqlite3 *db = sqlite3VdbeDb(v);
zColAff = (char *)sqlite3DbMallocRaw(db, pTab->nCol+1);
zColAff = (char *)sqlite3Malloc(pTab->nCol+1);
if( !zColAff ){
db->mallocFailed = 1;
return;
}
@ -994,11 +996,11 @@ void sqlite3Insert(
}
insert_cleanup:
sqlite3SrcListDelete(pTabList);
sqlite3ExprListDelete(pList);
sqlite3SelectDelete(pSelect);
sqlite3IdListDelete(pColumn);
sqlite3_free(aRegIdx);
sqlite3SrcListDelete(db, pTabList);
sqlite3ExprListDelete(db, pList);
sqlite3SelectDelete(db, pSelect);
sqlite3IdListDelete(db, pColumn);
sqlite3DbFree(db, aRegIdx);
}
/*

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.27 2008/06/15 02:51:47 drh Exp $
** $Id: legacy.c,v 1.29 2008/08/02 03:50:39 drh Exp $
*/
#include "sqliteInt.h"
@ -84,10 +84,9 @@ int sqlite3_exec(
}
for(i=0; i<nCol; i++){
azCols[i] = (char *)sqlite3_column_name(pStmt, i);
if( !azCols[i] ){
db->mallocFailed = 1;
goto exec_out;
}
/* sqlite3VdbeSetColName() installs column names as UTF8
** strings so there is no way for sqlite3_column_name() to fail. */
assert( azCols[i]!=0 );
}
nCallback++;
}
@ -122,13 +121,13 @@ int sqlite3_exec(
}
}
sqlite3_free(azCols);
sqlite3DbFree(db, azCols);
azCols = 0;
}
exec_out:
if( pStmt ) sqlite3_finalize(pStmt);
if( azCols ) sqlite3_free(azCols);
sqlite3DbFree(db, azCols);
rc = sqlite3ApiExit(db, rc);
if( rc!=SQLITE_OK && rc==sqlite3_errcode(db) && pzErrMsg ){

View File

@ -12,7 +12,7 @@
** This file contains code used to dynamically load extensions into
** the SQLite library.
**
** $Id: loadext.c,v 1.51 2008/07/08 14:17:35 danielk1977 Exp $
** $Id: loadext.c,v 1.53 2008/08/02 03:50:39 drh Exp $
*/
#ifndef SQLITE_CORE
@ -326,7 +326,7 @@ static const sqlite3_api_routines sqlite3Apis = {
**
** If an error occurs and pzErrMsg is not 0, then fill *pzErrMsg with
** error message text. The calling function should free this memory
** by calling sqlite3_free().
** by calling sqlite3DbFree(db, ).
*/
static int sqlite3LoadExtension(
sqlite3 *db, /* Load the extension into this database connection */
@ -365,7 +365,7 @@ static int sqlite3LoadExtension(
sqlite3_snprintf(sizeof(zErr)-1, zErr,
"unable to open shared library [%s]", zFile);
sqlite3OsDlError(pVfs, sizeof(zErr)-1, zErr);
*pzErrMsg = sqlite3DbStrDup(db, zErr);
*pzErrMsg = sqlite3DbStrDup(0, zErr);
}
return SQLITE_ERROR;
}
@ -378,7 +378,7 @@ static int sqlite3LoadExtension(
sqlite3_snprintf(sizeof(zErr)-1, zErr,
"no entry point [%s] in shared library [%s]", zProc,zFile);
sqlite3OsDlError(pVfs, sizeof(zErr)-1, zErr);
*pzErrMsg = sqlite3DbStrDup(db, zErr);
*pzErrMsg = sqlite3DbStrDup(0, zErr);
sqlite3OsDlClose(pVfs, handle);
}
return SQLITE_ERROR;
@ -392,18 +392,17 @@ static int sqlite3LoadExtension(
}
/* Append the new shared library handle to the db->aExtension array. */
db->nExtension++;
aHandle = sqlite3DbMallocZero(db, sizeof(handle)*db->nExtension);
aHandle = sqlite3DbMallocZero(db, sizeof(handle)*(db->nExtension+1));
if( aHandle==0 ){
return SQLITE_NOMEM;
}
if( db->nExtension>0 ){
memcpy(aHandle, db->aExtension, sizeof(handle)*(db->nExtension-1));
memcpy(aHandle, db->aExtension, sizeof(handle)*db->nExtension);
}
sqlite3_free(db->aExtension);
sqlite3DbFree(db, db->aExtension);
db->aExtension = aHandle;
db->aExtension[db->nExtension-1] = handle;
db->aExtension[db->nExtension++] = handle;
return SQLITE_OK;
}
int sqlite3_load_extension(
@ -429,7 +428,7 @@ void sqlite3CloseExtensions(sqlite3 *db){
for(i=0; i<db->nExtension; i++){
sqlite3OsDlClose(db->pVfs, db->aExtension[i]);
}
sqlite3_free(db->aExtension);
sqlite3DbFree(db, db->aExtension);
}
/*

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.479 2008/07/16 14:02:33 drh Exp $
** $Id: main.c,v 1.486 2008/08/04 20:13:27 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@ -117,6 +117,20 @@ int sqlite3_initialize(void){
sqlite3Config.isInit = (rc==SQLITE_OK ? 1 : 0);
sqlite3_mutex_leave(sqlite3Config.pInitMutex);
}
/* Check NaN support. */
#ifndef NDEBUG
/* This section of code's only "output" is via assert() statements. */
if ( rc==SQLITE_OK ){
u64 x = (((u64)1)<<63)-1;
double y;
assert(sizeof(x)==8);
assert(sizeof(x)==sizeof(y));
memcpy(&y, &x, 8);
assert( sqlite3IsNaN(y) );
}
#endif
return rc;
}
@ -253,6 +267,95 @@ int sqlite3_config(int op, ...){
}
#endif
#if defined(SQLITE_ENABLE_MEMSYS6)
case SQLITE_CONFIG_CHUNKALLOC: {
sqlite3Config.nSmall = va_arg(ap, int);
sqlite3Config.m = *sqlite3MemGetMemsys6();
break;
}
#endif
case SQLITE_CONFIG_LOOKASIDE: {
sqlite3Config.szLookaside = va_arg(ap, int);
sqlite3Config.nLookaside = va_arg(ap, int);
break;
}
default: {
rc = SQLITE_ERROR;
break;
}
}
va_end(ap);
return rc;
}
/*
** Set up the lookaside buffers for a database connection.
** Return SQLITE_OK on success.
** If lookaside is already active, return SQLITE_BUSY.
**
** The sz parameter is the number of bytes in each lookaside slot.
** The cnt parameter is the number of slots. If pStart is NULL the
** space for the lookaside memory is obtained from sqlite3_malloc().
** If pStart is not NULL then it is sz*cnt bytes of memory to use for
** the lookaside memory.
*/
static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
void *pStart;
if( db->lookaside.nOut ){
return SQLITE_BUSY;
}
if( sz<0 ) sz = 0;
if( cnt<0 ) cnt = 0;
sz = (sz+7)&~7;
if( pBuf==0 ){
sqlite3BeginBenignMalloc();
pStart = sqlite3Malloc( sz*cnt );
sqlite3EndBenignMalloc();
}else{
pStart = pBuf;
}
if( db->lookaside.bMalloced ){
sqlite3_free(db->lookaside.pStart);
}
db->lookaside.pStart = pStart;
db->lookaside.pFree = 0;
db->lookaside.sz = sz;
db->lookaside.bMalloced = pBuf==0;
if( pStart ){
int i;
LookasideSlot *p;
p = (LookasideSlot*)pStart;
for(i=cnt-1; i>=0; i--){
p->pNext = db->lookaside.pFree;
db->lookaside.pFree = p;
p = (LookasideSlot*)&((u8*)p)[sz];
}
db->lookaside.pEnd = p;
db->lookaside.bEnabled = 1;
}else{
db->lookaside.pEnd = 0;
db->lookaside.bEnabled = 0;
}
return SQLITE_OK;
}
/*
** Configuration settings for an individual database connection
*/
int sqlite3_db_config(sqlite3 *db, int op, ...){
va_list ap;
int rc;
va_start(ap, op);
switch( op ){
case SQLITE_DBCONFIG_LOOKASIDE: {
void *pBuf = va_arg(ap, void*);
int sz = va_arg(ap, int);
int cnt = va_arg(ap, int);
rc = setupLookaside(db, pBuf, sz, cnt);
break;
}
default: {
rc = SQLITE_ERROR;
break;
@ -411,7 +514,7 @@ int sqlite3_close(sqlite3 *db){
FuncDef *pFunc, *pNext;
for(pFunc = (FuncDef*)sqliteHashData(i); pFunc; pFunc=pNext){
pNext = pFunc->pNext;
sqlite3_free(pFunc);
sqlite3DbFree(db, pFunc);
}
}
@ -423,7 +526,7 @@ int sqlite3_close(sqlite3 *db){
pColl[j].xDel(pColl[j].pUser);
}
}
sqlite3_free(pColl);
sqlite3DbFree(db, pColl);
}
sqlite3HashClear(&db->aCollSeq);
#ifndef SQLITE_OMIT_VIRTUALTABLE
@ -432,7 +535,7 @@ int sqlite3_close(sqlite3 *db){
if( pMod->xDestroy ){
pMod->xDestroy(pMod->pAux);
}
sqlite3_free(pMod);
sqlite3DbFree(db, pMod);
}
sqlite3HashClear(&db->aModule);
#endif
@ -452,10 +555,13 @@ int sqlite3_close(sqlite3 *db){
** the same sqliteMalloc() as the one that allocates the database
** structure?
*/
sqlite3_free(db->aDb[1].pSchema);
sqlite3DbFree(db, db->aDb[1].pSchema);
sqlite3_mutex_leave(db->mutex);
db->magic = SQLITE_MAGIC_CLOSED;
sqlite3_mutex_free(db->mutex);
if( db->lookaside.bMalloced ){
sqlite3_free(db->lookaside.pStart);
}
sqlite3_free(db);
return SQLITE_OK;
}
@ -785,7 +891,7 @@ int sqlite3_create_function16(
assert( !db->mallocFailed );
zFunc8 = sqlite3Utf16to8(db, zFunctionName, -1);
rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xFunc, xStep, xFinal);
sqlite3_free(zFunc8);
sqlite3DbFree(db, zFunc8);
rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
return rc;
@ -1290,6 +1396,7 @@ static int openDatabase(
db->nDb = 2;
db->magic = SQLITE_MAGIC_BUSY;
db->aDb = db->aDbStatic;
assert( sizeof(db->aLimit)==sizeof(aHardLimit) );
memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit));
db->autoCommit = 1;
@ -1431,6 +1538,9 @@ static int openDatabase(
SQLITE_DEFAULT_LOCKING_MODE);
#endif
/* Enable the lookaside-malloc subsystem */
setupLookaside(db, 0, sqlite3Config.szLookaside, sqlite3Config.nLookaside);
opendb_out:
if( db ){
assert( db->mutex!=0 || isThreadsafe==0 || sqlite3Config.bFullMutex==0 );
@ -1558,7 +1668,7 @@ int sqlite3_create_collation16(
zName8 = sqlite3Utf16to8(db, zName, -1);
if( zName8 ){
rc = createCollation(db, zName8, enc, pCtx, xCompare, 0);
sqlite3_free(zName8);
sqlite3DbFree(db, zName8);
}
rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
@ -1747,13 +1857,13 @@ error_out:
if( pAutoinc ) *pAutoinc = autoinc;
if( SQLITE_OK==rc && !pTab ){
sqlite3_free(zErrMsg);
sqlite3DbFree(db, zErrMsg);
zErrMsg = sqlite3MPrintf(db, "no such table column: %s.%s", zTableName,
zColumnName);
rc = SQLITE_ERROR;
}
sqlite3Error(db, rc, (zErrMsg?"%s":0), zErrMsg);
sqlite3_free(zErrMsg);
sqlite3DbFree(db, zErrMsg);
rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
return rc;

View File

@ -12,7 +12,7 @@
**
** Memory allocation functions used throughout sqlite.
**
** $Id: malloc.c,v 1.28 2008/07/14 12:38:21 drh Exp $
** $Id: malloc.c,v 1.34 2008/08/05 17:53:23 drh Exp $
*/
#include "sqliteInt.h"
#include <stdarg.h>
@ -112,9 +112,10 @@ int sqlite3MallocInit(void){
if( sqlite3Config.bCoreMutex ){
mem0.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
}
if( sqlite3Config.pScratch && sqlite3Config.szScratch>=3000
&& sqlite3Config.nScratch>0 ){
if( sqlite3Config.pScratch && sqlite3Config.szScratch>=100
&& sqlite3Config.nScratch>=0 ){
int i;
sqlite3Config.szScratch -= 4;
mem0.aScratchFree = (u32*)&((char*)sqlite3Config.pScratch)
[sqlite3Config.szScratch*sqlite3Config.nScratch];
for(i=0; i<sqlite3Config.nScratch; i++){ mem0.aScratchFree[i] = i; }
@ -124,8 +125,13 @@ int sqlite3MallocInit(void){
sqlite3Config.szScratch = 0;
}
if( sqlite3Config.pPage && sqlite3Config.szPage>=512
&& sqlite3Config.nPage>0 ){
&& sqlite3Config.nPage>=1 ){
int i;
int overhead;
int sz = sqlite3Config.szPage;
int n = sqlite3Config.nPage;
overhead = (4*n + sz - 1)/sz;
sqlite3Config.nPage -= overhead;
mem0.aPageFree = (u32*)&((char*)sqlite3Config.pPage)
[sqlite3Config.szPage*sqlite3Config.nPage];
for(i=0; i<sqlite3Config.nPage; i++){ mem0.aPageFree[i] = i; }
@ -224,7 +230,10 @@ static int mallocWithAlarm(int n, void **pp){
sqlite3MallocAlarm(nFull);
p = sqlite3Config.m.xMalloc(nFull);
}
if( p ) sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, nFull);
if( p ){
nFull = sqlite3MallocSize(p);
sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, nFull);
}
*pp = p;
return nFull;
}
@ -303,6 +312,7 @@ void *sqlite3ScratchMalloc(int n){
sqlite3_mutex_leave(mem0.mutex);
i *= sqlite3Config.szScratch;
sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_USED, 1);
sqlite3StatusSet(SQLITE_STATUS_SCRATCH_SIZE, n);
p = (void*)&((char*)sqlite3Config.pScratch)[i];
}
}
@ -315,6 +325,7 @@ void *sqlite3ScratchMalloc(int n){
scratch_overflow:
if( sqlite3Config.bMemstat ){
sqlite3_mutex_enter(mem0.mutex);
sqlite3StatusSet(SQLITE_STATUS_SCRATCH_SIZE, n);
n = mallocWithAlarm(n, &p);
if( p ) sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_OVERFLOW, n);
sqlite3_mutex_leave(mem0.mutex);
@ -389,6 +400,7 @@ void *sqlite3PageMalloc(int n){
i = mem0.aPageFree[--mem0.nPageFree];
sqlite3_mutex_leave(mem0.mutex);
i *= sqlite3Config.szPage;
sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, n);
sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, 1);
p = (void*)&((char*)sqlite3Config.pPage)[i];
}
@ -398,6 +410,7 @@ void *sqlite3PageMalloc(int n){
page_overflow:
if( sqlite3Config.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);
@ -440,7 +453,7 @@ void sqlite3PageFree(void *p){
mem0.aPageFree[mem0.nPageFree++] = i;
sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, -1);
sqlite3_mutex_leave(mem0.mutex);
#ifndef NDEBUG
#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] );
@ -450,6 +463,13 @@ void sqlite3PageFree(void *p){
}
}
/*
** TRUE if p is a lookaside memory allocation from db
*/
static int isLookaside(sqlite3 *db, void *p){
return db && p && p>=db->lookaside.pStart && p<db->lookaside.pEnd;
}
/*
** Return the size of a memory allocation previously obtained from
** sqlite3Malloc() or sqlite3_malloc().
@ -457,6 +477,13 @@ void sqlite3PageFree(void *p){
int sqlite3MallocSize(void *p){
return sqlite3Config.m.xSize(p);
}
int sqlite3DbMallocSize(sqlite3 *db, void *p){
if( isLookaside(db, p) ){
return db->lookaside.sz;
}else{
return sqlite3Config.m.xSize(p);
}
}
/*
** Free memory previously obtained from sqlite3Malloc().
@ -473,6 +500,21 @@ void sqlite3_free(void *p){
}
}
/*
** Free memory that might be associated with a particular database
** connection.
*/
void sqlite3DbFree(sqlite3 *db, void *p){
if( isLookaside(db, p) ){
LookasideSlot *pBuf = (LookasideSlot*)p;
pBuf->pNext = db->lookaside.pFree;
db->lookaside.pFree = pBuf;
db->lookaside.nOut--;
}else{
sqlite3_free(p);
}
}
/*
** Change the size of an existing memory allocation
*/
@ -504,6 +546,7 @@ void *sqlite3Realloc(void *pOld, int nBytes){
pNew = sqlite3Config.m.xRealloc(pOld, nNew);
}
if( pNew ){
nNew = sqlite3MallocSize(pNew);
sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, nNew-nOld);
}
}
@ -554,26 +597,53 @@ void *sqlite3DbMallocZero(sqlite3 *db, int n){
** the mallocFailed flag in the connection pointer.
*/
void *sqlite3DbMallocRaw(sqlite3 *db, int n){
void *p = 0;
if( !db || db->mallocFailed==0 ){
p = sqlite3Malloc(n);
if( !p && db ){
db->mallocFailed = 1;
void *p;
if( db ){
LookasideSlot *pBuf;
if( db->mallocFailed ){
return 0;
}
if( db->lookaside.bEnabled && n<=db->lookaside.sz
&& (pBuf = db->lookaside.pFree)!=0 ){
db->lookaside.pFree = pBuf->pNext;
db->lookaside.nOut++;
if( db->lookaside.nOut>db->lookaside.mxOut ){
db->lookaside.mxOut = db->lookaside.nOut;
}
return (void*)pBuf;
}
}
p = sqlite3Malloc(n);
if( !p && db ){
db->mallocFailed = 1;
}
return p;
}
/*
** Resize the block of memory pointed to by p to n bytes. If the
** resize fails, set the mallocFailed flag inthe connection object.
** resize fails, set the mallocFailed flag in the connection object.
*/
void *sqlite3DbRealloc(sqlite3 *db, void *p, int n){
void *pNew = 0;
if( db->mallocFailed==0 ){
pNew = sqlite3_realloc(p, n);
if( !pNew ){
db->mallocFailed = 1;
if( p==0 ){
return sqlite3DbMallocRaw(db, n);
}
if( isLookaside(db, p) ){
if( n<=db->lookaside.sz ){
return p;
}
pNew = sqlite3DbMallocRaw(db, n);
if( pNew ){
memcpy(pNew, p, db->lookaside.sz);
sqlite3DbFree(db, p);
}
}else{
pNew = sqlite3_realloc(p, n);
if( !pNew ){
db->mallocFailed = 1;
}
}
}
return pNew;
@ -587,7 +657,7 @@ void *sqlite3DbReallocOrFree(sqlite3 *db, void *p, int n){
void *pNew;
pNew = sqlite3DbRealloc(db, p, n);
if( !pNew ){
sqlite3_free(p);
sqlite3DbFree(db, p);
}
return pNew;
}
@ -599,37 +669,30 @@ void *sqlite3DbReallocOrFree(sqlite3 *db, void *p, int n){
** called via macros that record the current file and line number in the
** ThreadData structure.
*/
char *sqlite3StrDup(const char *z){
char *sqlite3DbStrDup(sqlite3 *db, const char *z){
char *zNew;
int n;
if( z==0 ) return 0;
size_t n;
if( z==0 ){
return 0;
}
n = strlen(z)+1;
zNew = sqlite3Malloc(n);
if( zNew ) memcpy(zNew, z, n);
return zNew;
}
char *sqlite3StrNDup(const char *z, int n){
char *zNew;
if( z==0 ) return 0;
zNew = sqlite3Malloc(n+1);
assert( (n&0x7fffffff)==n );
zNew = sqlite3DbMallocRaw(db, (int)n);
if( zNew ){
memcpy(zNew, z, n);
zNew[n] = 0;
}
return zNew;
}
char *sqlite3DbStrDup(sqlite3 *db, const char *z){
char *zNew = sqlite3StrDup(z);
if( z && !zNew ){
db->mallocFailed = 1;
}
return zNew;
}
char *sqlite3DbStrNDup(sqlite3 *db, const char *z, int n){
char *zNew = sqlite3StrNDup(z, n);
if( z && !zNew ){
db->mallocFailed = 1;
char *zNew;
if( z==0 ){
return 0;
}
assert( (n&0x7fffffff)==n );
zNew = sqlite3DbMallocRaw(db, n+1);
if( zNew ){
memcpy(zNew, z, n);
zNew[n] = 0;
}
return zNew;
}
@ -646,7 +709,7 @@ void sqlite3SetString(char **pz, sqlite3 *db, const char *zFormat, ...){
va_start(ap, zFormat);
z = sqlite3VMPrintf(db, zFormat, ap);
va_end(ap);
sqlite3_free(*pz);
sqlite3DbFree(db, *pz);
*pz = z;
}

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.23 2008/06/23 15:10:25 danielk1977 Exp $
** $Id: mem1.c,v 1.25 2008/07/25 08:49:00 danielk1977 Exp $
*/
#include "sqliteInt.h"
@ -120,13 +120,7 @@ static void sqlite3MemShutdown(void *NotUsed){
return;
}
/*
** This routine is the only routine in this file with external linkage.
**
** Populate the low-level memory allocation function pointers in
** sqlite3Config.m with pointers to the routines in this file.
*/
void sqlite3MemSetDefault(void){
const sqlite3_mem_methods *sqlite3MemGetDefault(void){
static const sqlite3_mem_methods defaultMethods = {
sqlite3MemMalloc,
sqlite3MemFree,
@ -137,7 +131,17 @@ void sqlite3MemSetDefault(void){
sqlite3MemShutdown,
0
};
sqlite3_config(SQLITE_CONFIG_MALLOC, &defaultMethods);
return &defaultMethods;
}
/*
** This routine is the only routine in this file with external linkage.
**
** Populate the low-level memory allocation function pointers in
** sqlite3Config.m with pointers to the routines in this file.
*/
void sqlite3MemSetDefault(void){
sqlite3_config(SQLITE_CONFIG_MALLOC, sqlite3MemGetDefault());
}
#endif /* SQLITE_SYSTEM_MALLOC */

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.34 2008/07/10 18:13:42 drh Exp $
** $Id: mem2.c,v 1.37 2008/07/25 08:49:00 danielk1977 Exp $
*/
#include "sqliteInt.h"
@ -113,14 +113,37 @@ static struct {
/*
** Gather statistics on the sizes of memory allocations.
** sizeCnt[i] is the number of allocation attempts of i*8
** nAlloc[i] is the number of allocation attempts of i*8
** bytes. i==NCSIZE is the number of allocation attempts for
** sizes more than NCSIZE*8 bytes.
*/
int sizeCnt[NCSIZE];
int nAlloc[NCSIZE]; /* Total number of allocations */
int nCurrent[NCSIZE]; /* Current number of allocations */
int mxCurrent[NCSIZE]; /* Highwater mark for nCurrent */
} mem;
/*
** Adjust memory usage statistics
*/
static void adjustStats(int iSize, int increment){
int i = ((iSize+7)&~7)/8;
if( i>NCSIZE-1 ){
i = NCSIZE - 1;
}
if( increment>0 ){
mem.nAlloc[i]++;
mem.nCurrent[i]++;
if( mem.nCurrent[i]>mem.mxCurrent[i] ){
mem.mxCurrent[i] = mem.nCurrent[i];
}
}else{
mem.nCurrent[i]--;
assert( mem.nCurrent[i]>=0 );
}
}
/*
** Given an allocation, find the MemBlockHdr for that allocation.
**
@ -198,11 +221,6 @@ static void *sqlite3MemMalloc(int nByte){
sqlite3_mutex_enter(mem.mutex);
assert( mem.disallow==0 );
nReserve = (nByte+7)&~7;
if( nReserve/8>NCSIZE-1 ){
mem.sizeCnt[NCSIZE-1]++;
}else{
mem.sizeCnt[nReserve/8]++;
}
totalSize = nReserve + sizeof(*pHdr) + sizeof(int) +
mem.nBacktrace*sizeof(void*) + mem.nTitle;
p = malloc(totalSize);
@ -235,6 +253,7 @@ static void *sqlite3MemMalloc(int nByte){
memcpy(z, mem.zTitle, mem.nTitle);
}
pHdr->iSize = nByte;
adjustStats(nByte, +1);
pInt = (int*)&pHdr[1];
pInt[nReserve/sizeof(int)] = REARGUARD;
memset(pInt, 0x65, nReserve);
@ -272,6 +291,7 @@ static void sqlite3MemFree(void *pPrior){
}
z = (char*)pBt;
z -= pHdr->nTitle;
adjustStats(pHdr->iSize, -1);
memset(z, 0x2b, sizeof(void*)*pHdr->nBacktraceSlots + sizeof(*pHdr) +
pHdr->iSize + sizeof(int) + pHdr->nTitle);
free(z);
@ -304,11 +324,7 @@ static void *sqlite3MemRealloc(void *pPrior, int nByte){
}
/*
** Populate the low-level memory allocation function pointers in
** sqlite3Config.m with pointers to the routines in this file.
*/
void sqlite3MemSetDefault(void){
const sqlite3_mem_methods *sqlite3MemGetDefault(void){
static const sqlite3_mem_methods defaultMethods = {
sqlite3MemMalloc,
sqlite3MemFree,
@ -319,7 +335,15 @@ void sqlite3MemSetDefault(void){
sqlite3MemShutdown,
0
};
sqlite3_config(SQLITE_CONFIG_MALLOC, &defaultMethods);
return &defaultMethods;
}
/*
** Populate the low-level memory allocation function pointers in
** sqlite3Config.m with pointers to the routines in this file.
*/
void sqlite3MemSetDefault(void){
sqlite3_config(SQLITE_CONFIG_MALLOC, sqlite3MemGetDefault());
}
/*
@ -390,12 +414,15 @@ void sqlite3MemdebugDump(const char *zFilename){
}
fprintf(out, "COUNTS:\n");
for(i=0; i<NCSIZE-1; i++){
if( mem.sizeCnt[i] ){
fprintf(out, " %3d: %d\n", i*8+8, mem.sizeCnt[i]);
if( mem.nAlloc[i] ){
fprintf(out, " %5d: %10d %10d %10d\n",
i*8, mem.nAlloc[i], mem.nCurrent[i], mem.mxCurrent[i]);
}
}
if( mem.sizeCnt[NCSIZE-1] ){
fprintf(out, " >%3d: %d\n", NCSIZE*8, mem.sizeCnt[NCSIZE-1]);
if( mem.nAlloc[NCSIZE-1] ){
fprintf(out, " %5d: %10d %10d %10d\n",
NCSIZE*8-8, mem.nAlloc[NCSIZE-1],
mem.nCurrent[NCSIZE-1], mem.mxCurrent[NCSIZE-1]);
}
fclose(out);
}
@ -407,7 +434,7 @@ int sqlite3MemdebugMallocCount(){
int i;
int nTotal = 0;
for(i=0; i<NCSIZE; i++){
nTotal += mem.sizeCnt[i];
nTotal += mem.nAlloc[i];
}
return nTotal;
}

View File

@ -23,7 +23,7 @@
** This version of the memory allocation subsystem is included
** in the build only if SQLITE_ENABLE_MEMSYS3 is defined.
**
** $Id: mem3.c,v 1.19 2008/07/16 12:25:32 drh Exp $
** $Id: mem3.c,v 1.20 2008/07/18 18:56:17 drh Exp $
*/
#include "sqliteInt.h"
@ -138,7 +138,6 @@ static struct {
*/
u32 nPool;
Mem3Block *aPool;
/* Mem3Block aPool[SQLITE_MEMORY_SIZE/sizeof(Mem3Block)+2]; */
} mem3;
/*
@ -470,6 +469,30 @@ void memsys3FreeUnsafe(void *pOld){
}
}
/*
** Return the size of an outstanding allocation, in bytes. The
** size returned omits the 8-byte header overhead. This only
** works for chunks that are currently checked out.
*/
static int memsys3Size(void *p){
Mem3Block *pBlock;
if( p==0 ) return 0;
pBlock = (Mem3Block*)p;
assert( (pBlock[-1].u.hdr.size4x&1)!=0 );
return (pBlock[-1].u.hdr.size4x&~3)*2 - 4;
}
/*
** Round up a request size to the next valid allocation size.
*/
static int memsys3Roundup(int n){
if( n<=12 ){
return 12;
}else{
return ((n+11)&~7) - 4;
}
}
/*
** Allocate nBytes of memory.
*/
@ -492,19 +515,6 @@ void memsys3Free(void *pPrior){
memsys3Leave();
}
/*
** Return the size of an outstanding allocation, in bytes. The
** size returned omits the 8-byte header overhead. This only
** works for chunks that are currently checked out.
*/
static int memsys3Size(void *p){
Mem3Block *pBlock;
if( p==0 ) return 0;
pBlock = (Mem3Block*)p;
assert( (pBlock[-1].u.hdr.size4x&1)!=0 );
return (pBlock[-1].u.hdr.size4x&~3)*2 - 4;
}
/*
** Change the size of an existing memory allocation
*/
@ -536,13 +546,6 @@ void *memsys3Realloc(void *pPrior, int nBytes){
return p;
}
/*
** Round up a request size to the next valid allocation size.
*/
static int memsys3Roundup(int n){
return (n+7) & ~7;
}
/*
** Initialize this module.
*/

496
src/mem6.c Normal file
View File

@ -0,0 +1,496 @@
/*
** 2008 July 24
**
** 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 an alternative memory allocation system for SQLite.
** This system is implemented as a wrapper around the system provided
** by the operating system - vanilla malloc(), realloc() and free().
**
** This system differentiates between requests for "small" allocations
** (by default those of 128 bytes or less) and "large" allocations (all
** others). The 256 byte threshhold is configurable at runtime.
**
** All requests for large allocations are passed through to the
** default system.
**
** Requests for small allocations are met by allocating space within
** one or more larger "chunks" of memory obtained from the default
** memory allocation system. Chunks of memory are usually 64KB or
** larger. The algorithm used to manage space within each chunk is
** the same as that used by mem5.c.
**
** This strategy is designed to prevent the default memory allocation
** system (usually the system malloc) from suffering from heap
** fragmentation. On some systems, heap fragmentation can cause a
** significant real-time slowdown.
**
** $Id: mem6.c,v 1.7 2008/07/28 19:34:53 drh Exp $
*/
#ifdef SQLITE_ENABLE_MEMSYS6
#include "sqliteInt.h"
/*
** Maximum size of any "small" allocation is ((1<<LOGMAX)*Mem6Chunk.nAtom).
** Mem6Chunk.nAtom is always at least 8, so this is not a practical
** limitation
*/
#define LOGMAX 30
/*
** Default value for the "small" allocation size threshold.
*/
#define SMALL_MALLOC_DEFAULT_THRESHOLD 256
/*
** Minimum size for a memory chunk.
*/
#define MIN_CHUNKSIZE (1<<16)
#define LOG2_MINALLOC 4
typedef struct Mem6Chunk Mem6Chunk;
typedef struct Mem6Link Mem6Link;
/*
** A minimum allocation is an instance of the following structure.
** Larger allocations are an array of these structures where the
** size of the array is a power of 2.
*/
struct Mem6Link {
int next; /* Index of next free chunk */
int prev; /* Index of previous free chunk */
};
/*
** Masks used for mem5.aCtrl[] elements.
*/
#define CTRL_LOGSIZE 0x1f /* Log2 Size of this block relative to POW2_MIN */
#define CTRL_FREE 0x20 /* True if not checked out */
struct Mem6Chunk {
Mem6Chunk *pNext;
/*
** Lists of free blocks of various sizes.
*/
int aiFreelist[LOGMAX+1];
int nCheckedOut; /* Number of currently outstanding allocations */
/*
** Space for tracking which blocks are checked out and the size
** of each block. One byte per block.
*/
u8 *aCtrl;
/*
** Memory available for allocation
*/
int nAtom; /* Smallest possible allocation in bytes */
int nBlock; /* Number of nAtom sized blocks in zPool */
u8 *zPool; /* Pointer to memory chunk from which allocations are made */
};
#define MEM6LINK(idx) ((Mem6Link *)(&pChunk->zPool[(idx)*pChunk->nAtom]))
struct Mem6Global {
int nMinAlloc; /* Minimum allowed allocation size */
int nThreshold; /* Allocs larger than this go to malloc() */
int nLogThreshold; /* log2 of (nThreshold/nMinAlloc) */
sqlite3_mutex *mutex;
Mem6Chunk *pChunk; /* Singly linked list of all memory chunks */
} mem6;
/*
** Unlink the chunk at pChunk->aPool[i] from list it is currently
** on. It should be found on pChunk->aiFreelist[iLogsize].
*/
static void memsys6Unlink(Mem6Chunk *pChunk, int i, int iLogsize){
int next, prev;
assert( i>=0 && i<pChunk->nBlock );
assert( iLogsize>=0 && iLogsize<=mem6.nLogThreshold );
assert( (pChunk->aCtrl[i] & CTRL_LOGSIZE)==iLogsize );
next = MEM6LINK(i)->next;
prev = MEM6LINK(i)->prev;
if( prev<0 ){
pChunk->aiFreelist[iLogsize] = next;
}else{
MEM6LINK(prev)->next = next;
}
if( next>=0 ){
MEM6LINK(next)->prev = prev;
}
}
/*
** Link the chunk at mem5.aPool[i] so that is on the iLogsize
** free list.
*/
static void memsys6Link(Mem6Chunk *pChunk, int i, int iLogsize){
int x;
assert( i>=0 && i<pChunk->nBlock );
assert( iLogsize>=0 && iLogsize<=mem6.nLogThreshold );
assert( (pChunk->aCtrl[i] & CTRL_LOGSIZE)==iLogsize );
x = MEM6LINK(i)->next = pChunk->aiFreelist[iLogsize];
MEM6LINK(i)->prev = -1;
if( x>=0 ){
assert( x<pChunk->nBlock );
MEM6LINK(x)->prev = i;
}
pChunk->aiFreelist[iLogsize] = i;
}
/*
** Find the first entry on the freelist iLogsize. Unlink that
** entry and return its index.
*/
static int memsys6UnlinkFirst(Mem6Chunk *pChunk, int iLogsize){
int i;
int iFirst;
assert( iLogsize>=0 && iLogsize<=mem6.nLogThreshold );
i = iFirst = pChunk->aiFreelist[iLogsize];
assert( iFirst>=0 );
memsys6Unlink(pChunk, iFirst, iLogsize);
return iFirst;
}
static int roundupLog2(int n){
static const char LogTable256[256] = {
0, /* 1 */
1, /* 2 */
2, 2, /* 3..4 */
3, 3, 3, 3, /* 5..8 */
4, 4, 4, 4, 4, 4, 4, 4, /* 9..16 */
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, /* 17..32 */
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, /* 33..64 */
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, /* 65..128 */
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, /* 129..256 */
};
assert(n<=(1<<16) && n>0);
if( n<=256 ) return LogTable256[n-1];
return LogTable256[(n>>8) - ((n&0xFF)?0:1)] + 8;
}
/*
** Allocate and return a block of (pChunk->nAtom << iLogsize) bytes from chunk
** pChunk. If the allocation request cannot be satisfied, return 0.
*/
static void *chunkMalloc(Mem6Chunk *pChunk, int iLogsize){
int i; /* Index of a mem5.aPool[] slot */
int iBin; /* Index into mem5.aiFreelist[] */
/* Make sure mem5.aiFreelist[iLogsize] contains at least one free
** block. If not, then split a block of the next larger power of
** two in order to create a new free block of size iLogsize.
*/
for(iBin=iLogsize; pChunk->aiFreelist[iBin]<0 && iBin<=mem6.nLogThreshold; iBin++){}
if( iBin>mem6.nLogThreshold ) return 0;
i = memsys6UnlinkFirst(pChunk, iBin);
while( iBin>iLogsize ){
int newSize;
iBin--;
newSize = 1 << iBin;
pChunk->aCtrl[i+newSize] = CTRL_FREE | iBin;
memsys6Link(pChunk, i+newSize, iBin);
}
pChunk->aCtrl[i] = iLogsize;
/* Return a pointer to the allocated memory. */
pChunk->nCheckedOut++;
return (void*)&pChunk->zPool[i*pChunk->nAtom];
}
/*
** Free the allocation pointed to by p, which is guaranteed to be non-zero
** and a part of chunk object pChunk.
*/
static void chunkFree(Mem6Chunk *pChunk, void *pOld){
u32 size, iLogsize;
int iBlock;
/* Set iBlock to the index of the block pointed to by pOld in
** the array of pChunk->nAtom byte blocks pointed to by pChunk->zPool.
*/
iBlock = ((u8 *)pOld-pChunk->zPool)/pChunk->nAtom;
/* Check that the pointer pOld points to a valid, non-free block. */
assert( iBlock>=0 && iBlock<pChunk->nBlock );
assert( ((u8 *)pOld-pChunk->zPool)%pChunk->nAtom==0 );
assert( (pChunk->aCtrl[iBlock] & CTRL_FREE)==0 );
iLogsize = pChunk->aCtrl[iBlock] & CTRL_LOGSIZE;
size = 1<<iLogsize;
assert( iBlock+size-1<pChunk->nBlock );
pChunk->aCtrl[iBlock] |= CTRL_FREE;
pChunk->aCtrl[iBlock+size-1] |= CTRL_FREE;
pChunk->aCtrl[iBlock] = CTRL_FREE | iLogsize;
while( iLogsize<mem6.nLogThreshold ){
int iBuddy;
if( (iBlock>>iLogsize) & 1 ){
iBuddy = iBlock - size;
}else{
iBuddy = iBlock + size;
}
assert( iBuddy>=0 );
if( (iBuddy+(1<<iLogsize))>pChunk->nBlock ) break;
if( pChunk->aCtrl[iBuddy]!=(CTRL_FREE | iLogsize) ) break;
memsys6Unlink(pChunk, iBuddy, iLogsize);
iLogsize++;
if( iBuddy<iBlock ){
pChunk->aCtrl[iBuddy] = CTRL_FREE | iLogsize;
pChunk->aCtrl[iBlock] = 0;
iBlock = iBuddy;
}else{
pChunk->aCtrl[iBlock] = CTRL_FREE | iLogsize;
pChunk->aCtrl[iBuddy] = 0;
}
size *= 2;
}
pChunk->nCheckedOut--;
memsys6Link(pChunk, iBlock, iLogsize);
}
/*
** Return the actual size of the block pointed to by p, which is guaranteed
** to have been allocated from chunk pChunk.
*/
static int chunkSize(Mem6Chunk *pChunk, void *p){
int iSize = 0;
if( p ){
int i = ((u8 *)p-pChunk->zPool)/pChunk->nAtom;
assert( i>=0 && i<pChunk->nBlock );
iSize = pChunk->nAtom * (1 << (pChunk->aCtrl[i]&CTRL_LOGSIZE));
}
return iSize;
}
/*
** Return true if there are currently no outstanding allocations.
*/
static int chunkIsEmpty(Mem6Chunk *pChunk){
return (pChunk->nCheckedOut==0);
}
/*
** Initialize the buffer zChunk, which is nChunk bytes in size, as
** an Mem6Chunk object. Return a copy of the zChunk pointer.
*/
static Mem6Chunk *chunkInit(u8 *zChunk, int nChunk, int nMinAlloc){
int ii;
int iOffset;
Mem6Chunk *pChunk = (Mem6Chunk *)zChunk;
assert( nChunk>sizeof(Mem6Chunk) );
assert( nMinAlloc>sizeof(Mem6Link) );
memset(pChunk, 0, sizeof(Mem6Chunk));
pChunk->nAtom = nMinAlloc;
pChunk->nBlock = ((nChunk-sizeof(Mem6Chunk)) / (pChunk->nAtom+sizeof(u8)));
pChunk->zPool = (u8 *)&pChunk[1];
pChunk->aCtrl = &pChunk->zPool[pChunk->nBlock*pChunk->nAtom];
for(ii=0; ii<=mem6.nLogThreshold; ii++){
pChunk->aiFreelist[ii] = -1;
}
iOffset = 0;
for(ii=mem6.nLogThreshold; ii>=0; ii--){
int nAlloc = (1<<ii);
while( (iOffset+nAlloc)<=pChunk->nBlock ){
pChunk->aCtrl[iOffset] = ii | CTRL_FREE;
memsys6Link(pChunk, iOffset, ii);
iOffset += nAlloc;
}
}
return pChunk;
}
static void mem6Enter(void){
sqlite3_mutex_enter(mem6.mutex);
}
static void mem6Leave(void){
sqlite3_mutex_leave(mem6.mutex);
}
/*
** Based on the number and size of the currently allocated chunks, return
** the size of the next chunk to allocate, in bytes.
*/
static int nextChunkSize(void){
int iTotal = MIN_CHUNKSIZE;
Mem6Chunk *p;
for(p=mem6.pChunk; p; p=p->pNext){
iTotal = iTotal*2;
}
return iTotal;
}
static void freeChunk(Mem6Chunk *pChunk){
Mem6Chunk **pp = &mem6.pChunk;
for( pp=&mem6.pChunk; *pp!=pChunk; pp = &(*pp)->pNext );
*pp = (*pp)->pNext;
free(pChunk);
}
static void *memsys6Malloc(int nByte){
Mem6Chunk *pChunk;
void *p = 0;
int nTotal = nByte+8;
int iOffset = 0;
if( nTotal>mem6.nThreshold ){
p = malloc(nTotal);
}else{
int iLogsize = 0;
if( nTotal>(1<<LOG2_MINALLOC) ){
iLogsize = roundupLog2(nTotal) - LOG2_MINALLOC;
}
mem6Enter();
for(pChunk=mem6.pChunk; pChunk; pChunk=pChunk->pNext){
p = chunkMalloc(pChunk, iLogsize);
if( p ){
break;
}
}
if( !p ){
int iSize = nextChunkSize();
p = malloc(iSize);
if( p ){
pChunk = chunkInit((u8 *)p, iSize, mem6.nMinAlloc);
pChunk->pNext = mem6.pChunk;
mem6.pChunk = pChunk;
p = chunkMalloc(pChunk, iLogsize);
assert(p);
}
}
iOffset = ((u8*)p - (u8*)pChunk);
mem6Leave();
}
if( !p ){
return 0;
}
((u32 *)p)[0] = iOffset;
((u32 *)p)[1] = nByte;
return &((u32 *)p)[2];
}
static int memsys6Size(void *pPrior){
if( pPrior==0 ) return 0;
return ((u32*)pPrior)[-1];
}
static void memsys6Free(void *pPrior){
int iSlot;
void *p = &((u32 *)pPrior)[-2];
iSlot = ((u32 *)p)[0];
if( iSlot ){
Mem6Chunk *pChunk;
mem6Enter();
pChunk = (Mem6Chunk *)(&((u8 *)p)[-1 * iSlot]);
chunkFree(pChunk, p);
if( chunkIsEmpty(pChunk) ){
freeChunk(pChunk);
}
mem6Leave();
}else{
free(p);
}
}
static void *memsys6Realloc(void *p, int nByte){
void *p2;
if( p && nByte<=memsys6Size(p) ){
p2 = p;
}else{
p2 = memsys6Malloc(nByte);
if( p && p2 ){
memcpy(p2, p, memsys6Size(p));
memsys6Free(p);
}
}
return p2;
}
static int memsys6Roundup(int n){
if( n>mem6.nThreshold ){
return n;
}else{
return (1<<roundupLog2(n));
}
}
static int memsys6Init(void *pCtx){
u8 bMemstat = sqlite3Config.bMemstat;
mem6.nMinAlloc = (1 << LOG2_MINALLOC);
mem6.pChunk = 0;
mem6.nThreshold = sqlite3Config.nSmall;
if( mem6.nThreshold<=0 ){
mem6.nThreshold = SMALL_MALLOC_DEFAULT_THRESHOLD;
}
mem6.nLogThreshold = roundupLog2(mem6.nThreshold) - LOG2_MINALLOC;
if( !bMemstat ){
mem6.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
}
return SQLITE_OK;
}
static void memsys6Shutdown(void *pCtx){
memset(&mem6, 0, sizeof(mem6));
}
/*
** This routine is the only routine in this file with external
** linkage. It returns a pointer to a static sqlite3_mem_methods
** struct populated with the memsys6 methods.
*/
const sqlite3_mem_methods *sqlite3MemGetMemsys6(void){
static const sqlite3_mem_methods memsys6Methods = {
memsys6Malloc,
memsys6Free,
memsys6Realloc,
memsys6Size,
memsys6Roundup,
memsys6Init,
memsys6Shutdown,
0
};
return &memsys6Methods;
}
#endif

View File

@ -13,7 +13,7 @@
** This file contains OS interface code that is common to all
** architectures.
**
** $Id: os.c,v 1.119 2008/06/26 18:16:06 drh Exp $
** $Id: os.c,v 1.120 2008/07/28 19:34:53 drh Exp $
*/
#define _SQLITE_OS_C_ 1
#include "sqliteInt.h"
@ -36,7 +36,7 @@
** sqlite3OsLock()
**
*/
#if defined(SQLITE_TEST) && (SQLITE_OS_WIN==0)
#if defined(SQLITE_TEST) && (SQLITE_OS_WIN==0) && 0
#define DO_OS_MALLOC_TEST if (1) { \
void *pTstAlloc = sqlite3Malloc(10); \
if (!pTstAlloc) return SQLITE_IOERR_NOMEM; \

View File

@ -12,7 +12,7 @@
**
** This file contains code that is specific to OS/2.
**
** $Id: os_os2.c,v 1.50 2008/07/15 22:59:05 pweilbacher Exp $
** $Id: os_os2.c,v 1.55 2008/07/29 18:49:29 pweilbacher Exp $
*/
#include "sqliteInt.h"
@ -558,7 +558,6 @@ static UconvObject uclCp = NULL; /* convert between local codepage and UCS-2 */
** Helper function to initialize the conversion objects from and to UTF-8.
*/
static void initUconvObjects( void ){
printf("init them\n");
if( UniCreateUconvObject( UTF_8, &ucUtf8 ) != ULS_SUCCESS )
ucUtf8 = NULL;
if ( UniCreateUconvObject( (UniChar *)L"@path=yes", &uclCp ) != ULS_SUCCESS )
@ -569,7 +568,6 @@ static void initUconvObjects( void ){
** Helper function to free the conversion objects from and to UTF-8.
*/
static void freeUconvObjects( void ){
printf("free them\n");
if ( ucUtf8 )
UniFreeUconvObject( ucUtf8 );
if ( uclCp )
@ -587,7 +585,6 @@ static void freeUconvObjects( void ){
static char *convertUtf8PathToCp( const char *in ){
UniChar tempPath[CCHMAXPATH];
char *out = (char *)calloc( CCHMAXPATH, 1 );
printf("convertUtf8PathToCp(%s)\n", in);
if( !out )
return NULL;
@ -602,7 +599,6 @@ printf("convertUtf8PathToCp(%s)\n", in);
/* conversion for current codepage which can be used for paths */
UniStrFromUcs( uclCp, out, tempPath, CCHMAXPATH );
printf("%s -> Cp = %s\n", in, out);
return out;
}
@ -618,7 +614,6 @@ printf("convertUtf8PathToCp(%s)\n", in);
char *convertCpPathToUtf8( const char *in ){
UniChar tempPath[CCHMAXPATH];
char *out = (char *)calloc( CCHMAXPATH, 1 );
printf("convertCpPathToUtf8(%s)\n", in);
if( !out )
return NULL;
@ -633,7 +628,6 @@ printf("convertCpPathToUtf8(%s)\n", in);
/* determine string for the conversion of UTF-8 which is CP1208 */
UniStrFromUcs( ucUtf8, out, tempPath, CCHMAXPATH );
printf("%s -> Utf8 = %s\n", in, out);
return out;
}
@ -717,6 +711,30 @@ static int getTempname(int nBuf, char *zBuf ){
}
/*
** Turn a relative pathname into a full pathname. Write the full
** pathname into zFull[]. zFull[] will be at least pVfs->mxPathname
** bytes in size.
*/
static int os2FullPathname(
sqlite3_vfs *pVfs, /* Pointer to vfs object */
const char *zRelative, /* Possibly relative input path */
int nFull, /* Size of output buffer in bytes */
char *zFull /* Output buffer */
){
char *zRelativeCp = convertUtf8PathToCp( zRelative );
char zFullCp[CCHMAXPATH] = "\0";
char *zFullUTF;
APIRET rc = DosQueryPathInfo( zRelativeCp, FIL_QUERYFULLNAME, zFullCp,
CCHMAXPATH );
free( zRelativeCp );
zFullUTF = convertCpPathToUtf8( zFullCp );
sqlite3_snprintf( nFull, zFull, zFullUTF );
free( zFullUTF );
return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR;
}
/*
** Open a file.
*/
@ -783,9 +801,11 @@ static int os2Open(
if( flags & (SQLITE_OPEN_TEMP_DB | SQLITE_OPEN_TEMP_JOURNAL
| SQLITE_OPEN_SUBJOURNAL) ){
char pathUtf8[CCHMAXPATH];
/*ulFileAttribute = FILE_HIDDEN; //for debugging, we want to make sure it is deleted*/
#ifdef NDEBUG /* when debugging we want to make sure it is deleted */
ulFileAttribute = FILE_HIDDEN;
#endif
ulFileAttribute = FILE_NORMAL;
sqlite3OsFullPathname( pVfs, zName, CCHMAXPATH, pathUtf8 );
os2FullPathname( pVfs, zName, CCHMAXPATH, pathUtf8 );
pFile->pathToDel = convertUtf8PathToCp( pathUtf8 );
OSTRACE1( "OPEN hidden/delete on close file attributes\n" );
}else{
@ -817,7 +837,7 @@ static int os2Open(
pFile->pathToDel = NULL;
if( flags & SQLITE_OPEN_READWRITE ){
OSTRACE2( "OPEN %d Invalid handle\n", ((flags | SQLITE_OPEN_READONLY) & ~SQLITE_OPEN_READWRITE) );
return os2Open( 0, zName, id,
return os2Open( pVfs, zName, id,
((flags | SQLITE_OPEN_READONLY) & ~SQLITE_OPEN_READWRITE),
pOutFlags );
}else{
@ -890,29 +910,6 @@ static int os2Access(
}
/*
** Turn a relative pathname into a full pathname. Write the full
** pathname into zFull[]. zFull[] will be at least pVfs->mxPathname
** bytes in size.
*/
static int os2FullPathname(
sqlite3_vfs *pVfs, /* Pointer to vfs object */
const char *zRelative, /* Possibly relative input path */
int nFull, /* Size of output buffer in bytes */
char *zFull /* Output buffer */
){
char *zRelativeCp = convertUtf8PathToCp( zRelative );
char zFullCp[CCHMAXPATH];
char *zFullUTF;
APIRET rc = DosQueryPathInfo( zRelativeCp, FIL_QUERYFULLNAME, zFullCp,
CCHMAXPATH );
free( zRelativeCp );
zFullUTF = convertCpPathToUtf8( zFullCp );
sqlite3_snprintf( nFull, zFull, zFullUTF );
free( zFullUTF );
return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR;
}
#ifndef SQLITE_OMIT_LOAD_EXTENSION
/*
** Interfaces for opening a shared library, finding entry points
@ -1089,8 +1086,6 @@ static int os2GetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
** Initialize and deinitialize the operating system interface.
*/
int sqlite3_os_init(void){
initUconvObjects();
static sqlite3_vfs os2Vfs = {
1, /* iVersion */
sizeof(os2File), /* szOsFile */
@ -1113,6 +1108,7 @@ int sqlite3_os_init(void){
os2GetLastError /* xGetLastError */
};
sqlite3_vfs_register(&os2Vfs, 1);
initUconvObjects();
return SQLITE_OK;
}
int sqlite3_os_end(void){

View File

@ -12,7 +12,7 @@
**
** This file contains code that is specific to Unix systems.
**
** $Id: os_unix.c,v 1.193 2008/07/10 00:32:42 drh Exp $
** $Id: os_unix.c,v 1.195 2008/07/30 17:28:04 drh Exp $
*/
#include "sqliteInt.h"
#if SQLITE_OS_UNIX /* This file is used on unix only */
@ -311,6 +311,7 @@ struct lockInfo {
int cnt; /* Number of SHARED locks held */
int locktype; /* One of SHARED_LOCK, RESERVED_LOCK etc. */
int nRef; /* Number of pointers to this structure */
struct lockInfo *pNext, *pPrev; /* List of all lockInfo objects */
};
/*
@ -336,15 +337,17 @@ struct openCnt {
int nLock; /* Number of outstanding locks */
int nPending; /* Number of pending close() operations */
int *aPending; /* Malloced space holding fd's awaiting a close() */
struct openCnt *pNext, *pPrev; /* List of all openCnt objects */
};
/*
** These hash tables map inodes and file descriptors (really, lockKey and
** openKey structures) into lockInfo and openCnt structures. Access to
** these hash tables must be protected by a mutex.
/*
** List of all lockInfo and openCnt objects. This used to be a hash
** table. But the number of objects is rarely more than a dozen and
** never exceeds a few thousand. And lookup is not on a critical
** path oo a simple linked list will suffice.
*/
static Hash lockHash = {SQLITE_HASH_BINARY, 0, 0, 0, 0, 0};
static Hash openHash = {SQLITE_HASH_BINARY, 0, 0, 0, 0, 0};
static struct lockInfo *lockList = 0;
static struct openCnt *openList = 0;
/*
** The locking styles are associated with the different file locking
@ -362,9 +365,9 @@ static Hash openHash = {SQLITE_HASH_BINARY, 0, 0, 0, 0, 0};
** file systems that are known to be unsupported
*/
#define LOCKING_STYLE_POSIX 1
#define LOCKING_STYLE_FLOCK 2
#define LOCKING_STYLE_NONE 2
#define LOCKING_STYLE_DOTFILE 3
#define LOCKING_STYLE_NONE 4
#define LOCKING_STYLE_FLOCK 4
#define LOCKING_STYLE_AFP 5
/*
@ -523,7 +526,17 @@ static void releaseLockInfo(struct lockInfo *pLock){
if( pLock ){
pLock->nRef--;
if( pLock->nRef==0 ){
sqlite3HashInsert(&lockHash, &pLock->key, sizeof(pLock->key), 0);
if( pLock->pPrev ){
assert( pLock->pPrev->pNext==pLock );
pLock->pPrev->pNext = pLock->pNext;
}else{
assert( lockList==pLock );
lockList = pLock->pNext;
}
if( pLock->pNext ){
assert( pLock->pNext->pPrev==pLock );
pLock->pNext->pPrev = pLock->pPrev;
}
sqlite3_free(pLock);
}
}
@ -536,8 +549,18 @@ static void releaseOpenCnt(struct openCnt *pOpen){
if( pOpen ){
pOpen->nRef--;
if( pOpen->nRef==0 ){
sqlite3HashInsert(&openHash, &pOpen->key, sizeof(pOpen->key), 0);
free(pOpen->aPending);
if( pOpen->pPrev ){
assert( pOpen->pPrev->pNext==pOpen );
pOpen->pPrev->pNext = pOpen->pNext;
}else{
assert( openList==pOpen );
openList = pOpen->pNext;
}
if( pOpen->pNext ){
assert( pOpen->pNext->pPrev==pOpen );
pOpen->pNext->pPrev = pOpen->pPrev;
}
sqlite3_free(pOpen->aPending);
sqlite3_free(pOpen);
}
}
@ -651,6 +674,24 @@ static int findLockInfo(
return SQLITE_IOERR;
}
/* On OS X on an msdos filesystem, the inode number is reported
** incorrectly for zero-size files. See ticket #3260. To work
** around this problem (we consider it a bug in OS X, not SQLite)
** we always increase the file size to 1 by writing a single byte
** prior to accessing the inode number. The one byte written is
** an ASCII 'S' character which also happens to be the first byte
** in the header of every SQLite database. In this way, if there
** is a race condition such that another thread has already populated
** the first page of the database, no damage is done.
*/
if( statbuf.st_size==0 ){
write(fd, "S", 1);
rc = fstat(fd, &statbuf);
if( rc!=0 ){
return SQLITE_IOERR;
}
}
memset(&key1, 0, sizeof(key1));
key1.dev = statbuf.st_dev;
key1.ino = statbuf.st_ino;
@ -663,9 +704,11 @@ static int findLockInfo(
memset(&key2, 0, sizeof(key2));
key2.dev = statbuf.st_dev;
key2.ino = statbuf.st_ino;
pLock = (struct lockInfo*)sqlite3HashFind(&lockHash, &key1, sizeof(key1));
pLock = lockList;
while( pLock && memcmp(&key1, &pLock->key, sizeof(key1)) ){
pLock = pLock->pNext;
}
if( pLock==0 ){
struct lockInfo *pOld;
pLock = sqlite3_malloc( sizeof(*pLock) );
if( pLock==0 ){
rc = SQLITE_NOMEM;
@ -675,21 +718,20 @@ static int findLockInfo(
pLock->nRef = 1;
pLock->cnt = 0;
pLock->locktype = 0;
pOld = sqlite3HashInsert(&lockHash, &pLock->key, sizeof(key1), pLock);
if( pOld!=0 ){
assert( pOld==pLock );
sqlite3_free(pLock);
rc = SQLITE_NOMEM;
goto exit_findlockinfo;
}
pLock->pNext = lockList;
pLock->pPrev = 0;
if( lockList ) lockList->pPrev = pLock;
lockList = pLock;
}else{
pLock->nRef++;
}
*ppLock = pLock;
if( ppOpen!=0 ){
pOpen = (struct openCnt*)sqlite3HashFind(&openHash, &key2, sizeof(key2));
pOpen = openList;
while( pOpen && memcmp(&key2, &pOpen->key, sizeof(key2)) ){
pOpen = pOpen->pNext;
}
if( pOpen==0 ){
struct openCnt *pOld;
pOpen = sqlite3_malloc( sizeof(*pOpen) );
if( pOpen==0 ){
releaseLockInfo(pLock);
@ -701,14 +743,10 @@ static int findLockInfo(
pOpen->nLock = 0;
pOpen->nPending = 0;
pOpen->aPending = 0;
pOld = sqlite3HashInsert(&openHash, &pOpen->key, sizeof(key2), pOpen);
if( pOld!=0 ){
assert( pOld==pOpen );
sqlite3_free(pOpen);
releaseLockInfo(pLock);
rc = SQLITE_NOMEM;
goto exit_findlockinfo;
}
pOpen->pNext = openList;
pOpen->pPrev = 0;
if( openList ) openList->pPrev = pOpen;
openList = pOpen;
}else{
pOpen->nRef++;
}
@ -1072,6 +1110,16 @@ static int unixFileSize(sqlite3_file *id, i64 *pSize){
return SQLITE_IOERR_FSTAT;
}
*pSize = buf.st_size;
/* When opening a zero-size database, the findLockInfo() procedure
** writes a single byte into that file in order to work around a bug
** in the OS-X msdos filesystem. In order to avoid problems with upper
** layers, we need to report this file size as zero even though it is
** really 1. Ticket #3260.
*/
if( *pSize==1 ) *pSize = 0;
return SQLITE_OK;
}
@ -1424,7 +1472,7 @@ static int unixUnlock(sqlite3_file *id, int locktype){
for(i=0; i<pOpen->nPending; i++){
close(pOpen->aPending[i]);
}
free(pOpen->aPending);
sqlite3_free(pOpen->aPending);
pOpen->nPending = 0;
pOpen->aPending = 0;
}
@ -1473,7 +1521,7 @@ static int unixClose(sqlite3_file *id){
*/
int *aNew;
struct openCnt *pOpen = pFile->pOpen;
aNew = realloc( pOpen->aPending, (pOpen->nPending+1)*sizeof(int) );
aNew = sqlite3_realloc(pOpen->aPending, (pOpen->nPending+1)*sizeof(int) );
if( aNew==0 ){
/* If a malloc fails, just leak the file descriptor */
}else{
@ -1970,7 +2018,7 @@ static int dotlockClose(sqlite3_file *id) {
}
#pragma mark No locking
#endif /* SQLITE_ENABLE_LOCKING_STYLE */
/*
** The nolockLockingContext is void
@ -1997,8 +2045,6 @@ static int nolockClose(sqlite3_file *id) {
return closeUnixFile(id);
}
#endif /* SQLITE_ENABLE_LOCKING_STYLE */
/*
** Information and control of an open file handle.
@ -2047,8 +2093,13 @@ static int fillInUnixFile(
int h, /* Open file descriptor of file being opened */
int dirfd, /* Directory file descriptor */
sqlite3_file *pId, /* Write to the unixFile structure here */
const char *zFilename /* Name of the file being opened */
const char *zFilename, /* Name of the file being opened */
int noLock /* Omit locking if true */
){
int eLockingStyle;
unixFile *pNew = (unixFile *)pId;
int rc = SQLITE_OK;
/* Macro to define the static contents of an sqlite3_io_methods
** structure for a unix backend file. Different locking methods
** require different functions for the xClose, xLock, xUnlock and
@ -2071,17 +2122,21 @@ static int fillInUnixFile(
}
static sqlite3_io_methods aIoMethod[] = {
IOMETHODS(unixClose, unixLock, unixUnlock, unixCheckReservedLock)
#ifdef SQLITE_ENABLE_LOCKING_STYLE
,IOMETHODS(flockClose, flockLock, flockUnlock, flockCheckReservedLock)
,IOMETHODS(dotlockClose, dotlockLock, dotlockUnlock,dotlockCheckReservedLock)
,IOMETHODS(nolockClose, nolockLock, nolockUnlock, nolockCheckReservedLock)
#ifdef SQLITE_ENABLE_LOCKING_STYLE
,IOMETHODS(dotlockClose, dotlockLock, dotlockUnlock,dotlockCheckReservedLock)
,IOMETHODS(flockClose, flockLock, flockUnlock, flockCheckReservedLock)
,IOMETHODS(afpClose, afpLock, afpUnlock, afpCheckReservedLock)
#endif
};
int eLockingStyle;
unixFile *pNew = (unixFile *)pId;
int rc = SQLITE_OK;
/* The order of the IOMETHODS macros above is important. It must be the
** same order as the LOCKING_STYLE numbers
*/
assert(LOCKING_STYLE_POSIX==1);
assert(LOCKING_STYLE_NONE==2);
assert(LOCKING_STYLE_DOTFILE==3);
assert(LOCKING_STYLE_FLOCK==4);
assert(LOCKING_STYLE_AFP==5);
assert( pNew->pLock==NULL );
assert( pNew->pOpen==NULL );
@ -2091,12 +2146,11 @@ static int fillInUnixFile(
pNew->dirfd = dirfd;
SET_THREADID(pNew);
assert(LOCKING_STYLE_POSIX==1);
assert(LOCKING_STYLE_FLOCK==2);
assert(LOCKING_STYLE_DOTFILE==3);
assert(LOCKING_STYLE_NONE==4);
assert(LOCKING_STYLE_AFP==5);
eLockingStyle = detectLockingStyle(pVfs, zFilename, h);
if( noLock ){
eLockingStyle = LOCKING_STYLE_NONE;
}else{
eLockingStyle = detectLockingStyle(pVfs, zFilename, h);
}
switch( eLockingStyle ){
@ -2280,6 +2334,7 @@ static int unixOpen(
int dirfd = -1; /* Directory file descriptor */
int oflags = 0; /* Flags to pass to open() */
int eType = flags&0xFFFFFF00; /* Type of file to open */
int noLock; /* True to omit locking primitives */
int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE);
int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE);
@ -2375,7 +2430,8 @@ static int unixOpen(
fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
#endif
return fillInUnixFile(pVfs, fd, dirfd, pFile, zPath);
noLock = eType!=SQLITE_OPEN_MAIN_DB;
return fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock);
}
/*

View File

@ -12,7 +12,7 @@
**
** This file contains code that is specific to windows.
**
** $Id: os_win.c,v 1.129 2008/06/26 10:41:19 danielk1977 Exp $
** $Id: os_win.c,v 1.132 2008/07/31 01:34:34 shane Exp $
*/
#include "sqliteInt.h"
#if SQLITE_OS_WIN /* This file is used for windows only */
@ -1083,7 +1083,7 @@ static int getTempname(int nBuf, char *zBuf){
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789";
int i, j;
size_t i, j;
char zTempPath[MAX_PATH+1];
if( sqlite3_temp_directory ){
sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", sqlite3_temp_directory);
@ -1124,6 +1124,36 @@ static int getTempname(int nBuf, char *zBuf){
return SQLITE_OK;
}
/*
** The return value of getLastErrorMsg
** is zero if the error message fits in the buffer, or non-zero
** otherwise (if the message was truncated).
*/
static int getLastErrorMsg(int nBuf, char *zBuf){
DWORD error = GetLastError();
#if SQLITE_OS_WINCE
sqlite3_snprintf(nBuf, zBuf, "OsError 0x%x (%u)", error, error);
#else
/* FormatMessage returns 0 on failure. Otherwise it
** returns the number of TCHARs written to the output
** buffer, excluding the terminating null char.
*/
if (!FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
error,
0,
zBuf,
nBuf-1,
0))
{
sqlite3_snprintf(nBuf, zBuf, "OsError 0x%x (%u)", error, error);
}
#endif
return 0;
}
/*
** Open a file.
@ -1204,9 +1234,6 @@ static int winOpen(
NULL
);
}else{
#if SQLITE_OS_WINCE
return SQLITE_NOMEM;
#else
h = CreateFileA((char*)zConverted,
dwDesiredAccess,
dwShareMode,
@ -1215,7 +1242,6 @@ static int winOpen(
dwFlagsAndAttributes,
NULL
);
#endif
}
if( h==INVALID_HANDLE_VALUE ){
free(zConverted);
@ -1262,7 +1288,7 @@ static int winOpen(
** Note that windows does not allow a file to be deleted if some other
** process has it open. Sometimes a virus scanner or indexing program
** will open a journal file shortly after it is created in order to do
** whatever does. While this other process is holding the
** whatever it does. While this other process is holding the
** file open, we will be unable to delete it. To work around this
** problem, we delay 100 milliseconds and try to delete again. Up
** to MX_DELETION_ATTEMPTs deletion attempts are run before giving
@ -1276,6 +1302,7 @@ static int winDelete(
){
int cnt = 0;
int rc;
DWORD error;
void *zConverted = convertUtf8Filename(zFilename);
if( zConverted==0 ){
return SQLITE_NOMEM;
@ -1284,21 +1311,22 @@ static int winDelete(
if( isNT() ){
do{
DeleteFileW(zConverted);
}while( (rc = GetFileAttributesW(zConverted))!=0xffffffff
&& cnt++ < MX_DELETION_ATTEMPTS && (Sleep(100), 1) );
}while( ( ((rc = GetFileAttributesW(zConverted)) != INVALID_FILE_ATTRIBUTES)
|| ((error = GetLastError()) == ERROR_ACCESS_DENIED))
&& (cnt++ < MX_DELETION_ATTEMPTS)
&& (Sleep(100), 1) );
}else{
#if SQLITE_OS_WINCE
return SQLITE_NOMEM;
#else
do{
DeleteFileA(zConverted);
}while( (rc = GetFileAttributesA(zConverted))!=0xffffffff
&& cnt++ < MX_DELETION_ATTEMPTS && (Sleep(100), 1) );
#endif
}while( ( ((rc = GetFileAttributesA(zConverted)) != INVALID_FILE_ATTRIBUTES)
|| ((error = GetLastError()) == ERROR_ACCESS_DENIED))
&& (cnt++ < MX_DELETION_ATTEMPTS)
&& (Sleep(100), 1) );
}
free(zConverted);
OSTRACE2("DELETE \"%s\"\n", zFilename);
return rc==0xffffffff ? SQLITE_OK : SQLITE_IOERR_DELETE;
return ( (rc==INVALID_FILE_ATTRIBUTES)
&& (error == ERROR_FILE_NOT_FOUND)) ? SQLITE_OK : SQLITE_IOERR_DELETE;
}
/*
@ -1319,17 +1347,13 @@ static int winAccess(
if( isNT() ){
attr = GetFileAttributesW((WCHAR*)zConverted);
}else{
#if SQLITE_OS_WINCE
return SQLITE_NOMEM;
#else
attr = GetFileAttributesA((char*)zConverted);
#endif
}
free(zConverted);
switch( flags ){
case SQLITE_ACCESS_READ:
case SQLITE_ACCESS_EXISTS:
rc = attr!=0xffffffff;
rc = attr!=INVALID_FILE_ATTRIBUTES;
break;
case SQLITE_ACCESS_READWRITE:
rc = (attr & FILE_ATTRIBUTE_READONLY)==0;
@ -1423,34 +1447,13 @@ static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){
if( isNT() ){
h = LoadLibraryW((WCHAR*)zConverted);
}else{
#if SQLITE_OS_WINCE
return 0;
#else
h = LoadLibraryA((char*)zConverted);
#endif
}
free(zConverted);
return (void*)h;
}
static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
#if SQLITE_OS_WINCE
int error = GetLastError();
if( error>0x7FFFFFF ){
sqlite3_snprintf(nBuf, zBufOut, "OsError 0x%x", error);
}else{
sqlite3_snprintf(nBuf, zBufOut, "OsError %d", error);
}
#else
FormatMessageA(
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
GetLastError(),
0,
zBufOut,
nBuf-1,
0
);
#endif
getLastErrorMsg(nBuf, zBufOut);
}
void *winDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol){
#if SQLITE_OS_WINCE
@ -1534,7 +1537,10 @@ int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
#if SQLITE_OS_WINCE
SYSTEMTIME time;
GetSystemTime(&time);
SystemTimeToFileTime(&time,&ft);
/* if SystemTimeToFileTime() fails, it returns zero. */
if (!SystemTimeToFileTime(&time,&ft)){
return 1;
}
#else
GetSystemTimeAsFileTime( &ft );
#endif
@ -1548,8 +1554,38 @@ int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
return 0;
}
/*
** The idea is that this function works like a combination of
** GetLastError() and FormatMessage() on windows (or errno and
** strerror_r() on unix). After an error is returned by an OS
** 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
** thread.
**
** If the error message is too large for the supplied buffer,
** it should be truncated. The return value of xGetLastError
** is zero if the error message fits in the buffer, or non-zero
** otherwise (if the message was truncated). If non-zero is returned,
** then it is not necessary to include the nul-terminator character
** in the output buffer.
**
** Not supplying an error message will have no adverse effect
** on SQLite. It is fine to have an implementation that never
** returns an error message:
**
** int xGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
** assert(zBuf[0]=='\0');
** return 0;
** }
**
** However if an error message is supplied, it will be incorporated
** by sqlite into the error message available to the user using
** sqlite3_errmsg(), possibly making IO errors easier to debug.
*/
static int winGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
return 0;
return getLastErrorMsg(nBuf, zBuf);
}
/*

View File

@ -18,7 +18,7 @@
** file simultaneously, or one process from reading the database while
** another is writing.
**
** @(#) $Id: pager.c,v 1.465 2008/07/11 03:34:10 drh Exp $
** @(#) $Id: pager.c,v 1.469 2008/08/02 03:50:39 drh Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"
@ -896,7 +896,7 @@ static int readMasterJournal(sqlite3_file *pJrnl, char *zMaster, int nMaster){
u32 len;
i64 szJ;
u32 cksum;
int i;
u32 u; /* Unsigned loop counter */
unsigned char aMagic[8]; /* A buffer to hold the magic header */
zMaster[0] = '\0';
@ -924,8 +924,8 @@ static int readMasterJournal(sqlite3_file *pJrnl, char *zMaster, int nMaster){
zMaster[len] = '\0';
/* See if the checksum matches the master journal name */
for(i=0; i<len; i++){
cksum -= zMaster[i];
for(u=0; u<len; u++){
cksum -= zMaster[u];
}
if( cksum ){
/* If the checksum doesn't add up, then one or more of the disk sectors
@ -1848,7 +1848,7 @@ static int pager_playback(Pager *pPager, int isHot){
sqlite3_vfs *pVfs = pPager->pVfs;
i64 szJ; /* Size of the journal file in bytes */
u32 nRec; /* Number of Records in the journal */
u32 i; /* Loop counter */
u32 u; /* Unsigned loop counter */
Pgno mxPg = 0; /* Size of the original file in pages */
int rc; /* Result code of a subroutine */
int res = 1; /* Value returned by sqlite3OsAccess() */
@ -1931,7 +1931,7 @@ static int pager_playback(Pager *pPager, int isHot){
/* Copy original pages out of the journal and back into the database file.
*/
for(i=0; i<nRec; i++){
for(u=0; u<nRec; u++){
rc = pager_playback_one_page(pPager, pPager->jfd, pPager->journalOff, 1);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_DONE ){
@ -3144,11 +3144,11 @@ static PgHdr *pager_get_all_dirty_pages(Pager *pPager){
** is hot. The pager_playback() routine will discover that the
** journal file is not really hot and will no-op.
*/
static int hasHotJournal(Pager *pPager){
static int hasHotJournal(Pager *pPager, int *pExists){
sqlite3_vfs *pVfs = pPager->pVfs;
int res = 0;
int rc = SQLITE_OK;
*pExists = 0;
if( pPager->useJournal && pPager->fd->pMethods ){
int rc;
int exists;
int locked;
@ -3160,16 +3160,17 @@ static int hasHotJournal(Pager *pPager){
if( rc==SQLITE_OK && exists && !locked ){
int nPage;
rc = sqlite3PagerPagecount(pPager, &nPage);
if( rc==SQLITE_OK && nPage==0 ){
sqlite3OsDelete(pVfs, pPager->zJournal, 0);
exists = 0;
if( rc==SQLITE_OK ){
if( nPage==0 ){
sqlite3OsDelete(pVfs, pPager->zJournal, 0);
}else{
*pExists = 1;
}
}
}
res = (rc!=SQLITE_OK ? -1 : (exists && !locked));
}
return res;
return rc;
}
/*
@ -3435,7 +3436,7 @@ static int readDbPage(Pager *pPager, PgHdr *pPg, Pgno pgno){
*/
static int pagerSharedLock(Pager *pPager){
int rc = SQLITE_OK;
int isHot = 0;
int isErrorReset = 0;
/* If this database is opened for exclusive access, has no outstanding
** page references and is in an error-state, now is the chance to clear
@ -3444,7 +3445,7 @@ static int pagerSharedLock(Pager *pPager){
*/
if( !MEMDB && pPager->exclusiveMode && pPager->nRef==0 && pPager->errCode ){
if( pPager->journalOpen ){
isHot = 1;
isErrorReset = 1;
}
pPager->errCode = SQLITE_OK;
pager_reset(pPager);
@ -3458,9 +3459,10 @@ static int pagerSharedLock(Pager *pPager){
return pPager->errCode;
}
if( pPager->state==PAGER_UNLOCK || isHot ){
if( pPager->state==PAGER_UNLOCK || isErrorReset ){
sqlite3_vfs *pVfs = pPager->pVfs;
if( !MEMDB ){
int isHotJournal;
assert( pPager->nRef==0 );
if( !pPager->noReadlock ){
rc = pager_wait_on_lock(pPager, SHARED_LOCK);
@ -3474,12 +3476,13 @@ static int pagerSharedLock(Pager *pPager){
/* If a journal file exists, and there is no RESERVED lock on the
** database file, then it either needs to be played back or deleted.
*/
rc = hasHotJournal(pPager);
if( rc<0 ){
rc = SQLITE_IOERR_NOMEM;
goto failed;
if( !isErrorReset ){
rc = hasHotJournal(pPager, &isHotJournal);
if( rc!=SQLITE_OK ){
goto failed;
}
}
if( rc==1 || isHot ){
if( isErrorReset || isHotJournal ){
/* Get an EXCLUSIVE lock on the database file. At this point it is
** important that a RESERVED lock is not obtained on the way to the
** EXCLUSIVE lock. If it were, another process might open the
@ -3506,7 +3509,7 @@ static int pagerSharedLock(Pager *pPager){
** OsTruncate() call used in exclusive-access mode also requires
** a read/write file handle.
*/
if( !isHot && pPager->journalOpen==0 ){
if( !isErrorReset && pPager->journalOpen==0 ){
int res;
rc = sqlite3OsAccess(pVfs,pPager->zJournal,SQLITE_ACCESS_EXISTS,&res);
if( rc==SQLITE_OK ){
@ -4577,6 +4580,9 @@ static int pager_incr_changecounter(Pager *pPager, int isDirect){
u32 change_counter;
int rc = SQLITE_OK;
#ifndef SQLITE_ENABLE_ATOMIC_WRITE
assert( isDirect==0 ); /* isDirect is only true for atomic writes */
#endif
if( !pPager->changeCountDone ){
/* Open page 1 of the file for writing. */
rc = sqlite3PagerGet(pPager, 1, &pPgHdr);
@ -4595,10 +4601,12 @@ static int pager_incr_changecounter(Pager *pPager, int isDirect){
change_counter++;
put32bits(((char*)PGHDR_TO_DATA(pPgHdr))+24, change_counter);
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
if( isDirect && pPager->fd->pMethods ){
const void *zBuf = PGHDR_TO_DATA(pPgHdr);
rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0);
}
#endif
/* Release the page reference. */
sqlite3PagerUnref(pPgHdr);
@ -5184,8 +5192,13 @@ void sqlite3PagerSetCodec(
** required that a statement transaction was not active, but this restriction
** has been removed (CREATE INDEX needs to move a page when a statement
** transaction is active).
**
** If the fourth argument, isCommit, is non-zero, then this page is being
** moved as part of a database reorganization just before the transaction
** is being committed. In this case, it is guaranteed that the database page
** pPg refers to will not be written to again within this transaction.
*/
int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno){
int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){
PgHdr *pPgOld; /* The page being overwritten. */
int h;
Pgno needSyncPgno = 0;
@ -5198,7 +5211,15 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno){
IOTRACE(("MOVE %p %d %d\n", pPager, pPg->pgno, pgno))
pager_get_content(pPg);
if( pPg->needSync ){
/* If the journal needs to be sync()ed before page pPg->pgno can
** be written to, store pPg->pgno in local variable needSyncPgno.
**
** If the isCommit flag is set, there is no need to remember that
** the journal needs to be sync()ed before database page pPg->pgno
** can be written to. The caller has already promised not to write to it.
*/
if( pPg->needSync && !isCommit ){
needSyncPgno = pPg->pgno;
assert( pPg->inJournal || (int)pgno>pPager->origDbSize );
assert( pPg->dirty );
@ -5245,8 +5266,9 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno){
/* If needSyncPgno is non-zero, then the journal file needs to be
** sync()ed before any data is written to database file page needSyncPgno.
** Currently, no such page exists in the page-cache and the
** Pager.pInJournal bit has been set. This needs to be remedied by loading
** the page into the pager-cache and setting the PgHdr.needSync flag.
** "is journaled" bitvec flag has been set. This needs to be remedied by
** loading the page into the pager-cache and setting the PgHdr.needSync
** flag.
**
** If the attempt to load the page into the page-cache fails, (due
** to a malloc() or IO failure), clear the bit in the pInJournal[]

View File

@ -13,7 +13,7 @@
** subsystem. The page cache subsystem reads and writes a file a page
** at a time and provides a journal for rollback.
**
** @(#) $Id: pager.h,v 1.76 2008/06/07 08:58:22 danielk1977 Exp $
** @(#) $Id: pager.h,v 1.77 2008/07/16 18:17:56 danielk1977 Exp $
*/
#ifndef _PAGER_H_
@ -105,7 +105,7 @@ sqlite3_file *sqlite3PagerFile(Pager*);
const char *sqlite3PagerDirname(Pager*);
const char *sqlite3PagerJournalname(Pager*);
int sqlite3PagerNosync(Pager*);
int sqlite3PagerMovepage(Pager*,DbPage*,Pgno);
int sqlite3PagerMovepage(Pager*,DbPage*,Pgno,int);
void *sqlite3PagerGetData(DbPage *);
void *sqlite3PagerGetExtra(DbPage *);
int sqlite3PagerLockingMode(Pager *, int);

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.245 2008/07/08 23:40:20 drh Exp $
** @(#) $Id: parse.y,v 1.248 2008/07/31 01:40:42 shane Exp $
*/
// All token codes are small integers with #defines that begin with "TK_"
@ -135,7 +135,7 @@ create_table_args ::= LP columnlist conslist_opt(X) RP(Y). {
}
create_table_args ::= AS select(S). {
sqlite3EndTable(pParse,0,0,S);
sqlite3SelectDelete(S);
sqlite3SelectDelete(pParse->db, S);
}
columnlist ::= columnlist COMMA column.
columnlist ::= column.
@ -362,13 +362,13 @@ cmd ::= DROP VIEW ifexists(E) fullname(X). {
cmd ::= select(X). {
SelectDest dest = {SRT_Callback, 0, 0, 0, 0};
sqlite3Select(pParse, X, &dest, 0, 0, 0);
sqlite3SelectDelete(X);
sqlite3SelectDelete(pParse->db, X);
}
%type select {Select*}
%destructor select {sqlite3SelectDelete($$);}
%destructor select {sqlite3SelectDelete(pParse->db, $$);}
%type oneselect {Select*}
%destructor oneselect {sqlite3SelectDelete($$);}
%destructor oneselect {sqlite3SelectDelete(pParse->db, $$);}
select(A) ::= oneselect(X). {A = X;}
%ifndef SQLITE_OMIT_COMPOUND_SELECT
@ -377,7 +377,7 @@ select(A) ::= select(X) multiselect_op(Y) oneselect(Z). {
Z->op = Y;
Z->pPrior = X;
}else{
sqlite3SelectDelete(X);
sqlite3SelectDelete(pParse->db, X);
}
A = Z;
}
@ -405,9 +405,9 @@ distinct(A) ::= . {A = 0;}
// opcode of TK_ALL.
//
%type selcollist {ExprList*}
%destructor selcollist {sqlite3ExprListDelete($$);}
%destructor selcollist {sqlite3ExprListDelete(pParse->db, $$);}
%type sclp {ExprList*}
%destructor sclp {sqlite3ExprListDelete($$);}
%destructor sclp {sqlite3ExprListDelete(pParse->db, $$);}
sclp(A) ::= selcollist(X) COMMA. {A = X;}
sclp(A) ::= . {A = 0;}
selcollist(A) ::= sclp(P) expr(X) as(Y). {
@ -417,8 +417,8 @@ selcollist(A) ::= sclp(P) STAR. {
Expr *p = sqlite3PExpr(pParse, TK_ALL, 0, 0, 0);
A = sqlite3ExprListAppend(pParse, P, p, 0);
}
selcollist(A) ::= sclp(P) nm(X) DOT STAR. {
Expr *pRight = sqlite3PExpr(pParse, TK_ALL, 0, 0, 0);
selcollist(A) ::= sclp(P) nm(X) DOT STAR(Y). {
Expr *pRight = sqlite3PExpr(pParse, TK_ALL, 0, 0, &Y);
Expr *pLeft = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);
Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0);
A = sqlite3ExprListAppend(pParse,P, pDot, 0);
@ -434,11 +434,11 @@ as(X) ::= . {X.n = 0;}
%type seltablist {SrcList*}
%destructor seltablist {sqlite3SrcListDelete($$);}
%destructor seltablist {sqlite3SrcListDelete(pParse->db, $$);}
%type stl_prefix {SrcList*}
%destructor stl_prefix {sqlite3SrcListDelete($$);}
%destructor stl_prefix {sqlite3SrcListDelete(pParse->db, $$);}
%type from {SrcList*}
%destructor from {sqlite3SrcListDelete($$);}
%destructor from {sqlite3SrcListDelete(pParse->db, $$);}
// A complete FROM clause.
//
@ -470,7 +470,7 @@ seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) on_opt(N) using_opt(U). {
// a grouping of table and subqueries.
//
%type seltablist_paren {Select*}
%destructor seltablist_paren {sqlite3SelectDelete($$);}
%destructor seltablist_paren {sqlite3SelectDelete(pParse->db, $$);}
seltablist_paren(A) ::= select(S). {A = S;}
seltablist_paren(A) ::= seltablist(F). {
sqlite3SrcListShiftJoinType(F);
@ -483,7 +483,7 @@ dbnm(A) ::= . {A.z=0; A.n=0;}
dbnm(A) ::= DOT nm(X). {A = X;}
%type fullname {SrcList*}
%destructor fullname {sqlite3SrcListDelete($$);}
%destructor fullname {sqlite3SrcListDelete(pParse->db, $$);}
fullname(A) ::= nm(X) dbnm(Y). {A = sqlite3SrcListAppend(pParse->db,0,&X,&Y);}
%type joinop {int}
@ -495,22 +495,22 @@ joinop(X) ::= JOIN_KW(A) nm(B) nm(C) JOIN.
{ X = sqlite3JoinType(pParse,&A,&B,&C); }
%type on_opt {Expr*}
%destructor on_opt {sqlite3ExprDelete($$);}
%destructor on_opt {sqlite3ExprDelete(pParse->db, $$);}
on_opt(N) ::= ON expr(E). {N = E;}
on_opt(N) ::= . {N = 0;}
%type using_opt {IdList*}
%destructor using_opt {sqlite3IdListDelete($$);}
%destructor using_opt {sqlite3IdListDelete(pParse->db, $$);}
using_opt(U) ::= USING LP inscollist(L) RP. {U = L;}
using_opt(U) ::= . {U = 0;}
%type orderby_opt {ExprList*}
%destructor orderby_opt {sqlite3ExprListDelete($$);}
%destructor orderby_opt {sqlite3ExprListDelete(pParse->db, $$);}
%type sortlist {ExprList*}
%destructor sortlist {sqlite3ExprListDelete($$);}
%destructor sortlist {sqlite3ExprListDelete(pParse->db, $$);}
%type sortitem {Expr*}
%destructor sortitem {sqlite3ExprDelete($$);}
%destructor sortitem {sqlite3ExprDelete(pParse->db, $$);}
orderby_opt(A) ::= . {A = 0;}
orderby_opt(A) ::= ORDER BY sortlist(X). {A = X;}
@ -531,12 +531,12 @@ sortorder(A) ::= DESC. {A = SQLITE_SO_DESC;}
sortorder(A) ::= . {A = SQLITE_SO_ASC;}
%type groupby_opt {ExprList*}
%destructor groupby_opt {sqlite3ExprListDelete($$);}
%destructor groupby_opt {sqlite3ExprListDelete(pParse->db, $$);}
groupby_opt(A) ::= . {A = 0;}
groupby_opt(A) ::= GROUP BY nexprlist(X). {A = X;}
%type having_opt {Expr*}
%destructor having_opt {sqlite3ExprDelete($$);}
%destructor having_opt {sqlite3ExprDelete(pParse->db, $$);}
having_opt(A) ::= . {A = 0;}
having_opt(A) ::= HAVING expr(X). {A = X;}
@ -550,8 +550,8 @@ having_opt(A) ::= HAVING expr(X). {A = X;}
// except as a transient. So there is never anything to destroy.
//
//%destructor limit_opt {
// sqlite3ExprDelete($$.pLimit);
// sqlite3ExprDelete($$.pOffset);
// sqlite3ExprDelete(pParse->db, $$.pLimit);
// sqlite3ExprDelete(pParse->db, $$.pOffset);
//}
limit_opt(A) ::= . {A.pLimit = 0; A.pOffset = 0;}
limit_opt(A) ::= LIMIT expr(X). {A.pLimit = X; A.pOffset = 0;}
@ -565,7 +565,7 @@ limit_opt(A) ::= LIMIT expr(X) COMMA expr(Y).
cmd ::= DELETE FROM fullname(X) where_opt(Y). {sqlite3DeleteFrom(pParse,X,Y);}
%type where_opt {Expr*}
%destructor where_opt {sqlite3ExprDelete($$);}
%destructor where_opt {sqlite3ExprDelete(pParse->db, $$);}
where_opt(A) ::= . {A = 0;}
where_opt(A) ::= WHERE expr(X). {A = X;}
@ -578,7 +578,7 @@ cmd ::= UPDATE orconf(R) fullname(X) SET setlist(Y) where_opt(Z). {
}
%type setlist {ExprList*}
%destructor setlist {sqlite3ExprListDelete($$);}
%destructor setlist {sqlite3ExprListDelete(pParse->db, $$);}
setlist(A) ::= setlist(Z) COMMA nm(X) EQ expr(Y).
{A = sqlite3ExprListAppend(pParse,Z,Y,&X);}
@ -601,7 +601,7 @@ insert_cmd(A) ::= REPLACE. {A = OE_Replace;}
%type itemlist {ExprList*}
%destructor itemlist {sqlite3ExprListDelete($$);}
%destructor itemlist {sqlite3ExprListDelete(pParse->db, $$);}
itemlist(A) ::= itemlist(X) COMMA expr(Y).
{A = sqlite3ExprListAppend(pParse,X,Y,0);}
@ -609,9 +609,9 @@ itemlist(A) ::= expr(X).
{A = sqlite3ExprListAppend(pParse,0,X,0);}
%type inscollist_opt {IdList*}
%destructor inscollist_opt {sqlite3IdListDelete($$);}
%destructor inscollist_opt {sqlite3IdListDelete(pParse->db, $$);}
%type inscollist {IdList*}
%destructor inscollist {sqlite3IdListDelete($$);}
%destructor inscollist {sqlite3IdListDelete(pParse->db, $$);}
inscollist_opt(A) ::= . {A = 0;}
inscollist_opt(A) ::= LP inscollist(X) RP. {A = X;}
@ -624,9 +624,9 @@ inscollist(A) ::= nm(Y).
//
%type expr {Expr*}
%destructor expr {sqlite3ExprDelete($$);}
%destructor expr {sqlite3ExprDelete(pParse->db, $$);}
%type term {Expr*}
%destructor term {sqlite3ExprDelete($$);}
%destructor term {sqlite3ExprDelete(pParse->db, $$);}
expr(A) ::= term(X). {A = X;}
expr(A) ::= LP(B) expr(X) RP(E). {A = X; sqlite3ExprSpan(A,&B,&E); }
@ -702,7 +702,7 @@ likeop(A) ::= NOT LIKE_KW(X). {A.eOperator = X; A.not = 1;}
likeop(A) ::= MATCH(X). {A.eOperator = X; A.not = 0;}
likeop(A) ::= NOT MATCH(X). {A.eOperator = X; A.not = 1;}
%type escape {Expr*}
%destructor escape {sqlite3ExprDelete($$);}
%destructor escape {sqlite3ExprDelete(pParse->db, $$);}
escape(X) ::= ESCAPE expr(A). [ESCAPE] {X = A;}
escape(X) ::= . [ESCAPE] {X = 0;}
expr(A) ::= expr(X) likeop(OP) expr(Y) escape(E). [LIKE_KW] {
@ -760,7 +760,7 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
if( A ){
A->pList = pList;
}else{
sqlite3ExprListDelete(pList);
sqlite3ExprListDelete(pParse->db, pList);
}
if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0, 0);
sqlite3ExprSpan(A,&W->span,&Y->span);
@ -775,7 +775,7 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
A->pList = Y;
sqlite3ExprSetHeight(pParse, A);
}else{
sqlite3ExprListDelete(Y);
sqlite3ExprListDelete(pParse->db, Y);
}
if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0, 0);
sqlite3ExprSpan(A,&X->span,&E);
@ -786,7 +786,7 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
A->pSelect = X;
sqlite3ExprSetHeight(pParse, A);
}else{
sqlite3SelectDelete(X);
sqlite3SelectDelete(pParse->db, X);
}
sqlite3ExprSpan(A,&B,&E);
}
@ -796,7 +796,7 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
A->pSelect = Y;
sqlite3ExprSetHeight(pParse, A);
}else{
sqlite3SelectDelete(Y);
sqlite3SelectDelete(pParse->db, Y);
}
if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0, 0);
sqlite3ExprSpan(A,&X->span,&E);
@ -808,7 +808,7 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
A->pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0);
sqlite3ExprSetHeight(pParse, A);
}else{
sqlite3SrcListDelete(pSrc);
sqlite3SrcListDelete(pParse->db, pSrc);
}
if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0, 0);
sqlite3ExprSpan(A,&X->span,Z.z?&Z:&Y);
@ -820,7 +820,7 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
sqlite3ExprSpan(p,&B,&E);
sqlite3ExprSetHeight(pParse, A);
}else{
sqlite3SelectDelete(Y);
sqlite3SelectDelete(pParse->db, Y);
}
}
%endif SQLITE_OMIT_SUBQUERY
@ -832,12 +832,12 @@ expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). {
A->pList = Y;
sqlite3ExprSetHeight(pParse, A);
}else{
sqlite3ExprListDelete(Y);
sqlite3ExprListDelete(pParse->db, Y);
}
sqlite3ExprSpan(A, &C, &E);
}
%type case_exprlist {ExprList*}
%destructor case_exprlist {sqlite3ExprListDelete($$);}
%destructor case_exprlist {sqlite3ExprListDelete(pParse->db, $$);}
case_exprlist(A) ::= case_exprlist(X) WHEN expr(Y) THEN expr(Z). {
A = sqlite3ExprListAppend(pParse,X, Y, 0);
A = sqlite3ExprListAppend(pParse,A, Z, 0);
@ -847,18 +847,18 @@ case_exprlist(A) ::= WHEN expr(Y) THEN expr(Z). {
A = sqlite3ExprListAppend(pParse,A, Z, 0);
}
%type case_else {Expr*}
%destructor case_else {sqlite3ExprDelete($$);}
%destructor case_else {sqlite3ExprDelete(pParse->db, $$);}
case_else(A) ::= ELSE expr(X). {A = X;}
case_else(A) ::= . {A = 0;}
%type case_operand {Expr*}
%destructor case_operand {sqlite3ExprDelete($$);}
%destructor case_operand {sqlite3ExprDelete(pParse->db, $$);}
case_operand(A) ::= expr(X). {A = X;}
case_operand(A) ::= . {A = 0;}
%type exprlist {ExprList*}
%destructor exprlist {sqlite3ExprListDelete($$);}
%destructor exprlist {sqlite3ExprListDelete(pParse->db, $$);}
%type nexprlist {ExprList*}
%destructor nexprlist {sqlite3ExprListDelete($$);}
%destructor nexprlist {sqlite3ExprListDelete(pParse->db, $$);}
exprlist(A) ::= nexprlist(X). {A = X;}
exprlist(A) ::= . {A = 0;}
@ -882,9 +882,9 @@ uniqueflag(A) ::= UNIQUE. {A = OE_Abort;}
uniqueflag(A) ::= . {A = OE_None;}
%type idxlist {ExprList*}
%destructor idxlist {sqlite3ExprListDelete($$);}
%destructor idxlist {sqlite3ExprListDelete(pParse->db, $$);}
%type idxlist_opt {ExprList*}
%destructor idxlist_opt {sqlite3ExprListDelete($$);}
%destructor idxlist_opt {sqlite3ExprListDelete(pParse->db, $$);}
%type idxitem {Token}
idxlist_opt(A) ::= . {A = 0;}
@ -931,6 +931,7 @@ cmd ::= VACUUM nm. {sqlite3Vacuum(pParse);}
///////////////////////////// The PRAGMA command /////////////////////////////
//
%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);}
@ -943,6 +944,7 @@ cmd ::= PRAGMA nm(X) dbnm(Z). {sqlite3Pragma(pParse,&X,&Z,0,0);}
nmnum(A) ::= plus_num(X). {A = X;}
nmnum(A) ::= nm(X). {A = X;}
%endif SQLITE_OMIT_PRAGMA
%endif SQLITE_OMIT_PARSER
plus_num(A) ::= plus_opt number(X). {A = X;}
minus_num(A) ::= MINUS number(X). {A = X;}
number(A) ::= INTEGER|FLOAT(X). {A = X;}
@ -974,7 +976,7 @@ trigger_time(A) ::= INSTEAD OF. { A = TK_INSTEAD;}
trigger_time(A) ::= . { A = TK_BEFORE; }
%type trigger_event {struct TrigEvent}
%destructor trigger_event {sqlite3IdListDelete($$.b);}
%destructor trigger_event {sqlite3IdListDelete(pParse->db, $$.b);}
trigger_event(A) ::= DELETE|INSERT(OP). {A.a = @OP; A.b = 0;}
trigger_event(A) ::= UPDATE(OP). {A.a = @OP; A.b = 0;}
trigger_event(A) ::= UPDATE OF inscollist(X). {A.a = TK_UPDATE; A.b = X;}
@ -983,12 +985,12 @@ foreach_clause ::= .
foreach_clause ::= FOR EACH ROW.
%type when_clause {Expr*}
%destructor when_clause {sqlite3ExprDelete($$);}
%destructor when_clause {sqlite3ExprDelete(pParse->db, $$);}
when_clause(A) ::= . { A = 0; }
when_clause(A) ::= WHEN expr(X). { A = X; }
%type trigger_cmd_list {TriggerStep*}
%destructor trigger_cmd_list {sqlite3DeleteTriggerStep($$);}
%destructor trigger_cmd_list {sqlite3DeleteTriggerStep(pParse->db, $$);}
trigger_cmd_list(A) ::= trigger_cmd_list(Y) trigger_cmd(X) SEMI. {
if( Y ){
Y->pLast->pNext = X;
@ -1001,7 +1003,7 @@ trigger_cmd_list(A) ::= trigger_cmd_list(Y) trigger_cmd(X) SEMI. {
trigger_cmd_list(A) ::= . { A = 0; }
%type trigger_cmd {TriggerStep*}
%destructor trigger_cmd {sqlite3DeleteTriggerStep($$);}
%destructor trigger_cmd {sqlite3DeleteTriggerStep(pParse->db, $$);}
// UPDATE
trigger_cmd(A) ::= UPDATE orconf(R) nm(X) SET setlist(Y) where_opt(Z).
{ A = sqlite3TriggerUpdateStep(pParse->db, &X, Y, Z, R); }
@ -1061,7 +1063,7 @@ cmd ::= DETACH database_kw_opt expr(D). {
}
%type key_opt {Expr*}
%destructor key_opt {sqlite3ExprDelete($$);}
%destructor key_opt {sqlite3ExprDelete(pParse->db, $$);}
key_opt(A) ::= . { A = 0; }
key_opt(A) ::= KEY expr(X). { A = X; }

View File

@ -11,7 +11,7 @@
*************************************************************************
** This file contains code used to implement the PRAGMA command.
**
** $Id: pragma.c,v 1.182 2008/07/08 07:35:52 danielk1977 Exp $
** $Id: pragma.c,v 1.183 2008/07/28 19:34:53 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@ -682,8 +682,7 @@ void sqlite3Pragma(
}
sqlite3_free(sqlite3_temp_directory);
if( zRight[0] ){
sqlite3_temp_directory = zRight;
zRight = 0;
sqlite3_temp_directory = sqlite3DbStrDup(0, zRight);
}else{
sqlite3_temp_directory = 0;
}
@ -1323,8 +1322,8 @@ void sqlite3Pragma(
#endif
}
pragma_out:
sqlite3_free(zLeft);
sqlite3_free(zRight);
sqlite3DbFree(db, zLeft);
sqlite3DbFree(db, zRight);
}
#endif /* SQLITE_OMIT_PRAGMA || SQLITE_OMIT_PARSER */

View File

@ -13,7 +13,7 @@
** interface, and routines that contribute to loading the database schema
** from disk.
**
** $Id: prepare.c,v 1.89 2008/07/08 19:34:07 drh Exp $
** $Id: prepare.c,v 1.91 2008/08/02 03:50:39 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@ -32,7 +32,7 @@ static void corruptSchema(
sqlite3SetString(pData->pzErrMsg, pData->db,
"malformed database schema (%s)", zObj);
if( zExtra && zExtra[0] ){
*pData->pzErrMsg = sqlite3MPrintf(pData->db, "%z - %s",
*pData->pzErrMsg = sqlite3MAppendf(pData->db, *pData->pzErrMsg, "%s - %s",
*pData->pzErrMsg, zExtra);
}
}
@ -79,11 +79,15 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **azColName){
*/
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;
@ -92,7 +96,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **azColName){
}else if( rc!=SQLITE_INTERRUPT ){
corruptSchema(pData, argv[0], zErr);
}
sqlite3_free(zErr);
sqlite3DbFree(db, zErr);
return 1;
}
}else if( argv[0]==0 ){
@ -220,7 +224,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
rc = sqlite3BtreeCursor(pDb->pBt, MASTER_ROOT, 0, 0, curMain);
if( rc!=SQLITE_OK && rc!=SQLITE_EMPTY ){
sqlite3SetString(pzErrMsg, db, "%s", sqlite3ErrStr(rc));
goto leave_error_out;
goto initone_error_out;
}
/* Get the database meta information.
@ -242,12 +246,12 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
*/
if( rc==SQLITE_OK ){
int i;
for(i=0; rc==SQLITE_OK && i<sizeof(meta)/sizeof(meta[0]); i++){
for(i=0; i<sizeof(meta)/sizeof(meta[0]); i++){
rc = sqlite3BtreeGetMeta(pDb->pBt, i+1, (u32 *)&meta[i]);
}
if( rc ){
sqlite3SetString(pzErrMsg, db, "%s", sqlite3ErrStr(rc));
goto leave_error_out;
if( rc ){
sqlite3SetString(pzErrMsg, db, "%s", sqlite3ErrStr(rc));
goto initone_error_out;
}
}
}else{
memset(meta, 0, sizeof(meta));
@ -270,7 +274,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
sqlite3SetString(pzErrMsg, db, "attached databases must use the same"
" text encoding as main database");
rc = SQLITE_ERROR;
goto leave_error_out;
goto initone_error_out;
}
}
}else{
@ -299,7 +303,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
if( pDb->pSchema->file_format>SQLITE_MAX_FILE_FORMAT ){
sqlite3SetString(pzErrMsg, db, "unsupported file format");
rc = SQLITE_ERROR;
goto leave_error_out;
goto initone_error_out;
}
/* Ticket #2804: When we open a database in the newer file format,
@ -336,7 +340,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
#endif
if( rc==SQLITE_ABORT ) rc = initData.rc;
(void)sqlite3SafetyOn(db);
sqlite3_free(zSql);
sqlite3DbFree(db, zSql);
#ifndef SQLITE_OMIT_ANALYZE
if( rc==SQLITE_OK ){
sqlite3AnalysisLoad(db, iDb);
@ -364,7 +368,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
** curMain and calling sqlite3BtreeEnter(). For an error that occurs
** before that point, jump to error_out.
*/
leave_error_out:
initone_error_out:
sqlite3BtreeCloseCursor(curMain);
sqlite3_free(curMain);
sqlite3BtreeLeave(pDb->pBt);
@ -568,7 +572,7 @@ static int sqlite3Prepare(
zSqlCopy = sqlite3DbStrNDup(db, zSql, nBytes);
if( zSqlCopy ){
sqlite3RunParser(&sParse, zSqlCopy, &zErrMsg);
sqlite3_free(zSqlCopy);
sqlite3DbFree(db, zSqlCopy);
sParse.zTail = &zSql[sParse.zTail-zSqlCopy];
}else{
sParse.zTail = &zSql[nBytes];
@ -632,7 +636,7 @@ static int sqlite3Prepare(
if( zErrMsg ){
sqlite3Error(db, rc, "%s", zErrMsg);
sqlite3_free(zErrMsg);
sqlite3DbFree(db, zErrMsg);
}else{
sqlite3Error(db, rc, 0);
}
@ -767,7 +771,7 @@ static int sqlite3Prepare16(
int chars_parsed = sqlite3Utf8CharLen(zSql8, zTail8-zSql8);
*pzTail = (u8 *)zSql + sqlite3Utf16ByteLen(zSql, chars_parsed);
}
sqlite3_free(zSql8);
sqlite3DbFree(db, zSql8);
rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
return rc;

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.92 2008/07/15 00:27:35 drh Exp $
** $Id: printf.c,v 1.93 2008/07/28 19:34:53 drh Exp $
**
**************************************************************************
**
@ -746,7 +746,7 @@ void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
}else{
p->nAlloc = szNew;
}
zNew = sqlite3Malloc( p->nAlloc );
zNew = sqlite3DbMallocRaw(p->db, p->nAlloc );
if( zNew ){
memcpy(zNew, p->zText, p->nChar);
sqlite3StrAccumReset(p);
@ -771,7 +771,7 @@ char *sqlite3StrAccumFinish(StrAccum *p){
if( p->zText ){
p->zText[p->nChar] = 0;
if( p->useMalloc && p->zText==p->zBase ){
p->zText = sqlite3Malloc( p->nChar+1 );
p->zText = sqlite3DbMallocRaw(p->db, p->nChar+1 );
if( p->zText ){
memcpy(p->zText, p->zBase, p->nChar+1);
}else{
@ -787,7 +787,7 @@ char *sqlite3StrAccumFinish(StrAccum *p){
*/
void sqlite3StrAccumReset(StrAccum *p){
if( p->zText!=p->zBase ){
sqlite3_free(p->zText);
sqlite3DbFree(p->db, p->zText);
}
p->zText = 0;
}
@ -797,6 +797,7 @@ void sqlite3StrAccumReset(StrAccum *p){
*/
void sqlite3StrAccumInit(StrAccum *p, char *zBase, int n, int mx){
p->zText = p->zBase = zBase;
p->db = 0;
p->nChar = 0;
p->nAlloc = n;
p->mxAlloc = mx;
@ -815,6 +816,7 @@ char *sqlite3VMPrintf(sqlite3 *db, const char *zFormat, va_list ap){
StrAccum acc;
sqlite3StrAccumInit(&acc, zBase, sizeof(zBase),
db ? db->aLimit[SQLITE_LIMIT_LENGTH] : SQLITE_MAX_LENGTH);
acc.db = db;
sqlite3VXPrintf(&acc, 1, zFormat, ap);
z = sqlite3StrAccumFinish(&acc);
if( acc.mallocFailed && db ){
@ -836,6 +838,24 @@ char *sqlite3MPrintf(sqlite3 *db, const char *zFormat, ...){
return z;
}
/*
** Like sqlite3MPrintf(), but call sqlite3DbFree() on zStr after formatting
** the string and before returnning. This routine is intended to be used
** to modify an existing string. For example:
**
** x = sqlite3MPrintf(db, x, "prefix %s suffix", x);
**
*/
char *sqlite3MAppendf(sqlite3 *db, char *zStr, const char *zFormat, ...){
va_list ap;
char *z;
va_start(ap, zFormat);
z = sqlite3VMPrintf(db, zFormat, ap);
va_end(ap);
sqlite3DbFree(db, zStr);
return z;
}
/*
** Print into memory obtained from sqlite3_malloc(). Omit the internal
** %-conversion extensions.

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.457 2008/07/15 20:56:17 drh Exp $
** $Id: select.c,v 1.463 2008/08/04 03:51:24 danielk1977 Exp $
*/
#include "sqliteInt.h"
@ -21,16 +21,16 @@
** Delete all the content of a Select structure but do not deallocate
** the select structure itself.
*/
static void clearSelect(Select *p){
sqlite3ExprListDelete(p->pEList);
sqlite3SrcListDelete(p->pSrc);
sqlite3ExprDelete(p->pWhere);
sqlite3ExprListDelete(p->pGroupBy);
sqlite3ExprDelete(p->pHaving);
sqlite3ExprListDelete(p->pOrderBy);
sqlite3SelectDelete(p->pPrior);
sqlite3ExprDelete(p->pLimit);
sqlite3ExprDelete(p->pOffset);
static void clearSelect(sqlite3 *db, Select *p){
sqlite3ExprListDelete(db, p->pEList);
sqlite3SrcListDelete(db, p->pSrc);
sqlite3ExprDelete(db, p->pWhere);
sqlite3ExprListDelete(db, p->pGroupBy);
sqlite3ExprDelete(db, p->pHaving);
sqlite3ExprListDelete(db, p->pOrderBy);
sqlite3SelectDelete(db, p->pPrior);
sqlite3ExprDelete(db, p->pLimit);
sqlite3ExprDelete(db, p->pOffset);
}
/*
@ -88,7 +88,7 @@ Select *sqlite3SelectNew(
pNew->addrOpenEphm[1] = -1;
pNew->addrOpenEphm[2] = -1;
if( pNew==&standin) {
clearSelect(pNew);
clearSelect(db, pNew);
pNew = 0;
}
return pNew;
@ -97,10 +97,10 @@ Select *sqlite3SelectNew(
/*
** Delete the given Select structure and all of its substructures.
*/
void sqlite3SelectDelete(Select *p){
void sqlite3SelectDelete(sqlite3 *db, Select *p){
if( p ){
clearSelect(p);
sqlite3_free(p);
clearSelect(db, p);
sqlite3DbFree(db, p);
}
}
@ -1163,12 +1163,14 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
if( pTab==0 ){
return 0;
}
pTab->db = db;
pTab->nRef = 1;
pTab->zName = zTabName ? sqlite3DbStrDup(db, zTabName) : 0;
pEList = pSelect->pEList;
pTab->nCol = pEList->nExpr;
assert( pTab->nCol>0 );
pTab->aCol = aCol = sqlite3DbMallocZero(db, sizeof(pTab->aCol[0])*pTab->nCol);
testcase( aCol==0 );
for(i=0, pCol=aCol; i<pTab->nCol; i++, pCol++){
Expr *p;
char *zType;
@ -1194,11 +1196,9 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
/* Use the original text of the column expression as its name */
zName = sqlite3MPrintf(db, "%T", &p->span);
}
if( !zName || db->mallocFailed ){
db->mallocFailed = 1;
sqlite3_free(zName);
sqlite3DeleteTable(pTab);
return 0;
if( db->mallocFailed ){
sqlite3DbFree(db, zName);
break;
}
sqlite3Dequote(zName);
@ -1208,8 +1208,11 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
nName = strlen(zName);
for(j=cnt=0; j<i; j++){
if( sqlite3StrICmp(aCol[j].zName, zName)==0 ){
char *zNewName;
zName[nName] = 0;
zName = sqlite3MPrintf(db, "%z:%d", zName, ++cnt);
zNewName = sqlite3MPrintf(db, "%s:%d", zName, ++cnt);
sqlite3DbFree(db, zName);
zName = zNewName;
j = -1;
if( zName==0 ) break;
}
@ -1230,6 +1233,10 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
}
}
pTab->iPKey = -1;
if( db->mallocFailed ){
sqlite3DeleteTable(pTab);
return 0;
}
return pTab;
}
@ -1471,10 +1478,10 @@ static int prepSelectStmt(Parse *pParse, Select *p){
}
rc = 1;
}
sqlite3_free(zTName);
sqlite3DbFree(db, zTName);
}
}
sqlite3ExprListDelete(pEList);
sqlite3ExprListDelete(db, pEList);
p->pEList = pNew;
}
#if SQLITE_MAX_COLUMN
@ -1535,11 +1542,11 @@ static int matchOrderByTermToExprList(
for(i=0; i<pEList->nExpr; i++){
char *zAs = pEList->a[i].zName;
if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){
sqlite3_free(zCol);
sqlite3DbFree(db, zCol);
return i+1;
}
}
sqlite3_free(zCol);
sqlite3DbFree(db, zCol);
}
/* Resolve all names in the ORDER BY term expression
@ -1628,7 +1635,7 @@ static int processOrderGroupBy(
if( iCol>0 ){
CollSeq *pColl = pE->pColl;
int flags = pE->flags & EP_ExpCollate;
sqlite3ExprDelete(pE);
sqlite3ExprDelete(db, pE);
pE = sqlite3ExprDup(db, pEList->a[iCol-1].pExpr);
pOrderBy->a[i].pExpr = pE;
if( pE && pColl && flags ){
@ -1699,7 +1706,7 @@ static int processCompoundOrderBy(
assert(pDup);
iCol = matchOrderByTermToExprList(pParse, pSelect, pDup, i+1, 1, 0);
}
sqlite3ExprDelete(pDup);
sqlite3ExprDelete(db, pDup);
if( iCol<0 ){
return 1;
}
@ -1879,14 +1886,13 @@ static int multiSelect(
Vdbe *v; /* Generate code to this VDBE */
SelectDest dest; /* Alternative data destination */
Select *pDelete = 0; /* Chain of simple selects to delete */
sqlite3 *db; /* Database connection */
/* Make sure there is no ORDER BY or LIMIT clause on prior SELECTs. Only
** the last (right-most) SELECT in the series may have an ORDER BY or LIMIT.
*/
if( p==0 || p->pPrior==0 ){
rc = 1;
goto multi_select_end;
}
assert( p && p->pPrior ); /* Calling function guarantees this much */
db = pParse->db;
pPrior = p->pPrior;
assert( pPrior->pRightmost!=pPrior );
assert( pPrior->pRightmost==p->pRightmost );
@ -1903,13 +1909,8 @@ static int multiSelect(
goto multi_select_end;
}
/* Make sure we have a valid query engine. If not, create a new one.
*/
v = sqlite3GetVdbe(pParse);
if( v==0 ){
rc = 1;
goto multi_select_end;
}
assert( v!=0 ); /* The VDBE already created by calling function */
/* Create the destination temporary table if necessary
*/
@ -2008,10 +2009,11 @@ static int multiSelect(
/* Code the current SELECT statement
*/
switch( p->op ){
case TK_EXCEPT: op = SRT_Except; break;
case TK_UNION: op = SRT_Union; break;
case TK_ALL: op = SRT_Table; break;
if( p->op==TK_EXCEPT ){
op = SRT_Except;
}else{
assert( p->op==TK_UNION );
op = SRT_Union;
}
p->pPrior = 0;
p->disallowOrderBy = 0;
@ -2023,11 +2025,11 @@ static int multiSelect(
rc = sqlite3Select(pParse, p, &uniondest, 0, 0, 0);
/* Query flattening in sqlite3Select() might refill p->pOrderBy.
** Be sure to delete p->pOrderBy, therefore, to avoid a memory leak. */
sqlite3ExprListDelete(p->pOrderBy);
sqlite3ExprListDelete(db, p->pOrderBy);
pDelete = p->pPrior;
p->pPrior = pPrior;
p->pOrderBy = 0;
sqlite3ExprDelete(p->pLimit);
sqlite3ExprDelete(db, p->pLimit);
p->pLimit = pLimit;
p->pOffset = pOffset;
p->iLimit = 0;
@ -2106,7 +2108,7 @@ static int multiSelect(
rc = sqlite3Select(pParse, p, &intersectdest, 0, 0, 0);
pDelete = p->pPrior;
p->pPrior = pPrior;
sqlite3ExprDelete(p->pLimit);
sqlite3ExprDelete(db, p->pLimit);
p->pLimit = pLimit;
p->pOffset = pOffset;
if( rc ){
@ -2159,20 +2161,20 @@ static int multiSelect(
assert( p->pRightmost==p );
nCol = p->pEList->nExpr;
pKeyInfo = sqlite3DbMallocZero(pParse->db,
pKeyInfo = sqlite3DbMallocZero(db,
sizeof(*pKeyInfo)+nCol*(sizeof(CollSeq*) + 1));
if( !pKeyInfo ){
rc = SQLITE_NOMEM;
goto multi_select_end;
}
pKeyInfo->enc = ENC(pParse->db);
pKeyInfo->enc = ENC(db);
pKeyInfo->nField = nCol;
for(i=0, apColl=pKeyInfo->aColl; i<nCol; i++, apColl++){
*apColl = multiSelectCollSeq(pParse, p, i);
if( 0==*apColl ){
*apColl = pParse->db->pDfltColl;
*apColl = db->pDfltColl;
}
}
@ -2190,13 +2192,13 @@ static int multiSelect(
pLoop->addrOpenEphm[i] = -1;
}
}
sqlite3_free(pKeyInfo);
sqlite3DbFree(db, pKeyInfo);
}
multi_select_end:
pDest->iMem = dest.iMem;
pDest->nMem = dest.nMem;
sqlite3SelectDelete(pDelete);
sqlite3SelectDelete(db, pDelete);
return rc;
}
#endif /* SQLITE_OMIT_COMPOUND_SELECT */
@ -2445,6 +2447,7 @@ static int generateOutputSubroutine(
** until all data is exhausted then jump to the "end" labe. AltB, AeqB,
** and AgtB jump to either L2 or to one of EofA or EofB.
*/
#ifndef SQLITE_OMIT_COMPOUND_SELECT
static int multiSelectOrderBy(
Parse *pParse, /* Parsing context */
Select *p, /* The right-most of SELECTs to be coded */
@ -2619,9 +2622,9 @@ static int multiSelectOrderBy(
}else{
regLimitA = regLimitB = 0;
}
sqlite3ExprDelete(p->pLimit);
sqlite3ExprDelete(db, p->pLimit);
p->pLimit = 0;
sqlite3ExprDelete(p->pOffset);
sqlite3ExprDelete(db, p->pOffset);
p->pOffset = 0;
regAddrA = ++pParse->nMem;
@ -2783,7 +2786,7 @@ static int multiSelectOrderBy(
/* Reassembly the compound query so that it will be freed correctly
** by the calling function */
if( p->pPrior ){
sqlite3SelectDelete(p->pPrior);
sqlite3SelectDelete(db, p->pPrior);
}
p->pPrior = pPrior;
@ -2791,8 +2794,9 @@ static int multiSelectOrderBy(
**** subqueries ****/
return SQLITE_OK;
}
#endif
#ifndef SQLITE_OMIT_VIEW
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
/* Forward Declarations */
static void substExprList(sqlite3*, ExprList*, int, ExprList*);
static void substSelect(sqlite3*, Select *, int, ExprList *);
@ -2875,9 +2879,9 @@ static void substSelect(
substExpr(db, p->pWhere, iTable, pEList);
substSelect(db, p->pPrior, iTable, pEList);
}
#endif /* !defined(SQLITE_OMIT_VIEW) */
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
#ifndef SQLITE_OMIT_VIEW
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
/*
** This routine attempts to flatten subqueries in order to speed
** execution. It returns 1 if it makes changes and 0 if no flattening
@ -3152,9 +3156,9 @@ static int flattenSubquery(
nSubSrc = pSubSrc->nSrc;
jointype = pSubitem->jointype;
sqlite3DeleteTable(pSubitem->pTab);
sqlite3_free(pSubitem->zDatabase);
sqlite3_free(pSubitem->zName);
sqlite3_free(pSubitem->zAlias);
sqlite3DbFree(db, pSubitem->zDatabase);
sqlite3DbFree(db, pSubitem->zName);
sqlite3DbFree(db, pSubitem->zAlias);
pSubitem->pTab = 0;
pSubitem->zDatabase = 0;
pSubitem->zName = 0;
@ -3251,11 +3255,11 @@ static int flattenSubquery(
/* Finially, delete what is left of the subquery and return
** success.
*/
sqlite3SelectDelete(pSub1);
sqlite3SelectDelete(db, pSub1);
return 1;
}
#endif /* SQLITE_OMIT_VIEW */
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
/*
** Analyze the SELECT statement passed as an argument to see if it
@ -3522,33 +3526,6 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
pAggInfo->directMode = 0;
}
#if 0
/*
** This function is used when a SELECT statement is used to create a
** temporary table for iterating through when running an INSTEAD OF
** UPDATE or INSTEAD OF DELETE trigger.
**
** If possible, the SELECT statement is modified so that NULL values
** are stored in the temporary table for all columns for which the
** corresponding bit in argument mask is not set. If mask takes the
** special value 0xffffffff, then all columns are populated.
*/
void sqlite3SelectMask(Parse *pParse, Select *p, u32 mask){
if( p && !p->pPrior && !p->isDistinct && mask!=0xffffffff ){
ExprList *pEList;
int i;
sqlite3SelectResolve(pParse, p, 0);
pEList = p->pEList;
for(i=0; pEList && i<pEList->nExpr && i<32; i++){
if( !(mask&((u32)1<<i)) ){
sqlite3ExprDelete(pEList->a[i].pExpr);
pEList->a[i].pExpr = sqlite3Expr(pParse->db, TK_NULL, 0, 0, 0);
}
}
}
}
#endif
/*
** Generate code for the given SELECT statement.
**
@ -4017,12 +3994,20 @@ int sqlite3Select(
struct AggInfo_col *pCol = &sAggInfo.aCol[i];
if( pCol->iSorterColumn>=j ){
int r1 = j + regBase;
int r2 = sqlite3ExprCodeGetColumn(pParse,
#ifndef NDEBUG
int r2 =
#endif
sqlite3ExprCodeGetColumn(pParse,
pCol->pTab, pCol->iColumn, pCol->iTable, r1, 0);
if( r1!=r2 ){
sqlite3VdbeAddOp2(v, OP_SCopy, r2, r1);
}
j++;
/* sAggInfo.aCol[] only contains one entry per column. So
** The reference to pCol->iColumn,pCol->iTable must have been
** the first reference to that column. Hence,
** sqliteExprCodeGetColumn is guaranteed to put the result in
** the column requested.
*/
assert( r1==r2 );
}
}
regRecord = sqlite3GetTempReg(pParse);
@ -4141,7 +4126,7 @@ int sqlite3Select(
resetAccumulator(pParse, &sAggInfo);
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pMinMax, flag);
if( pWInfo==0 ){
sqlite3ExprListDelete(pDel);
sqlite3ExprListDelete(db, pDel);
goto select_end;
}
updateAccumulator(pParse, &sAggInfo);
@ -4158,7 +4143,7 @@ int sqlite3Select(
selectInnerLoop(pParse, p, p->pEList, 0, 0, 0, -1,
pDest, addrEnd, addrEnd);
sqlite3ExprListDelete(pDel);
sqlite3ExprListDelete(db, pDel);
}
sqlite3VdbeResolveLabel(v, addrEnd);
@ -4205,8 +4190,8 @@ select_end:
generateColumnNames(pParse, pTabList, pEList);
}
sqlite3_free(sAggInfo.aCol);
sqlite3_free(sAggInfo.aFunc);
sqlite3DbFree(db, sAggInfo.aCol);
sqlite3DbFree(db, sAggInfo.aFunc);
return rc;
}

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.742 2008/07/12 14:52:20 drh Exp $
** @(#) $Id: sqliteInt.h,v 1.752 2008/08/04 20:13:27 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
@ -36,7 +36,9 @@
#endif
/* Needed for various definitions... */
#define _GNU_SOURCE
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
/*
** Include standard header files as necessary
@ -430,6 +432,12 @@ struct BusyHandler {
*/
#define ArraySize(X) (sizeof(X)/sizeof(X[0]))
/*
** The following value as a destructor means to use sqlite3DbFree().
** This is an internal extension to SQLITE_STATIC and SQLITE_TRANSIENT.
*/
#define SQLITE_DYNAMIC ((sqlite3_destructor_type)sqlite3DbFree)
/*
** Forward references to structures
*/
@ -448,6 +456,8 @@ typedef struct IdList IdList;
typedef struct Index Index;
typedef struct KeyClass KeyClass;
typedef struct KeyInfo KeyInfo;
typedef struct Lookaside Lookaside;
typedef struct LookasideSlot LookasideSlot;
typedef struct Module Module;
typedef struct NameContext NameContext;
typedef struct Parse Parse;
@ -549,6 +559,33 @@ struct Schema {
*/
#define SQLITE_N_LIMIT (SQLITE_LIMIT_VARIABLE_NUMBER+1)
/*
** Lookaside malloc is a set of fixed-size buffers that can be used
** to satisify small transient memory allocation requests for objects
** associated with a particular database connection. The use of
** lookaside malloc provides a significant performance enhancement
** (approx 10%) by avoiding numerous malloc/free requests while parsing
** SQL statements.
**
** The Lookaside structure holds configuration information about the
** lookaside malloc subsystem. Each available memory allocation in
** the lookaside subsystem is stored on a linked list of LookasideSlot
** objects.
*/
struct Lookaside {
u16 sz; /* Size of each buffer in bytes */
u8 bEnabled; /* True if use lookaside. False to ignore it */
u8 bMalloced; /* True if pStart obtained from sqlite3_malloc() */
int nOut; /* Number of buffers currently checked out */
int mxOut; /* Highwater mark for nOut */
LookasideSlot *pFree; /* List if available buffers */
void *pStart; /* First byte of available memory space */
void *pEnd; /* First byte past end of available space */
};
struct LookasideSlot {
LookasideSlot *pNext; /* Next buffer in the list of free buffers */
};
/*
** Each database is an instance of the following structure.
**
@ -628,6 +665,7 @@ struct sqlite3 {
int isInterrupted; /* True if sqlite3_interrupt has been called */
double notUsed1; /* Spacer */
} u1;
Lookaside lookaside; /* Lookaside malloc configuration */
#ifndef SQLITE_OMIT_AUTHORIZATION
int (*xAuth)(void*,int,const char*,const char*,const char*,const char*);
/* Access authorization function */
@ -867,6 +905,7 @@ struct CollSeq {
** of a SELECT statement.
*/
struct Table {
sqlite3 *db; /* Associated database connection. Might be NULL. */
char *zName; /* Name of the table */
int nCol; /* Number of columns in this table */
Column *aCol; /* Information about each column */
@ -1744,10 +1783,11 @@ struct DbFixer {
** do not necessarily know how big the string will be in the end.
*/
struct StrAccum {
char *zBase; /* A base allocation. Not from malloc. */
char *zText; /* The string collected so far */
int nChar; /* Length of the string so far */
int nAlloc; /* Amount of space allocated in zText */
sqlite3 *db; /* Optional database for lookaside. Can be NULL */
char *zBase; /* A base allocation. Not from malloc. */
char *zText; /* The string collected so far */
int nChar; /* Length of the string so far */
int nAlloc; /* Amount of space allocated in zText */
int mxAlloc; /* Maximum allowed string length */
u8 mallocFailed; /* Becomes true if any memory allocation fails */
u8 useMalloc; /* True if zText is enlargable using realloc */
@ -1775,6 +1815,8 @@ struct Sqlite3Config {
int bCoreMutex; /* True to enable core mutexing */
int bFullMutex; /* True to enable full mutexing */
int mxStrlen; /* Maximum string length */
int szLookaside; /* Default lookaside buffer size */
int nLookaside; /* Default lookaside buffer count */
sqlite3_mem_methods m; /* Low-level memory allocation interface */
sqlite3_mutex_methods mutex; /* Low-level mutex interface */
void *pHeap; /* Heap storage space */
@ -1789,6 +1831,8 @@ struct Sqlite3Config {
int isInit; /* True after initialization has finished */
int isMallocInit; /* True after malloc is initialized */
sqlite3_mutex *pInitMutex; /* Mutex used by sqlite3_initialize() */
int nSmall; /* alloc size threshold used by mem6.c */
int mxParserStack; /* maximum depth of the parser stack */
};
/*
@ -1828,21 +1872,23 @@ void *sqlite3Malloc(int);
void *sqlite3MallocZero(int);
void *sqlite3DbMallocZero(sqlite3*, int);
void *sqlite3DbMallocRaw(sqlite3*, int);
char *sqlite3StrDup(const char*);
char *sqlite3StrNDup(const char*, int);
char *sqlite3DbStrDup(sqlite3*,const char*);
char *sqlite3DbStrNDup(sqlite3*,const char*, int);
void *sqlite3Realloc(void*, int);
void *sqlite3DbReallocOrFree(sqlite3 *, void *, int);
void *sqlite3DbRealloc(sqlite3 *, void *, int);
int sqlite3MallocSize(void *);
void sqlite3DbFree(sqlite3*, void*);
int sqlite3MallocSize(void*);
int sqlite3DbMallocSize(sqlite3*, void*);
void *sqlite3ScratchMalloc(int);
void sqlite3ScratchFree(void*);
void *sqlite3PageMalloc(int);
void sqlite3PageFree(void*);
void sqlite3MemSetDefault(void);
const sqlite3_mem_methods *sqlite3MemGetDefault(void);
const sqlite3_mem_methods *sqlite3MemGetMemsys5(void);
const sqlite3_mem_methods *sqlite3MemGetMemsys3(void);
const sqlite3_mem_methods *sqlite3MemGetMemsys6(void);
void sqlite3BenignMallocHooks(void (*)(void), void (*)(void));
#ifndef SQLITE_MUTEX_NOOP
@ -1862,6 +1908,7 @@ int sqlite3IsNaN(double);
void sqlite3VXPrintf(StrAccum*, int, const char*, va_list);
char *sqlite3MPrintf(sqlite3*,const char*, ...);
char *sqlite3VMPrintf(sqlite3*,const char*, va_list);
char *sqlite3MAppendf(sqlite3*,char*,const char*,...);
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
void sqlite3DebugPrintf(const char*, ...);
#endif
@ -1887,9 +1934,9 @@ Expr *sqlite3ExprAnd(sqlite3*,Expr*, Expr*);
void sqlite3ExprSpan(Expr*,Token*,Token*);
Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*);
void sqlite3ExprAssignVarNumber(Parse*, Expr*);
void sqlite3ExprDelete(Expr*);
void sqlite3ExprDelete(sqlite3*, Expr*);
ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*,Token*);
void sqlite3ExprListDelete(ExprList*);
void sqlite3ExprListDelete(sqlite3*, ExprList*);
int sqlite3Init(sqlite3*, char**);
int sqlite3InitCallback(void*, int, char**, char**);
void sqlite3Pragma(Parse*,Token*,Token*,Token*,int);
@ -1934,15 +1981,15 @@ SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*, Token*,
Select*, Expr*, IdList*);
void sqlite3SrcListShiftJoinType(SrcList*);
void sqlite3SrcListAssignCursors(Parse*, SrcList*);
void sqlite3IdListDelete(IdList*);
void sqlite3SrcListDelete(SrcList*);
void sqlite3IdListDelete(sqlite3*, IdList*);
void sqlite3SrcListDelete(sqlite3*, SrcList*);
void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*,
Token*, int, int);
void sqlite3DropIndex(Parse*, SrcList*, int);
int sqlite3Select(Parse*, Select*, SelectDest*, Select*, int, int*);
Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*,
Expr*,ExprList*,int,Expr*,Expr*);
void sqlite3SelectDelete(Select*);
void sqlite3SelectDelete(sqlite3*, Select*);
Table *sqlite3SrcListLookup(Parse*, SrcList*);
int sqlite3IsReadOnly(Parse*, Table*, int);
void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
@ -2031,17 +2078,17 @@ void sqlite3MaterializeView(Parse*, Select*, Expr*, int);
int sqlite3CodeRowTrigger(Parse*, int, ExprList*, int, Table *, int, int,
int, int, u32*, u32*);
void sqliteViewTriggers(Parse*, Table*, Expr*, int, ExprList*);
void sqlite3DeleteTriggerStep(TriggerStep*);
void sqlite3DeleteTriggerStep(sqlite3*, TriggerStep*);
TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*);
TriggerStep *sqlite3TriggerInsertStep(sqlite3*,Token*, IdList*,
ExprList*,Select*,int);
TriggerStep *sqlite3TriggerUpdateStep(sqlite3*,Token*,ExprList*, Expr*, int);
TriggerStep *sqlite3TriggerDeleteStep(sqlite3*,Token*, Expr*);
void sqlite3DeleteTrigger(Trigger*);
void sqlite3DeleteTrigger(sqlite3*, Trigger*);
void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*);
#else
# define sqlite3TriggersExist(A,B,C,D,E,F) 0
# define sqlite3DeleteTrigger(A)
# 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
@ -2192,6 +2239,9 @@ void sqlite3SelectDestInit(SelectDest*,int,int);
void *sqlite3ParserAlloc(void*(*)(size_t));
void sqlite3ParserFree(void*, void(*)(void*));
void sqlite3Parser(void*, int, Token, Parse*);
#ifdef YYTRACKMAXSTACKDEPTH
int sqlite3ParserStackPeak(void*);
#endif
int sqlite3AutoLoadExtensions(sqlite3*);
#ifndef SQLITE_OMIT_LOAD_EXTENSION
@ -2212,12 +2262,12 @@ int sqlite3AutoLoadExtensions(sqlite3*);
#ifdef SQLITE_OMIT_VIRTUALTABLE
# define sqlite3VtabClear(X)
# define sqlite3VtabSync(X,Y) (Y)
# define sqlite3VtabSync(X,Y) SQLITE_OK
# define sqlite3VtabRollback(X)
# define sqlite3VtabCommit(X)
#else
void sqlite3VtabClear(Table*);
int sqlite3VtabSync(sqlite3 *db, int rc);
int sqlite3VtabSync(sqlite3 *db, char **);
int sqlite3VtabRollback(sqlite3 *db);
int sqlite3VtabCommit(sqlite3 *db);
#endif

View File

@ -13,7 +13,7 @@
** This module implements the sqlite3_status() interface and related
** functionality.
**
** $Id: status.c,v 1.3 2008/07/11 16:15:18 drh Exp $
** $Id: status.c,v 1.7 2008/08/05 17:53:23 drh Exp $
*/
#include "sqliteInt.h"
@ -21,8 +21,8 @@
** Variables in which to record status information.
*/
static struct {
int nowValue[6]; /* Current value */
int mxValue[6]; /* Maximum value */
int nowValue[9]; /* Current value */
int mxValue[9]; /* Maximum value */
} sqlite3Stat;
@ -83,3 +83,29 @@ int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){
}
return SQLITE_OK;
}
/*
** Query status information for a single database connection
*/
int sqlite3_db_status(
sqlite3 *db, /* The database connection whose status is desired */
int op, /* Status verb */
int *pCurrent, /* Write current value here */
int *pHighwater, /* Write high-water mark here */
int resetFlag /* Reset high-water mark if true */
){
switch( op ){
case SQLITE_DBSTATUS_LOOKASIDE_USED: {
*pCurrent = db->lookaside.nOut;
*pHighwater = db->lookaside.mxOut;
if( resetFlag ){
db->lookaside.mxOut = db->lookaside.nOut;
}
break;
}
default: {
return SQLITE_ERROR;
}
}
return SQLITE_OK;
}

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.315 2008/07/12 14:52:20 drh Exp $
** $Id: test1.c,v 1.317 2008/07/31 02:05:04 shane Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
@ -497,6 +497,8 @@ static int test_snprintf_int(
return TCL_OK;
}
#ifndef SQLITE_OMIT_GET_TABLE
/*
** Usage: sqlite3_get_table_printf DB FORMAT STRING ?--no-counts?
**
@ -559,6 +561,8 @@ static int test_get_table_printf(
return TCL_OK;
}
#endif /* SQLITE_OMIT_GET_TABLE */
/*
** Usage: sqlite3_last_insert_rowid DB
@ -3787,167 +3791,6 @@ static int test_stmt_int(
return TCL_OK;
}
#ifndef SQLITE_OMIT_DISKIO
#if 0
/*
** Usage: sqlite3OsOpenReadWrite <filename>
*/
static int test_sqlite3OsOpenReadWrite(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
sqlite3_file *pFile;
int rc;
int dummy;
char zBuf[100];
if( objc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"",
Tcl_GetString(objv[0]), " filename", 0);
return TCL_ERROR;
}
rc = sqlite3OsOpenReadWrite(Tcl_GetString(objv[1]), &pFile, &dummy);
if( rc!=SQLITE_OK ){
Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
return TCL_ERROR;
}
sqlite3TestMakePointerStr(interp, zBuf, pFile);
Tcl_SetResult(interp, zBuf, 0);
return TCL_ERROR;
}
/*
** Usage: sqlite3OsClose <file handle>
*/
static int test_sqlite3OsClose(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
sqlite3_file *pFile;
int rc;
if( objc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"",
Tcl_GetString(objv[0]), " filehandle", 0);
return TCL_ERROR;
}
if( getFilePointer(interp, Tcl_GetString(objv[1]), &pFile) ){
return TCL_ERROR;
}
rc = sqlite3OsClose(&pFile);
if( rc!=SQLITE_OK ){
Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
return TCL_ERROR;
}
return TCL_OK;
}
/*
** Usage: sqlite3OsLock <file handle> <locktype>
*/
static int test_sqlite3OsLock(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
sqlite3_file * pFile;
int rc;
if( objc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"",
Tcl_GetString(objv[0]),
" filehandle (SHARED|RESERVED|PENDING|EXCLUSIVE)", 0);
return TCL_ERROR;
}
if( getFilePointer(interp, Tcl_GetString(objv[1]), &pFile) ){
return TCL_ERROR;
}
if( 0==strcmp("SHARED", Tcl_GetString(objv[2])) ){
rc = sqlite3OsLock(pFile, SHARED_LOCK);
}
else if( 0==strcmp("RESERVED", Tcl_GetString(objv[2])) ){
rc = sqlite3OsLock(pFile, RESERVED_LOCK);
}
else if( 0==strcmp("PENDING", Tcl_GetString(objv[2])) ){
rc = sqlite3OsLock(pFile, PENDING_LOCK);
}
else if( 0==strcmp("EXCLUSIVE", Tcl_GetString(objv[2])) ){
rc = sqlite3OsLock(pFile, EXCLUSIVE_LOCK);
}else{
Tcl_AppendResult(interp, "wrong # args: should be \"",
Tcl_GetString(objv[0]),
" filehandle (SHARED|RESERVED|PENDING|EXCLUSIVE)", 0);
return TCL_ERROR;
}
if( rc!=SQLITE_OK ){
Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
return TCL_ERROR;
}
return TCL_OK;
}
/*
** Usage: sqlite3OsUnlock <file handle>
*/
static int test_sqlite3OsUnlock(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
sqlite3_file * pFile;
int rc;
if( objc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"",
Tcl_GetString(objv[0]), " filehandle", 0);
return TCL_ERROR;
}
if( getFilePointer(interp, Tcl_GetString(objv[1]), &pFile) ){
return TCL_ERROR;
}
rc = sqlite3OsUnlock(pFile, NO_LOCK);
if( rc!=SQLITE_OK ){
Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
return TCL_ERROR;
}
return TCL_OK;
}
/*
** Usage: sqlite3OsTempFileName
*/
static int test_sqlite3OsTempFileName(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
char zFile[SQLITE_TEMPNAME_SIZE];
int rc;
rc = sqlite3OsTempFileName(zFile);
if( rc!=SQLITE_OK ){
Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
return TCL_ERROR;
}
Tcl_AppendResult(interp, zFile, 0);
return TCL_OK;
}
#endif
#endif
/*
** Usage: sqlite_set_magic DB MAGIC-NUMBER
**
@ -4690,7 +4533,9 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_exec_printf", (Tcl_CmdProc*)test_exec_printf },
{ "sqlite3_exec", (Tcl_CmdProc*)test_exec },
{ "sqlite3_exec_nr", (Tcl_CmdProc*)test_exec_nr },
#ifndef SQLITE_OMIT_GET_TABLE
{ "sqlite3_get_table_printf", (Tcl_CmdProc*)test_get_table_printf },
#endif
{ "sqlite3_close", (Tcl_CmdProc*)sqlite_test_close },
{ "sqlite3_create_function", (Tcl_CmdProc*)test_create_function },
{ "sqlite3_create_aggregate", (Tcl_CmdProc*)test_create_aggregate },
@ -4809,17 +4654,6 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_vfs_list", vfs_list, 0 },
/* Functions from os.h */
#ifndef SQLITE_OMIT_DISKIO
#if 0
{ "sqlite3OsOpenReadWrite",test_sqlite3OsOpenReadWrite, 0 },
{ "sqlite3OsClose", test_sqlite3OsClose, 0 },
{ "sqlite3OsLock", test_sqlite3OsLock, 0 },
{ "sqlite3OsTempFileName", test_sqlite3OsTempFileName, 0 },
/* Custom test interfaces */
{ "sqlite3OsUnlock", test_sqlite3OsUnlock, 0 },
#endif
#endif
#ifndef SQLITE_OMIT_UTF16
{ "add_test_collate", test_collate, 0 },
{ "add_test_collate_needed", test_collate_needed, 0 },

View File

@ -11,7 +11,7 @@
*************************************************************************
** Code for testing the the SQLite library in a multithreaded environment.
**
** $Id: test4.c,v 1.22 2008/06/26 10:41:19 danielk1977 Exp $
** $Id: test4.c,v 1.23 2008/07/28 19:34:54 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
@ -142,7 +142,7 @@ static int tcl_thread_create(
}
threadset[i].busy = 1;
sqlite3_free(threadset[i].zFilename);
threadset[i].zFilename = sqlite3StrDup(argv[2]);
threadset[i].zFilename = sqlite3DbStrDup(0, argv[2]);
threadset[i].opnum = 1;
threadset[i].completed = 0;
rc = pthread_create(&x, 0, thread_main, &threadset[i]);
@ -476,7 +476,7 @@ static int tcl_thread_compile(
thread_wait(&threadset[i]);
threadset[i].xOp = do_compile;
sqlite3_free(threadset[i].zArg);
threadset[i].zArg = sqlite3StrDup(argv[2]);
threadset[i].zArg = sqlite3DbStrDup(0, argv[2]);
threadset[i].opnum++;
return TCL_OK;
}

View File

@ -15,7 +15,7 @@
** is used for testing the SQLite routines for converting between
** the various supported unicode encodings.
**
** $Id: test5.c,v 1.20 2007/08/21 19:33:57 drh Exp $
** $Id: test5.c,v 1.21 2008/07/28 19:34:54 drh Exp $
*/
#include "sqliteInt.h"
#include "vdbeInt.h"
@ -154,7 +154,7 @@ static int test_translate(
if( enc_from==SQLITE_UTF8 ){
z = Tcl_GetString(objv[1]);
if( objc==5 ){
z = sqlite3StrDup(z);
z = sqlite3DbStrDup(0, z);
}
sqlite3ValueSetStr(pVal, -1, z, enc_from, xDel);
}else{

View File

@ -12,7 +12,7 @@
** Code for testing the client/server version of the SQLite library.
** Derived from test4.c.
**
** $Id: test7.c,v 1.11 2008/06/26 10:41:19 danielk1977 Exp $
** $Id: test7.c,v 1.12 2008/07/28 19:34:54 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
@ -164,7 +164,7 @@ static int tcl_client_create(
}
threadset[i].busy = 1;
sqlite3_free(threadset[i].zFilename);
threadset[i].zFilename = sqlite3StrDup(argv[2]);
threadset[i].zFilename = sqlite3DbStrDup(0, argv[2]);
threadset[i].opnum = 1;
threadset[i].completed = 0;
rc = pthread_create(&x, 0, client_main, &threadset[i]);
@ -507,7 +507,7 @@ static int tcl_client_compile(
client_wait(&threadset[i]);
threadset[i].xOp = do_compile;
sqlite3_free(threadset[i].zArg);
threadset[i].zArg = sqlite3StrDup(argv[2]);
threadset[i].zArg = sqlite3DbStrDup(0, argv[2]);
threadset[i].opnum++;
return TCL_OK;
}

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.67 2008/07/07 14:50:14 drh Exp $
** $Id: test8.c,v 1.72 2008/08/05 21:36:07 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
@ -44,6 +44,22 @@ typedef struct echo_cursor echo_cursor;
** use the named table as a backing store will fail.
*/
/*
** Errors can be provoked within the following echo virtual table methods:
**
** xBestIndex xOpen xFilter xNext
** xColumn xRowid xUpdate xSync
** xBegin xRename
**
** This is done by setting the global tcl variable:
**
** echo_module_fail($method,$tbl)
**
** where $method is set to the name of the virtual table method to fail
** (i.e. "xBestIndex") and $tbl is the name of the table being echoed (not
** the name of the virtual table, the name of the underlying real table).
*/
/*
** An echo virtual-table object.
**
@ -76,6 +92,19 @@ struct echo_cursor {
sqlite3_stmt *pStmt;
};
static int simulateVtabError(echo_vtab *p, const char *zMethod){
const char *zErr;
char zVarname[128];
zVarname[127] = '\0';
sqlite3_snprintf(127, zVarname,
"echo_module_fail(%s,%s)", zMethod, p->zTableName);
zErr = Tcl_GetVar(p->interp, zVarname, TCL_GLOBAL_ONLY);
if( zErr ){
p->base.zErrMsg = sqlite3_mprintf("echo-vtab-error: %s", zErr);
}
return (zErr!=0);
}
/*
** Convert an SQL-style quoted string into a normal string by removing
** the quote characters. The conversion is done in-place. If the
@ -459,7 +488,7 @@ static int echoCreate(
rc = sqlite3_exec(db, zSql, 0, 0, 0);
sqlite3_free(zSql);
if( rc!=SQLITE_OK ){
*pzErr = sqlite3StrDup(sqlite3_errmsg(db));
*pzErr = sqlite3DbStrDup(0, sqlite3_errmsg(db));
}
}
@ -524,6 +553,9 @@ static int echoDestroy(sqlite3_vtab *pVtab){
*/
static int echoOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
echo_cursor *pCur;
if( simulateVtabError((echo_vtab *)pVTab, "xOpen") ){
return SQLITE_ERROR;
}
pCur = sqlite3MallocZero(sizeof(echo_cursor));
*ppCursor = (sqlite3_vtab_cursor *)pCur;
return (pCur ? SQLITE_OK : SQLITE_NOMEM);
@ -557,6 +589,10 @@ static int echoNext(sqlite3_vtab_cursor *cur){
int rc = SQLITE_OK;
echo_cursor *pCur = (echo_cursor *)cur;
if( simulateVtabError((echo_vtab *)(cur->pVtab), "xNext") ){
return SQLITE_ERROR;
}
if( pCur->pStmt ){
rc = sqlite3_step(pCur->pStmt);
if( rc==SQLITE_ROW ){
@ -576,6 +612,11 @@ static int echoNext(sqlite3_vtab_cursor *cur){
static int echoColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
int iCol = i + 1;
sqlite3_stmt *pStmt = ((echo_cursor *)cur)->pStmt;
if( simulateVtabError((echo_vtab *)(cur->pVtab), "xColumn") ){
return SQLITE_ERROR;
}
if( !pStmt ){
sqlite3_result_null(ctx);
}else{
@ -590,6 +631,11 @@ static int echoColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
*/
static int echoRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
sqlite3_stmt *pStmt = ((echo_cursor *)cur)->pStmt;
if( simulateVtabError((echo_vtab *)(cur->pVtab), "xRowid") ){
return SQLITE_ERROR;
}
*pRowid = sqlite3_column_int64(pStmt, 0);
return SQLITE_OK;
}
@ -627,6 +673,10 @@ static int echoFilter(
echo_vtab *pVtab = (echo_vtab *)pVtabCursor->pVtab;
sqlite3 *db = pVtab->db;
if( simulateVtabError(pVtab, "xFilter") ){
return SQLITE_ERROR;
}
/* Check that idxNum matches idxStr */
assert( idxNum==hashString(idxStr) );
@ -734,12 +784,15 @@ static int echoBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
int rc = SQLITE_OK;
int useCost = 0;
double cost;
int isIgnoreUsable = 0;
if( Tcl_GetVar(interp, "echo_module_ignore_usable", TCL_GLOBAL_ONLY) ){
isIgnoreUsable = 1;
}
if( simulateVtabError(pVtab, "xBestIndex") ){
return SQLITE_ERROR;
}
/* Determine the number of rows in the table and store this value in local
** variable nRow. The 'estimated-cost' of the scan will be the number of
** rows in the table for a linear scan, or the log (base 2) of the
@ -892,6 +945,10 @@ int echoUpdate(
** making any changes to a virtual table */
assert( pVtab->inTransaction );
if( simulateVtabError(pVtab, "xUpdate") ){
return SQLITE_ERROR;
}
/* If apData[0] is an integer and nData>1 then do an UPDATE */
if( nData>1 && sqlite3_value_type(apData[0])==SQLITE_INTEGER ){
char *zSep = " SET";
@ -987,6 +1044,9 @@ int echoUpdate(
if( pRowid && rc==SQLITE_OK ){
*pRowid = sqlite3_last_insert_rowid(db);
}
if( rc!=SQLITE_OK ){
tab->zErrMsg = sqlite3_mprintf("echo-vtab-error: %s", sqlite3_errmsg(db));
}
return rc;
}
@ -1016,6 +1076,10 @@ static int echoBegin(sqlite3_vtab *tab){
** a transaction */
assert( !pVtab->inTransaction );
if( simulateVtabError(pVtab, "xBegin") ){
return SQLITE_ERROR;
}
rc = echoTransactionCall(tab, "xBegin");
if( rc==SQLITE_OK ){
@ -1043,6 +1107,10 @@ static int echoSync(sqlite3_vtab *tab){
** transaction */
assert( pVtab->inTransaction );
if( simulateVtabError(pVtab, "xSync") ){
return SQLITE_ERROR;
}
rc = echoTransactionCall(tab, "xSync");
if( rc==SQLITE_OK ){
@ -1065,6 +1133,10 @@ static int echoCommit(sqlite3_vtab *tab){
** a transaction */
assert( pVtab->inTransaction );
if( simulateVtabError(pVtab, "xCommit") ){
return SQLITE_ERROR;
}
sqlite3BeginBenignMalloc();
rc = echoTransactionCall(tab, "xCommit");
sqlite3EndBenignMalloc();
@ -1147,6 +1219,10 @@ static int echoRename(sqlite3_vtab *vtab, const char *zNewName){
int rc = SQLITE_OK;
echo_vtab *p = (echo_vtab *)vtab;
if( simulateVtabError(p, "xRename") ){
return SQLITE_ERROR;
}
if( p->isPattern ){
int nThis = strlen(p->zThis);
char *zSql = sqlite3MPrintf(0, "ALTER TABLE %s RENAME TO %s%s",

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.31 2008/07/08 23:40:20 drh Exp $
** $Id: test_config.c,v 1.33 2008/07/31 02:05:05 shane Exp $
*/
#include "sqliteLimit.h"
@ -243,6 +243,12 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "fts3", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_GET_TABLE
Tcl_SetVar2(interp, "sqlite_options", "gettable", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "gettable", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_GLOBALRECOVER
Tcl_SetVar2(interp, "sqlite_options", "globalrecover", "0", TCL_GLOBAL_ONLY);
#else
@ -437,6 +443,12 @@ Tcl_SetVar2(interp, "sqlite_options", "long_double",
Tcl_SetVar2(interp, "sqlite_options", "secure_delete", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef YYTRACKMAXSTACKDEPTH
Tcl_SetVar2(interp, "sqlite_options", "yytrackmaxstackdepth", "1", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "yytrackmaxstackdepth", "0", TCL_GLOBAL_ONLY);
#endif
#define LINKVAR(x) { \
static const int cv_ ## x = SQLITE_ ## x; \
Tcl_LinkVar(interp, "SQLITE_" #x, (char *)&(cv_ ## x), \

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.8 2008/07/11 21:02:54 drh Exp $
** $Id: test_func.c,v 1.10 2008/08/02 03:50:39 drh Exp $
*/
#include "sqlite3.h"
#include "tcl.h"
@ -114,6 +114,7 @@ static void test_destructor(
memcpy(zVal, sqlite3_value_text(argv[0]), len);
sqlite3_result_text(pCtx, zVal, -1, destructor);
}
#ifndef SQLITE_OMIT_UTF16
static void test_destructor16(
sqlite3_context *pCtx,
int nArg,
@ -136,6 +137,7 @@ static void test_destructor16(
memcpy(zVal, sqlite3_value_text16(argv[0]), len);
sqlite3_result_text16(pCtx, zVal, -1, destructor);
}
#endif
static void test_destructor_count(
sqlite3_context *pCtx,
int nArg,
@ -272,7 +274,9 @@ static int registerTestFunctions(sqlite3 *db){
} aFuncs[] = {
{ "randstr", 2, SQLITE_UTF8, randStr },
{ "test_destructor", 1, SQLITE_UTF8, test_destructor},
#ifndef SQLITE_OMIT_UTF16
{ "test_destructor16", 1, SQLITE_UTF8, test_destructor16},
#endif
{ "test_destructor_count", 0, SQLITE_UTF8, test_destructor_count},
{ "test_auxdata", -1, SQLITE_UTF8, test_auxdata},
{ "test_error", 1, SQLITE_UTF8, test_error},
@ -304,7 +308,8 @@ static int autoinstall_test_funcs(
int objc,
Tcl_Obj *CONST objv[]
){
sqlite3_auto_extension((void*)registerTestFunctions);
int rc = sqlite3_auto_extension((void*)registerTestFunctions);
Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
return TCL_OK;
}

View File

@ -11,7 +11,7 @@
*************************************************************************
** Test extension for testing the sqlite3_load_extension() function.
**
** $Id: test_loadext.c,v 1.2 2008/06/19 15:44:00 drh Exp $
** $Id: test_loadext.c,v 1.3 2008/08/02 03:50:39 drh Exp $
*/
#include <string.h>
#include "sqlite3ext.h"
@ -98,13 +98,14 @@ int testloadext_init(
char **pzErrMsg,
const sqlite3_api_routines *pApi
){
int nErr = 0;
SQLITE_EXTENSION_INIT2(pApi);
sqlite3_create_function(db, "half", 1, SQLITE_ANY, 0, halfFunc, 0, 0);
sqlite3_create_function(db, "sqlite3_status", 1, SQLITE_ANY, 0,
nErr |= sqlite3_create_function(db, "half", 1, SQLITE_ANY, 0, halfFunc, 0, 0);
nErr |= sqlite3_create_function(db, "sqlite3_status", 1, SQLITE_ANY, 0,
statusFunc, 0, 0);
sqlite3_create_function(db, "sqlite3_status", 2, SQLITE_ANY, 0,
nErr |= sqlite3_create_function(db, "sqlite3_status", 2, SQLITE_ANY, 0,
statusFunc, 0, 0);
return 0;
return nErr ? SQLITE_ERROR : SQLITE_OK;
}
/*

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.38 2008/07/16 12:25:32 drh Exp $
** $Id: test_malloc.c,v 1.47 2008/08/05 17:53:24 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
@ -874,18 +874,19 @@ static int test_config_scratch(
){
int sz, N, rc;
Tcl_Obj *pResult;
static char buf[30000];
static char *buf = 0;
if( objc!=3 ){
Tcl_WrongNumArgs(interp, 1, objv, "SIZE N");
return TCL_ERROR;
}
if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR;
free(buf);
if( sz<0 ){
buf = 0;
rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, 0, 0, 0);
}else{
int mx = sizeof(buf)/(sz+4);
if( N>mx ) N = mx;
buf = malloc( sz*N + 1 );
rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, buf, sz, N);
}
pResult = Tcl_NewObj();
@ -913,18 +914,19 @@ static int test_config_pagecache(
){
int sz, N, rc;
Tcl_Obj *pResult;
static char buf[100000];
static char *buf = 0;
if( objc!=3 ){
Tcl_WrongNumArgs(interp, 1, objv, "SIZE N");
return TCL_ERROR;
}
if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR;
free(buf);
if( sz<0 ){
buf = 0;
rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, 0, 0, 0);
}else{
int mx = sizeof(buf)/(sz+4);
if( N>mx ) N = mx;
buf = malloc( sz*N );
rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, buf, sz, N);
}
pResult = Tcl_NewObj();
@ -956,6 +958,91 @@ static int test_config_memstatus(
return TCL_OK;
}
/*
** Usage: sqlite3_config_chunkalloc
**
*/
static int test_config_chunkalloc(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
int rc;
int nThreshold;
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "THRESHOLD");
return TCL_ERROR;
}
if( Tcl_GetIntFromObj(interp, objv[1], &nThreshold) ) return TCL_ERROR;
rc = sqlite3_config(SQLITE_CONFIG_CHUNKALLOC, nThreshold);
Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
return TCL_OK;
}
/*
** Usage: sqlite3_config_lookaside SIZE COUNT
**
*/
static int test_config_lookaside(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
int rc;
int sz, cnt;
if( objc!=3 ){
Tcl_WrongNumArgs(interp, 1, objv, "SIZE COUNT");
return TCL_ERROR;
}
if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
if( Tcl_GetIntFromObj(interp, objv[2], &cnt) ) return TCL_ERROR;
rc = sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, cnt);
Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
return TCL_OK;
}
/*
** Usage: sqlite3_db_config_lookaside CONNECTION BUFID SIZE COUNT
**
** There are two static buffers with BUFID 1 and 2. Each static buffer
** is 10KB in size. A BUFID of 0 indicates that the buffer should be NULL
** which will cause sqlite3_db_config() to allocate space on its own.
*/
static int test_db_config_lookaside(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
int rc;
int sz, cnt;
sqlite3 *db;
int bufid;
static char azBuf[2][10000];
int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
if( objc!=5 ){
Tcl_WrongNumArgs(interp, 1, objv, "BUFID SIZE COUNT");
return TCL_ERROR;
}
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
if( Tcl_GetIntFromObj(interp, objv[2], &bufid) ) return TCL_ERROR;
if( Tcl_GetIntFromObj(interp, objv[3], &sz) ) return TCL_ERROR;
if( Tcl_GetIntFromObj(interp, objv[4], &cnt) ) return TCL_ERROR;
if( bufid==0 ){
rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, 0, sz, cnt);
}else if( bufid>=1 && bufid<=2 && sz*cnt<=sizeof(azBuf[0]) ){
rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, azBuf[bufid], sz,cnt);
}else{
Tcl_AppendResult(interp, "illegal arguments - see documentation", (char*)0);
return TCL_ERROR;
}
Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
return TCL_OK;
}
/*
** Usage:
**
@ -998,6 +1085,44 @@ static int test_config_heap(
return TCL_OK;
}
/*
** tclcmd: sqlite3_config_error [DB]
**
** Invoke sqlite3_config() or sqlite3_db_config() with invalid
** opcodes and verify that they return errors.
*/
static int test_config_error(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
sqlite3 *db;
int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
if( objc!=2 && objc!=1 ){
Tcl_WrongNumArgs(interp, 1, objv, "[DB]");
return TCL_ERROR;
}
if( objc==2 ){
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
if( sqlite3_db_config(db, 99999)!=SQLITE_ERROR ){
Tcl_AppendResult(interp,
"sqlite3_db_config(db, 99999) does not return SQLITE_ERROR",
(char*)0);
return TCL_ERROR;
}
}else{
if( sqlite3_config(99999)!=SQLITE_ERROR ){
Tcl_AppendResult(interp,
"sqlite3_config(99999) does not return SQLITE_ERROR",
(char*)0);
return TCL_ERROR;
}
}
return TCL_OK;
}
/*
** Usage:
**
@ -1056,11 +1181,14 @@ static int test_status(
int op;
} aOp[] = {
{ "SQLITE_STATUS_MEMORY_USED", SQLITE_STATUS_MEMORY_USED },
{ "SQLITE_STATUS_MALLOC_SIZE", SQLITE_STATUS_MALLOC_SIZE },
{ "SQLITE_STATUS_PAGECACHE_USED", SQLITE_STATUS_PAGECACHE_USED },
{ "SQLITE_STATUS_PAGECACHE_OVERFLOW", SQLITE_STATUS_PAGECACHE_OVERFLOW },
{ "SQLITE_STATUS_PAGECACHE_SIZE", SQLITE_STATUS_PAGECACHE_SIZE },
{ "SQLITE_STATUS_SCRATCH_USED", SQLITE_STATUS_SCRATCH_USED },
{ "SQLITE_STATUS_SCRATCH_OVERFLOW", SQLITE_STATUS_SCRATCH_OVERFLOW },
{ "SQLITE_STATUS_MALLOC_SIZE", SQLITE_STATUS_MALLOC_SIZE },
{ "SQLITE_STATUS_SCRATCH_SIZE", SQLITE_STATUS_SCRATCH_SIZE },
{ "SQLITE_STATUS_PARSER_STACK", SQLITE_STATUS_PARSER_STACK },
};
Tcl_Obj *pResult;
if( objc!=3 ){
@ -1089,6 +1217,57 @@ static int test_status(
return TCL_OK;
}
/*
** Usage: sqlite3_db_status DATABASE OPCODE RESETFLAG
**
** Return a list of three elements which are the sqlite3_db_status() return
** code, the current value, and the high-water mark value.
*/
static int test_db_status(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
int rc, iValue, mxValue;
int i, op, resetFlag;
const char *zOpName;
sqlite3 *db;
int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
static const struct {
const char *zName;
int op;
} aOp[] = {
{ "SQLITE_DBSTATUS_LOOKASIDE_USED", SQLITE_DBSTATUS_LOOKASIDE_USED },
};
Tcl_Obj *pResult;
if( objc!=4 ){
Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG");
return TCL_ERROR;
}
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
zOpName = Tcl_GetString(objv[2]);
for(i=0; i<ArraySize(aOp); i++){
if( strcmp(aOp[i].zName, zOpName)==0 ){
op = aOp[i].op;
break;
}
}
if( i>=ArraySize(aOp) ){
if( Tcl_GetIntFromObj(interp, objv[2], &op) ) return TCL_ERROR;
}
if( Tcl_GetBooleanFromObj(interp, objv[3], &resetFlag) ) return TCL_ERROR;
iValue = 0;
mxValue = 0;
rc = sqlite3_db_status(db, op, &iValue, &mxValue, resetFlag);
pResult = Tcl_NewObj();
Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue));
Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue));
Tcl_SetObjResult(interp, pResult);
return TCL_OK;
}
/*
** install_malloc_faultsim BOOLEAN
*/
@ -1139,9 +1318,14 @@ int Sqlitetest_malloc_Init(Tcl_Interp *interp){
{ "sqlite3_config_scratch", test_config_scratch ,0 },
{ "sqlite3_config_pagecache", test_config_pagecache ,0 },
{ "sqlite3_status", test_status ,0 },
{ "sqlite3_db_status", test_db_status ,0 },
{ "install_malloc_faultsim", test_install_malloc_faultsim ,0 },
{ "sqlite3_config_heap", test_config_heap ,0 },
{ "sqlite3_config_memstatus", test_config_memstatus ,0 },
{ "sqlite3_config_chunkalloc", test_config_chunkalloc ,0 },
{ "sqlite3_config_lookaside", test_config_lookaside ,0 },
{ "sqlite3_config_error", test_config_error ,0 },
{ "sqlite3_db_config_lookaside",test_db_config_lookaside ,0 },
{ "sqlite3_dump_memsys3", test_dump_memsys3 ,3 },
{ "sqlite3_dump_memsys5", test_dump_memsys3 ,5 }
};

View File

@ -10,11 +10,12 @@
**
*************************************************************************
**
** $Id: test_mutex.c,v 1.9 2008/07/10 20:41:50 drh Exp $
** $Id: test_mutex.c,v 1.11 2008/07/19 13:43:24 danielk1977 Exp $
*/
#include "tcl.h"
#include "sqlite3.h"
#include "sqliteInt.h"
#include <stdlib.h>
#include <assert.h>
#include <string.h>
@ -300,11 +301,13 @@ static int test_alloc_mutex(
int objc,
Tcl_Obj *CONST objv[]
){
#if SQLITE_THREADSAFE
sqlite3_mutex *p = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
char zBuf[100];
sqlite3_mutex_free(p);
sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", p);
Tcl_AppendResult(interp, zBuf, (char*)0);
#endif
return TCL_OK;
}

View File

@ -14,9 +14,10 @@
** adds instrumentation to all vfs and file methods. C and Tcl interfaces
** are provided to control the instrumentation.
**
** $Id: test_osinst.c,v 1.17 2008/07/12 15:55:55 danielk1977 Exp $
** $Id: test_osinst.c,v 1.18 2008/07/25 13:32:45 drh Exp $
*/
#ifdef SQLITE_ENABLE_INSTVFS
/*
** C interface:
**
@ -809,6 +810,7 @@ sqlite3_vfs *sqlite3_instvfs_binarylog(
return pVfs;
}
#endif /* SQLITE_ENABLE_INSTVFS */
/**************************************************************************
***************************************************************************
@ -818,6 +820,7 @@ sqlite3_vfs *sqlite3_instvfs_binarylog(
#include <tcl.h>
#ifdef SQLITE_ENABLE_INSTVFS
struct InstVfsCall {
Tcl_Interp *interp;
Tcl_Obj *pScript;
@ -1039,10 +1042,28 @@ static int test_sqlite3_instvfs(
return TCL_OK;
}
#endif /* SQLITE_ENABLE_INSTVFS */
/* Alternative implementation of sqlite3_instvfs when the real
** implementation is unavailable.
*/
#ifndef SQLITE_ENABLE_INSTVFS
static int test_sqlite3_instvfs(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
Tcl_AppendResult(interp,
"not compiled with -DSQLITE_ENABLE_INSTVFS; sqlite3_instvfs is "
"unavailable", (char*)0);
return TCL_ERROR;
}
#endif /* !defined(SQLITE_ENABLE_INSTVFS) */
int SqlitetestOsinst_Init(Tcl_Interp *interp){
Tcl_CreateObjCommand(interp, "sqlite3_instvfs", test_sqlite3_instvfs, 0, 0);
return TCL_OK;
}
#endif
#endif /* SQLITE_TEST */

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.146 2008/07/08 19:34:07 drh Exp $
** $Id: tokenize.c,v 1.148 2008/07/28 19:34:54 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@ -427,7 +427,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
break;
}
case TK_ILLEGAL: {
sqlite3_free(*pzErrMsg);
sqlite3DbFree(db, *pzErrMsg);
*pzErrMsg = sqlite3MPrintf(db, "unrecognized token: \"%T\"",
&pParse->sLastToken);
nErr++;
@ -455,6 +455,11 @@ abort_parse:
}
sqlite3Parser(pEngine, 0, pParse->sLastToken, pParse);
}
#ifdef YYTRACKMAXSTACKDEPTH
sqlite3StatusSet(SQLITE_STATUS_PARSER_STACK,
sqlite3ParserStackPeak(pEngine)
);
#endif /* YYDEBUG */
sqlite3ParserFree(pEngine, sqlite3_free);
if( db->mallocFailed ){
pParse->rc = SQLITE_NOMEM;
@ -466,7 +471,7 @@ abort_parse:
if( *pzErrMsg==0 ){
*pzErrMsg = pParse->zErrMsg;
}else{
sqlite3_free(pParse->zErrMsg);
sqlite3DbFree(db, pParse->zErrMsg);
}
pParse->zErrMsg = 0;
nErr++;
@ -477,13 +482,13 @@ abort_parse:
}
#ifndef SQLITE_OMIT_SHARED_CACHE
if( pParse->nested==0 ){
sqlite3_free(pParse->aTableLock);
sqlite3DbFree(db, pParse->aTableLock);
pParse->aTableLock = 0;
pParse->nTableLock = 0;
}
#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
sqlite3_free(pParse->apVtabLock);
sqlite3DbFree(db, pParse->apVtabLock);
#endif
if( !IN_DECLARE_VTAB ){
@ -494,8 +499,8 @@ abort_parse:
sqlite3DeleteTable(pParse->pNewTable);
}
sqlite3DeleteTrigger(pParse->pNewTrigger);
sqlite3_free(pParse->apVarExpr);
sqlite3DeleteTrigger(db, pParse->pNewTrigger);
sqlite3DbFree(db, pParse->apVarExpr);
if( nErr>0 && (pParse->rc==SQLITE_OK || pParse->rc==SQLITE_DONE) ){
pParse->rc = SQLITE_ERROR;
}

View File

@ -10,7 +10,7 @@
*************************************************************************
**
**
** $Id: trigger.c,v 1.127 2008/07/08 23:40:20 drh Exp $
** $Id: trigger.c,v 1.128 2008/07/28 19:34:54 drh Exp $
*/
#include "sqliteInt.h"
@ -18,18 +18,18 @@
/*
** Delete a linked list of TriggerStep structures.
*/
void sqlite3DeleteTriggerStep(TriggerStep *pTriggerStep){
void sqlite3DeleteTriggerStep(sqlite3 *db, TriggerStep *pTriggerStep){
while( pTriggerStep ){
TriggerStep * pTmp = pTriggerStep;
pTriggerStep = pTriggerStep->pNext;
if( pTmp->target.dyn ) sqlite3_free((char*)pTmp->target.z);
sqlite3ExprDelete(pTmp->pWhere);
sqlite3ExprListDelete(pTmp->pExprList);
sqlite3SelectDelete(pTmp->pSelect);
sqlite3IdListDelete(pTmp->pIdList);
if( pTmp->target.dyn ) sqlite3DbFree(db, (char*)pTmp->target.z);
sqlite3ExprDelete(db, pTmp->pWhere);
sqlite3ExprListDelete(db, pTmp->pExprList);
sqlite3SelectDelete(db, pTmp->pSelect);
sqlite3IdListDelete(db, pTmp->pIdList);
sqlite3_free(pTmp);
sqlite3DbFree(db, pTmp);
}
}
@ -186,12 +186,12 @@ void sqlite3BeginTrigger(
pParse->pNewTrigger = pTrigger;
trigger_cleanup:
sqlite3_free(zName);
sqlite3SrcListDelete(pTableName);
sqlite3IdListDelete(pColumns);
sqlite3ExprDelete(pWhen);
sqlite3DbFree(db, zName);
sqlite3SrcListDelete(db, pTableName);
sqlite3IdListDelete(db, pColumns);
sqlite3ExprDelete(db, pWhen);
if( !pParse->pNewTrigger ){
sqlite3DeleteTrigger(pTrigger);
sqlite3DeleteTrigger(db, pTrigger);
}else{
assert( pParse->pNewTrigger==pTrigger );
}
@ -241,7 +241,7 @@ void sqlite3FinishTrigger(
"INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')",
db->aDb[iDb].zName, SCHEMA_TABLE(iDb), pTrig->name,
pTrig->table, z);
sqlite3_free(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
@ -268,9 +268,9 @@ void sqlite3FinishTrigger(
}
triggerfinish_cleanup:
sqlite3DeleteTrigger(pTrig);
sqlite3DeleteTrigger(db, pTrig);
assert( !pParse->pNewTrigger );
sqlite3DeleteTriggerStep(pStepList);
sqlite3DeleteTriggerStep(db, pStepList);
}
/*
@ -290,22 +290,22 @@ static void sqlitePersistTriggerStep(sqlite3 *db, TriggerStep *p){
}
if( p->pSelect ){
Select *pNew = sqlite3SelectDup(db, p->pSelect);
sqlite3SelectDelete(p->pSelect);
sqlite3SelectDelete(db, p->pSelect);
p->pSelect = pNew;
}
if( p->pWhere ){
Expr *pNew = sqlite3ExprDup(db, p->pWhere);
sqlite3ExprDelete(p->pWhere);
sqlite3ExprDelete(db, p->pWhere);
p->pWhere = pNew;
}
if( p->pExprList ){
ExprList *pNew = sqlite3ExprListDup(db, p->pExprList);
sqlite3ExprListDelete(p->pExprList);
sqlite3ExprListDelete(db, p->pExprList);
p->pExprList = pNew;
}
if( p->pIdList ){
IdList *pNew = sqlite3IdListDup(db, p->pIdList);
sqlite3IdListDelete(p->pIdList);
sqlite3IdListDelete(db, p->pIdList);
p->pIdList = pNew;
}
}
@ -320,7 +320,7 @@ static void sqlitePersistTriggerStep(sqlite3 *db, TriggerStep *p){
TriggerStep *sqlite3TriggerSelectStep(sqlite3 *db, Select *pSelect){
TriggerStep *pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep));
if( pTriggerStep==0 ) {
sqlite3SelectDelete(pSelect);
sqlite3SelectDelete(db, pSelect);
return 0;
}
@ -362,9 +362,9 @@ TriggerStep *sqlite3TriggerInsertStep(
pTriggerStep->orconf = orconf;
sqlitePersistTriggerStep(db, pTriggerStep);
}else{
sqlite3IdListDelete(pColumn);
sqlite3ExprListDelete(pEList);
sqlite3SelectDelete(pSelect);
sqlite3IdListDelete(db, pColumn);
sqlite3ExprListDelete(db, pEList);
sqlite3SelectDelete(db, pSelect);
}
return pTriggerStep;
@ -384,8 +384,8 @@ TriggerStep *sqlite3TriggerUpdateStep(
){
TriggerStep *pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep));
if( pTriggerStep==0 ){
sqlite3ExprListDelete(pEList);
sqlite3ExprDelete(pWhere);
sqlite3ExprListDelete(db, pEList);
sqlite3ExprDelete(db, pWhere);
return 0;
}
@ -411,7 +411,7 @@ TriggerStep *sqlite3TriggerDeleteStep(
){
TriggerStep *pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep));
if( pTriggerStep==0 ){
sqlite3ExprDelete(pWhere);
sqlite3ExprDelete(db, pWhere);
return 0;
}
@ -427,15 +427,15 @@ TriggerStep *sqlite3TriggerDeleteStep(
/*
** Recursively delete a Trigger structure
*/
void sqlite3DeleteTrigger(Trigger *pTrigger){
void sqlite3DeleteTrigger(sqlite3 *db, Trigger *pTrigger){
if( pTrigger==0 ) return;
sqlite3DeleteTriggerStep(pTrigger->step_list);
sqlite3_free(pTrigger->name);
sqlite3_free(pTrigger->table);
sqlite3ExprDelete(pTrigger->pWhen);
sqlite3IdListDelete(pTrigger->pColumns);
if( pTrigger->nameToken.dyn ) sqlite3_free((char*)pTrigger->nameToken.z);
sqlite3_free(pTrigger);
sqlite3DeleteTriggerStep(db, pTrigger->step_list);
sqlite3DbFree(db, pTrigger->name);
sqlite3DbFree(db, pTrigger->table);
sqlite3ExprDelete(db, pTrigger->pWhen);
sqlite3IdListDelete(db, pTrigger->pColumns);
if( pTrigger->nameToken.dyn ) sqlite3DbFree(db, (char*)pTrigger->nameToken.z);
sqlite3DbFree(db, pTrigger);
}
/*
@ -478,7 +478,7 @@ void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr){
sqlite3DropTriggerPtr(pParse, pTrigger);
drop_trigger_cleanup:
sqlite3SrcListDelete(pName);
sqlite3SrcListDelete(db, pName);
}
/*
@ -570,7 +570,7 @@ void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){
}
assert(cc);
}
sqlite3DeleteTrigger(pTrigger);
sqlite3DeleteTrigger(db, pTrigger);
db->flags |= SQLITE_InternChanges;
}
}
@ -681,7 +681,7 @@ static int codeTriggerProgram(
sqlite3SelectDestInit(&dest, SRT_Discard, 0);
sqlite3SelectResolve(pParse, ss, 0);
sqlite3Select(pParse, ss, &dest, 0, 0, 0);
sqlite3SelectDelete(ss);
sqlite3SelectDelete(db, ss);
}
break;
}
@ -831,11 +831,11 @@ int sqlite3CodeRowTrigger(
whenExpr = sqlite3ExprDup(db, p->pWhen);
if( db->mallocFailed || sqlite3ExprResolveNames(&sNC, whenExpr) ){
pParse->trigStack = trigStackEntry.pNext;
sqlite3ExprDelete(whenExpr);
sqlite3ExprDelete(db, whenExpr);
return 1;
}
sqlite3ExprIfFalse(pParse, whenExpr, endTrigger, SQLITE_JUMPIFNULL);
sqlite3ExprDelete(whenExpr);
sqlite3ExprDelete(db, whenExpr);
codeTriggerProgram(pParse, p->step_list, orconf);

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.180 2008/07/09 16:51:51 drh Exp $
** $Id: update.c,v 1.181 2008/07/28 19:34:54 drh Exp $
*/
#include "sqliteInt.h"
@ -570,11 +570,11 @@ void sqlite3Update(
update_cleanup:
sqlite3AuthContextPop(&sContext);
sqlite3_free(aRegIdx);
sqlite3_free(aXRef);
sqlite3SrcListDelete(pTabList);
sqlite3ExprListDelete(pChanges);
sqlite3ExprDelete(pWhere);
sqlite3DbFree(db, aRegIdx);
sqlite3DbFree(db, aXRef);
sqlite3SrcListDelete(db, pTabList);
sqlite3ExprListDelete(db, pChanges);
sqlite3ExprDelete(db, pWhere);
return;
}
@ -668,7 +668,7 @@ static void updateVirtualTable(
sqlite3VdbeAddOp2(v, OP_Close, ephemTab, 0);
/* Cleanup */
sqlite3SelectDelete(pSelect);
sqlite3SelectDelete(db, pSelect);
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */

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.62 2008/06/27 18:59:45 mihailim Exp $
** $Id: utf.c,v 1.63 2008/07/29 11:25:14 danielk1977 Exp $
**
** Notes on UTF-8:
**
@ -154,27 +154,31 @@ static const unsigned char sqlite3UtfTrans1[] = {
** for unicode values 0x80 and greater. It do not change over-length
** encodings to 0xfffd as some systems recommend.
*/
#define READ_UTF8(zIn, zTerm, c) \
c = *(zIn++); \
if( c>=0xc0 ){ \
c = sqlite3UtfTrans1[c-0xc0]; \
while( zIn!=zTerm && (*zIn & 0xc0)==0x80 ){ \
c = (c<<6) + (0x3f & *(zIn++)); \
} \
if( c<0x80 \
|| (c&0xFFFFF800)==0xD800 \
|| (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 **pzNext /* Write first byte past UTF-8 char here */
){
int c = *(z++);
if( c>=0xc0 ){
c = sqlite3UtfTrans1[c-0xc0];
while( z!=zTerm && (*z & 0xc0)==0x80 ){
c = (c<<6) + (0x3f & *(z++));
}
if( c<0x80
|| (c&0xFFFFF800)==0xD800
|| (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; }
}
int c;
READ_UTF8(z, zTerm, c);
*pzNext = z;
return c;
}
/*
** If the TRANSLATE_TRACE macro is defined, the value of each Mem is
** printed on stderr on the way into and out of sqlite3VdbeMemTranslate().
@ -268,14 +272,16 @@ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
if( desiredEnc==SQLITE_UTF16LE ){
/* UTF-8 -> UTF-16 Little-endian */
while( zIn<zTerm ){
c = sqlite3Utf8Read(zIn, zTerm, (const u8**)&zIn);
/* c = sqlite3Utf8Read(zIn, zTerm, (const u8**)&zIn); */
READ_UTF8(zIn, zTerm, c);
WRITE_UTF16LE(z, c);
}
}else{
assert( desiredEnc==SQLITE_UTF16BE );
/* UTF-8 -> UTF-16 Big-endian */
while( zIn<zTerm ){
c = sqlite3Utf8Read(zIn, zTerm, (const u8**)&zIn);
/* c = sqlite3Utf8Read(zIn, zTerm, (const u8**)&zIn); */
READ_UTF8(zIn, zTerm, c);
WRITE_UTF16BE(z, c);
}
}

View File

@ -14,7 +14,7 @@
** This file contains functions for allocating memory, comparing
** strings, and stuff like that.
**
** $Id: util.c,v 1.238 2008/07/11 16:19:10 drh Exp $
** $Id: util.c,v 1.241 2008/07/28 19:34:54 drh Exp $
*/
#include "sqliteInt.h"
#include <stdarg.h>
@ -22,7 +22,7 @@
/*
** Return true if the floating point value is Not a Number.
** Return true if the floating point value is Not a Number (NaN).
*/
int sqlite3IsNaN(double x){
/* This NaN test sometimes fails if compiled on GCC with -ffast-math.
@ -33,6 +33,14 @@ int sqlite3IsNaN(double x){
** -O option since it can result in incorrect output for programs
** which depend on an exact implementation of IEEE or ISO
** rules/specifications for math functions.
**
** Under MSVC, this NaN test may fail if compiled with a floating-
** point precision mode other than /fp:precise. From the MSDN
** documentation:
**
** The compiler [with /fp:precise] will properly handle comparisons
** involving NaN. For example, x != x evaluates to true if x is NaN
** ...
*/
#ifdef __FAST_MATH__
# error SQLite will not work correctly with the -ffast-math option of GCC.
@ -48,11 +56,15 @@ int sqlite3IsNaN(double x){
*/
int sqlite3Strlen(sqlite3 *db, const char *z){
const char *z2 = z;
int len;
size_t x;
while( *z2 ){ z2++; }
if( z2 > &z[db->aLimit[SQLITE_LIMIT_LENGTH]] ){
x = z2 - z;
len = 0x7fffffff & x;
if( len!=x || len > db->aLimit[SQLITE_LIMIT_LENGTH] ){
return db->aLimit[SQLITE_LIMIT_LENGTH];
}else{
return (int)(z2 - z);
return len;
}
}
@ -86,7 +98,7 @@ void sqlite3Error(sqlite3 *db, int err_code, const char *zFormat, ...){
va_start(ap, zFormat);
z = sqlite3VMPrintf(db, zFormat, ap);
va_end(ap);
sqlite3ValueSetStr(db->pErr, -1, z, SQLITE_UTF8, sqlite3_free);
sqlite3ValueSetStr(db->pErr, -1, z, SQLITE_UTF8, SQLITE_DYNAMIC);
}else{
sqlite3ValueSetStr(db->pErr, 0, 0, SQLITE_UTF8, SQLITE_STATIC);
}
@ -112,10 +124,11 @@ void sqlite3Error(sqlite3 *db, int err_code, const char *zFormat, ...){
*/
void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
va_list ap;
sqlite3 *db = pParse->db;
pParse->nErr++;
sqlite3_free(pParse->zErrMsg);
sqlite3DbFree(db, pParse->zErrMsg);
va_start(ap, zFormat);
pParse->zErrMsg = sqlite3VMPrintf(pParse->db, zFormat, ap);
pParse->zErrMsg = sqlite3VMPrintf(db, zFormat, ap);
va_end(ap);
if( pParse->rc==SQLITE_OK ){
pParse->rc = SQLITE_ERROR;
@ -126,7 +139,7 @@ void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
** Clear the error message in pParse, if any
*/
void sqlite3ErrorClear(Parse *pParse){
sqlite3_free(pParse->zErrMsg);
sqlite3DbFree(pParse->db, pParse->zErrMsg);
pParse->zErrMsg = 0;
pParse->nErr = 0;
}

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.761 2008/07/11 21:02:54 drh Exp $
** $Id: vdbe.c,v 1.772 2008/08/02 15:10:09 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@ -890,12 +890,12 @@ case OP_String8: { /* same as TK_STRING, out2-prerelease */
if( encoding!=SQLITE_UTF8 ){
sqlite3VdbeMemSetStr(pOut, pOp->p4.z, -1, SQLITE_UTF8, SQLITE_STATIC);
if( SQLITE_OK!=sqlite3VdbeChangeEncoding(pOut, encoding) ) goto no_mem;
if( SQLITE_OK!=sqlite3VdbeMemDynamicify(pOut) ) goto no_mem;
if( SQLITE_OK!=sqlite3VdbeMemMakeWriteable(pOut) ) goto no_mem;
pOut->zMalloc = 0;
pOut->flags |= MEM_Static;
pOut->flags &= ~MEM_Dyn;
if( pOp->p4type==P4_DYNAMIC ){
sqlite3_free(pOp->p4.z);
sqlite3DbFree(db, pOp->p4.z);
}
pOp->p4type = P4_DYNAMIC;
pOp->p4.z = pOut->z;
@ -1179,6 +1179,8 @@ case OP_Multiply: /* same as TK_STAR, in1, in2, out3 */
case OP_Divide: /* same as TK_SLASH, in1, in2, out3 */
case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
int flags;
applyNumericAffinity(pIn1);
applyNumericAffinity(pIn2);
flags = pIn1->flags | pIn2->flags;
if( (flags & MEM_Null)!=0 ) goto arithmetic_result_is_null;
if( (pIn1->flags & pIn2->flags & MEM_Int)==MEM_Int ){
@ -2155,17 +2157,8 @@ case OP_Column: {
if( aOffset[p2] ){
assert( rc==SQLITE_OK );
if( zRec ){
if( pDest->flags&MEM_Dyn ){
sqlite3VdbeSerialGet((u8 *)&zRec[aOffset[p2]], aType[p2], &sMem);
sMem.db = db;
rc = sqlite3VdbeMemCopy(pDest, &sMem);
assert( !(sMem.flags&MEM_Dyn) );
if( rc!=SQLITE_OK ){
goto op_column_out;
}
}else{
sqlite3VdbeSerialGet((u8 *)&zRec[aOffset[p2]], aType[p2], pDest);
}
sqlite3VdbeMemReleaseExternal(pDest);
sqlite3VdbeSerialGet((u8 *)&zRec[aOffset[p2]], aType[p2], pDest);
}else{
len = sqlite3VdbeSerialTypeLen(aType[p2]);
sqlite3VdbeMemMove(&sMem, pDest);
@ -2605,7 +2598,7 @@ case OP_VerifyCookie: {
iMeta = 0;
}
if( rc==SQLITE_OK && iMeta!=pOp->p2 ){
sqlite3_free(p->zErrMsg);
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed");
/* If the schema-cookie from the database file matches the cookie
** stored with the in-memory representation of the schema, do
@ -3136,7 +3129,14 @@ case OP_IsUnique: { /* jump, in3 */
zKey = pK->z;
nKey = pK->n;
szRowid = sqlite3VdbeIdxRowidLen((u8*)zKey);
/* sqlite3VdbeIdxRowidLen() only returns other than SQLITE_OK when the
** record passed as an argument corrupt. Since the record in this case
** has just been created by an OP_MakeRecord instruction, and not loaded
** from the database file, it is not possible for it to be corrupt.
** Therefore, assert(rc==SQLITE_OK).
*/
rc = sqlite3VdbeIdxRowidLen((u8*)zKey, nKey, &szRowid);
assert(rc==SQLITE_OK);
len = nKey-szRowid;
/* Search for an entry in P1 where all but the last four bytes match K.
@ -3463,7 +3463,7 @@ case OP_Insert: {
}
if( pC->pseudoTable ){
if( !pC->ephemPseudoTable ){
sqlite3_free(pC->pData);
sqlite3DbFree(db, pC->pData);
}
pC->iKey = iKey;
pC->nData = pData->n;
@ -4142,7 +4142,7 @@ case OP_ParseSchema: {
assert( !db->mallocFailed );
rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
if( rc==SQLITE_ABORT ) rc = initData.rc;
sqlite3_free(zSql);
sqlite3DbFree(db, zSql);
db->init.busy = 0;
(void)sqlite3SafetyOn(db);
if( rc==SQLITE_NOMEM ){
@ -4234,7 +4234,7 @@ case OP_IntegrityCk: {
nRoot = pOp->p2;
assert( nRoot>0 );
aRoot = sqlite3Malloc( sizeof(int)*(nRoot+1) );
aRoot = sqlite3DbMallocRaw(db, sizeof(int)*(nRoot+1) );
if( aRoot==0 ) goto no_mem;
assert( pOp->p3>0 && pOp->p3<=p->nMem );
pnErr = &p->aMem[pOp->p3];
@ -4249,16 +4249,18 @@ case OP_IntegrityCk: {
assert( (p->btreeMask & (1<<pOp->p5))!=0 );
z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, aRoot, nRoot,
pnErr->u.i, &nErr);
sqlite3DbFree(db, aRoot);
pnErr->u.i -= nErr;
sqlite3VdbeMemSetNull(pIn1);
if( nErr==0 ){
assert( z==0 );
}else if( z==0 ){
goto no_mem;
}else{
sqlite3VdbeMemSetStr(pIn1, z, -1, SQLITE_UTF8, sqlite3_free);
}
UPDATE_MAX_BLOBSIZE(pIn1);
sqlite3VdbeChangeEncoding(pIn1, encoding);
sqlite3_free(aRoot);
break;
}
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
@ -4268,6 +4270,7 @@ case OP_IntegrityCk: {
** Write the integer from register P1 into the Fifo.
*/
case OP_FifoWrite: { /* in1 */
p->sFifo.db = db;
if( sqlite3VdbeFifoPush(&p->sFifo, sqlite3VdbeIntValue(pIn1))==SQLITE_NOMEM ){
goto no_mem;
}
@ -4315,7 +4318,7 @@ case OP_ContextPush: {
pContext->lastRowid = db->lastRowid;
pContext->nChange = p->nChange;
pContext->sFifo = p->sFifo;
sqlite3VdbeFifoInit(&p->sFifo);
sqlite3VdbeFifoInit(&p->sFifo, db);
break;
}
@ -4569,11 +4572,21 @@ case OP_TableLock: {
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VBegin * * * P4 *
**
** P4 a pointer to an sqlite3_vtab structure. Call the xBegin method
** for that table.
** P4 may be a pointer to an sqlite3_vtab structure. If so, call the
** 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.
*/
case OP_VBegin: {
rc = sqlite3VtabBegin(db, pOp->p4.pVtab);
sqlite3_vtab *pVtab = pOp->p4.pVtab;
rc = sqlite3VtabBegin(db, pVtab);
if( pVtab ){
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = pVtab->zErrMsg;
pVtab->zErrMsg = 0;
}
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@ -4621,6 +4634,9 @@ case OP_VOpen: {
assert(pVtab && pModule);
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
rc = pModule->xOpen(pVtab, &pVtabCursor);
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = pVtab->zErrMsg;
pVtab->zErrMsg = 0;
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
if( SQLITE_OK==rc ){
/* Initialize sqlite3_vtab_cursor base class */
@ -4665,12 +4681,16 @@ case OP_VFilter: { /* jump */
const sqlite3_module *pModule;
Mem *pQuery = &p->aMem[pOp->p3];
Mem *pArgc = &pQuery[1];
sqlite3_vtab_cursor *pVtabCursor;
sqlite3_vtab *pVtab;
Cursor *pCur = p->apCsr[pOp->p1];
REGISTER_TRACE(pOp->p3, pQuery);
assert( pCur->pVtabCursor );
pModule = pCur->pVtabCursor->pVtab->pModule;
pVtabCursor = pCur->pVtabCursor;
pVtab = pVtabCursor->pVtab;
pModule = pVtab->pModule;
/* Grab the index number and argc parameters */
assert( (pQuery->flags&MEM_Int)!=0 && pArgc->flags==MEM_Int );
@ -4688,11 +4708,16 @@ case OP_VFilter: { /* jump */
}
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
sqlite3VtabLock(pVtab);
p->inVtabMethod = 1;
rc = pModule->xFilter(pCur->pVtabCursor, iQuery, pOp->p4.z, nArg, apArg);
rc = pModule->xFilter(pVtabCursor, iQuery, pOp->p4.z, nArg, apArg);
p->inVtabMethod = 0;
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = pVtab->zErrMsg;
pVtab->zErrMsg = 0;
sqlite3VtabUnlock(db, pVtab);
if( rc==SQLITE_OK ){
res = pModule->xEof(pCur->pVtabCursor);
res = pModule->xEof(pVtabCursor);
}
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
@ -4713,6 +4738,7 @@ case OP_VFilter: { /* jump */
** the virtual-table that the P1 cursor is pointing to.
*/
case OP_VRowid: { /* out2-prerelease */
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
sqlite_int64 iRow;
Cursor *pCur = p->apCsr[pOp->p1];
@ -4721,10 +4747,14 @@ case OP_VRowid: { /* out2-prerelease */
if( pCur->nullRow ){
break;
}
pModule = pCur->pVtabCursor->pVtab->pModule;
pVtab = pCur->pVtabCursor->pVtab;
pModule = pVtab->pModule;
assert( pModule->xRowid );
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
rc = pModule->xRowid(pCur->pVtabCursor, &iRow);
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = pVtab->zErrMsg;
pVtab->zErrMsg = 0;
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
MemSetTypeFlag(pOut, MEM_Int);
pOut->u.i = iRow;
@ -4740,6 +4770,7 @@ case OP_VRowid: { /* out2-prerelease */
** P1 cursor is pointing to into register P3.
*/
case OP_VColumn: {
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
Mem *pDest;
sqlite3_context sContext;
@ -4752,7 +4783,8 @@ case OP_VColumn: {
sqlite3VdbeMemSetNull(pDest);
break;
}
pModule = pCur->pVtabCursor->pVtab->pModule;
pVtab = pCur->pVtabCursor->pVtab;
pModule = pVtab->pModule;
assert( pModule->xColumn );
memset(&sContext, 0, sizeof(sContext));
@ -4766,6 +4798,9 @@ case OP_VColumn: {
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
rc = pModule->xColumn(pCur->pVtabCursor, &sContext, pOp->p2);
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = pVtab->zErrMsg;
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
@ -4794,6 +4829,7 @@ case OP_VColumn: {
** the end of its result set, then fall through to the next instruction.
*/
case OP_VNext: { /* jump */
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
int res = 0;
@ -4802,7 +4838,8 @@ case OP_VNext: { /* jump */
if( pCur->nullRow ){
break;
}
pModule = pCur->pVtabCursor->pVtab->pModule;
pVtab = pCur->pVtabCursor->pVtab;
pModule = pVtab->pModule;
assert( pModule->xNext );
/* Invoke the xNext() method of the module. There is no way for the
@ -4812,9 +4849,14 @@ case OP_VNext: { /* jump */
** some other method is next invoked on the save virtual table cursor.
*/
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
sqlite3VtabLock(pVtab);
p->inVtabMethod = 1;
rc = pModule->xNext(pCur->pVtabCursor);
p->inVtabMethod = 0;
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = pVtab->zErrMsg;
pVtab->zErrMsg = 0;
sqlite3VtabUnlock(db, pVtab);
if( rc==SQLITE_OK ){
res = pModule->xEof(pCur->pVtabCursor);
}
@ -4846,6 +4888,9 @@ case OP_VRename: {
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
sqlite3VtabLock(pVtab);
rc = pVtab->pModule->xRename(pVtab, pName->z);
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = pVtab->zErrMsg;
pVtab->zErrMsg = 0;
sqlite3VtabUnlock(db, pVtab);
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
@ -4898,6 +4943,9 @@ case OP_VUpdate: {
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
sqlite3VtabLock(pVtab);
rc = pModule->xUpdate(pVtab, nArg, apArg, &rowid);
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = pVtab->zErrMsg;
pVtab->zErrMsg = 0;
sqlite3VtabUnlock(db, pVtab);
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
if( pOp->p1 && rc==SQLITE_OK ){

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.134 2008/06/25 00:12:41 drh Exp $
** $Id: vdbe.h,v 1.135 2008/08/01 20:10:08 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
@ -177,7 +177,7 @@ int sqlite3VdbeCurrentAddr(Vdbe*);
void sqlite3VdbeTrace(Vdbe*,FILE*);
#endif
void sqlite3VdbeResetStepResult(Vdbe*);
int sqlite3VdbeReset(Vdbe*, int);
int sqlite3VdbeReset(Vdbe*);
void sqlite3VdbeSetNumCols(Vdbe*,int);
int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, int);
void sqlite3VdbeCountChanges(Vdbe*);

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.149 2008/06/25 00:12:41 drh Exp $
** $Id: vdbeInt.h,v 1.153 2008/08/02 03:50:39 drh Exp $
*/
#ifndef _VDBEINT_H_
#define _VDBEINT_H_
@ -245,6 +245,7 @@ struct FifoPage {
typedef struct Fifo Fifo;
struct Fifo {
int nEntry; /* Total number of entries */
sqlite3 *db; /* The associated database connection */
FifoPage *pFirst; /* First page on the list */
FifoPage *pLast; /* Last page on the list */
};
@ -317,7 +318,6 @@ struct Vdbe {
Mem *pResultSet; /* Pointer to an array of results */
u8 explain; /* True if EXPLAIN present on SQL command */
u8 changeCntOn; /* True to update the change-counter */
u8 aborted; /* True if ROLLBACK in another VM causes an abort */
u8 expired; /* True if the VM needs to be recompiled */
u8 minWriteFileFormat; /* Minimum file format for writable database files */
u8 inVtabMethod; /* See comments above */
@ -390,7 +390,7 @@ int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
int sqlite3VdbeIdxKeyCompare(Cursor*,UnpackedRecord *,int,const unsigned char*,int*);
int sqlite3VdbeIdxRowid(BtCursor *, i64 *);
int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);
int sqlite3VdbeIdxRowidLen(const u8*);
int sqlite3VdbeIdxRowidLen(const u8*, int, int*);
int sqlite3VdbeExec(Vdbe*);
int sqlite3VdbeList(Vdbe*);
int sqlite3VdbeHalt(Vdbe*);
@ -406,7 +406,6 @@ void sqlite3VdbeMemSetDouble(Mem*, double);
void sqlite3VdbeMemSetNull(Mem*);
void sqlite3VdbeMemSetZeroBlob(Mem*,int);
int sqlite3VdbeMemMakeWriteable(Mem*);
int sqlite3VdbeMemDynamicify(Mem*);
int sqlite3VdbeMemStringify(Mem*, int);
i64 sqlite3VdbeIntValue(Mem*);
int sqlite3VdbeMemIntegerify(Mem*);
@ -434,7 +433,7 @@ int sqlite3VdbeMemTranslate(Mem*, u8);
void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf);
#endif
int sqlite3VdbeMemHandleBom(Mem *pMem);
void sqlite3VdbeFifoInit(Fifo*);
void sqlite3VdbeFifoInit(Fifo*, sqlite3*);
int sqlite3VdbeFifoPush(Fifo*, i64);
int sqlite3VdbeFifoPop(Fifo*, i64*);
void sqlite3VdbeFifoClear(Fifo*);

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.134 2008/06/19 02:52:25 drh Exp $
** $Id: vdbeapi.c,v 1.138 2008/08/02 03:50:39 drh Exp $
*/
#include "sqliteInt.h"
#include "vdbeInt.h"
@ -228,7 +228,7 @@ int sqlite3_reset(sqlite3_stmt *pStmt){
}else{
Vdbe *v = (Vdbe*)pStmt;
sqlite3_mutex_enter(v->db->mutex);
rc = sqlite3VdbeReset(v, 1);
rc = sqlite3VdbeReset(v);
stmtLruAdd(v);
sqlite3VdbeMakeReady(v, -1, 0, 0, 0);
assert( (rc & (v->db->errMask))==rc );
@ -435,9 +435,6 @@ static int sqlite3Step(Vdbe *p){
db = p->db;
assert( !db->mallocFailed );
if( p->aborted ){
return SQLITE_ABORT;
}
if( p->pc<=0 && p->expired ){
if( p->rc==SQLITE_OK ){
p->rc = SQLITE_SCHEMA;
@ -497,14 +494,16 @@ static int sqlite3Step(Vdbe *p){
}
#endif
sqlite3Error(p->db, rc, 0);
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 */
sqlite3Error(p->db, p->rc, 0);
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
@ -554,7 +553,7 @@ int sqlite3_step(sqlite3_stmt *pStmt){
** sqlite3_errmsg() and sqlite3_errcode().
*/
const char *zErr = (const char *)sqlite3_value_text(db->pErr);
sqlite3_free(v->zErrMsg);
sqlite3DbFree(db, v->zErrMsg);
if( !db->mallocFailed ){
v->zErrMsg = sqlite3DbStrDup(db, zErr);
} else {

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.397 2008/07/11 21:02:54 drh Exp $
** $Id: vdbeaux.c,v 1.405 2008/08/02 03:50:39 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@ -302,7 +302,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
pOp->p2 = aLabel[-1-pOp->p2];
}
}
sqlite3_free(p->aLabel);
sqlite3DbFree(p->db, p->aLabel);
p->aLabel = 0;
*pMaxFuncArgs = nMaxArgs;
@ -432,16 +432,16 @@ void sqlite3VdbeJumpHere(Vdbe *p, int addr){
** If the input FuncDef structure is ephemeral, then free it. If
** the FuncDef is not ephermal, then do nothing.
*/
static void freeEphemeralFunction(FuncDef *pDef){
static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){
if( pDef && (pDef->flags & SQLITE_FUNC_EPHEM)!=0 ){
sqlite3_free(pDef);
sqlite3DbFree(db, pDef);
}
}
/*
** Delete a P4 value if necessary.
*/
static void freeP4(int p4type, void *p4){
static void freeP4(sqlite3 *db, int p4type, void *p4){
if( p4 ){
switch( p4type ){
case P4_REAL:
@ -451,18 +451,18 @@ static void freeP4(int p4type, void *p4){
case P4_KEYINFO:
case P4_INTARRAY:
case P4_KEYINFO_HANDOFF: {
sqlite3_free(p4);
sqlite3DbFree(db, p4);
break;
}
case P4_VDBEFUNC: {
VdbeFunc *pVdbeFunc = (VdbeFunc *)p4;
freeEphemeralFunction(pVdbeFunc->pFunc);
freeEphemeralFunction(db, pVdbeFunc->pFunc);
sqlite3VdbeDeleteAuxData(pVdbeFunc, 0);
sqlite3_free(pVdbeFunc);
sqlite3DbFree(db, pVdbeFunc);
break;
}
case P4_FUNCDEF: {
freeEphemeralFunction((FuncDef*)p4);
freeEphemeralFunction(db, (FuncDef*)p4);
break;
}
case P4_MEM: {
@ -480,8 +480,9 @@ static void freeP4(int p4type, void *p4){
void sqlite3VdbeChangeToNoop(Vdbe *p, int addr, int N){
if( p && p->aOp ){
VdbeOp *pOp = &p->aOp[addr];
sqlite3 *db = p->db;
while( N-- ){
freeP4(pOp->p4type, pOp->p4.p);
freeP4(db, pOp->p4type, pOp->p4.p);
memset(pOp, 0, sizeof(pOp[0]));
pOp->opcode = OP_Noop;
pOp++;
@ -516,11 +517,13 @@ void sqlite3VdbeChangeToNoop(Vdbe *p, int addr, int N){
*/
void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){
Op *pOp;
sqlite3 *db;
assert( p!=0 );
db = p->db;
assert( p->magic==VDBE_MAGIC_INIT );
if( p->aOp==0 || p->db->mallocFailed ){
if( p->aOp==0 || db->mallocFailed ){
if (n != P4_KEYINFO) {
freeP4(n, (void*)*(char**)&zP4);
freeP4(db, n, (void*)*(char**)&zP4);
}
return;
}
@ -530,7 +533,7 @@ void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){
if( addr<0 ) return;
}
pOp = &p->aOp[addr];
freeP4(pOp->p4type, pOp->p4.p);
freeP4(db, pOp->p4type, pOp->p4.p);
pOp->p4.p = 0;
if( n==P4_INT32 ){
/* Note: this cast is safe, because the origin data point was an int
@ -588,7 +591,7 @@ void sqlite3VdbeComment(Vdbe *p, const char *zFormat, ...){
if( p->nOp ){
char **pz = &p->aOp[p->nOp-1].zComment;
va_start(ap, zFormat);
sqlite3_free(*pz);
sqlite3DbFree(p->db, *pz);
*pz = sqlite3VMPrintf(p->db, zFormat, ap);
va_end(ap);
}
@ -601,7 +604,7 @@ void sqlite3VdbeNoopComment(Vdbe *p, const char *zFormat, ...){
if( p->nOp ){
char **pz = &p->aOp[p->nOp-1].zComment;
va_start(ap, zFormat);
sqlite3_free(*pz);
sqlite3DbFree(p->db, *pz);
*pz = sqlite3VMPrintf(p->db, zFormat, ap);
va_end(ap);
}
@ -756,17 +759,13 @@ void sqlite3VdbePrintOp(FILE *pOut, int pc, Op *pOp){
/*
** Release an array of N Mem elements
*/
static void releaseMemArray(Mem *p, int N, int freebuffers){
static void releaseMemArray(Mem *p, int N){
if( p && N ){
sqlite3 *db = p->db;
int malloc_failed = db->mallocFailed;
while( N-->0 ){
assert( N<2 || p[0].db==p[1].db );
if( freebuffers ){
sqlite3VdbeMemRelease(p);
}else{
sqlite3VdbeMemReleaseExternal(p);
}
sqlite3VdbeMemRelease(p);
p->flags = MEM_Null;
p++;
}
@ -783,7 +782,7 @@ int sqlite3VdbeReleaseBuffers(Vdbe *p){
Mem *pMem = &p->aMem[ii];
if( pMem->z && pMem->flags&MEM_Dyn ){
assert( !pMem->xDel );
nFree += sqlite3MallocSize(pMem->z);
nFree += sqlite3DbMallocSize(pMem->db, pMem->z);
sqlite3VdbeMemRelease(pMem);
}
}
@ -821,7 +820,7 @@ int sqlite3VdbeList(
** the result, result columns may become dynamic if the user calls
** sqlite3_column_text16(), causing a translation to UTF-16 encoding.
*/
releaseMemArray(pMem, p->nMem, 1);
releaseMemArray(pMem, p->nMem);
do{
i = p->pc++;
@ -1102,11 +1101,8 @@ void sqlite3VdbeFreeCursor(Vdbe *p, Cursor *pCx){
}
#endif
if( !pCx->ephemPseudoTable ){
sqlite3_free(pCx->pData);
sqlite3DbFree(p->db, pCx->pData);
}
/* memset(pCx, 0, sizeof(Cursor)); */
/* sqlite3_free(pCx->aType); */
/* sqlite3_free(pCx); */
}
/*
@ -1132,24 +1128,25 @@ static void closeAllCursorsExceptActiveVtabs(Vdbe *p){
** sorters that were left open. It also deletes the values of
** variables in the aVar[] array.
*/
static void Cleanup(Vdbe *p, int freebuffers){
static void Cleanup(Vdbe *p){
int i;
sqlite3 *db = p->db;
closeAllCursorsExceptActiveVtabs(p);
for(i=1; i<=p->nMem; i++){
MemSetTypeFlag(&p->aMem[i], MEM_Null);
}
releaseMemArray(&p->aMem[1], p->nMem, freebuffers);
releaseMemArray(&p->aMem[1], p->nMem);
sqlite3VdbeFifoClear(&p->sFifo);
if( p->contextStack ){
for(i=0; i<p->contextStackTop; i++){
sqlite3VdbeFifoClear(&p->contextStack[i].sFifo);
}
sqlite3_free(p->contextStack);
sqlite3DbFree(db, p->contextStack);
}
p->contextStack = 0;
p->contextStackDepth = 0;
p->contextStackTop = 0;
sqlite3_free(p->zErrMsg);
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = 0;
p->pResultSet = 0;
}
@ -1163,12 +1160,13 @@ static void Cleanup(Vdbe *p, int freebuffers){
void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){
Mem *pColName;
int n;
sqlite3 *db = p->db;
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N, 1);
sqlite3_free(p->aColName);
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
sqlite3DbFree(db, p->aColName);
n = nResColumn*COLNAME_N;
p->nResColumn = nResColumn;
p->aColName = pColName = (Mem*)sqlite3DbMallocZero(p->db, sizeof(Mem)*n );
p->aColName = pColName = (Mem*)sqlite3DbMallocZero(db, sizeof(Mem)*n );
if( p->aColName==0 ) return;
while( n-- > 0 ){
pColName->flags = MEM_Null;
@ -1185,7 +1183,7 @@ void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){
**
** If N==P4_STATIC it means that zName is a pointer to a constant static
** string and we can just copy the pointer. If it is P4_DYNAMIC, then
** the string is freed using sqlite3_free() when the vdbe is finished with
** the string is freed using sqlite3DbFree(db, ) when the vdbe is finished with
** it. Otherwise, N bytes of zName are copied.
*/
int sqlite3VdbeSetColName(Vdbe *p, int idx, int var, const char *zName, int N){
@ -1214,7 +1212,7 @@ int sqlite3VdbeSetColName(Vdbe *p, int idx, int var, const char *zName, int N){
** write-transaction spanning more than one database file, this routine
** takes care of the master journal trickery.
*/
static int vdbeCommit(sqlite3 *db){
static int vdbeCommit(sqlite3 *db, Vdbe *p){
int i;
int nTrans = 0; /* Number of databases with an active write-transaction */
int rc = SQLITE_OK;
@ -1226,7 +1224,7 @@ static int vdbeCommit(sqlite3 *db){
** required, as an xSync() callback may add an attached database
** to the transaction.
*/
rc = sqlite3VtabSync(db, rc);
rc = sqlite3VtabSync(db, &p->zErrMsg);
if( rc!=SQLITE_OK ){
return rc;
}
@ -1305,7 +1303,7 @@ static int vdbeCommit(sqlite3 *db){
/* Select a master journal file name */
do {
u32 random;
sqlite3_free(zMaster);
sqlite3DbFree(db, zMaster);
sqlite3_randomness(sizeof(random), &random);
zMaster = sqlite3MPrintf(db, "%s-mj%08X", zMainFile, random&0x7fffffff);
if( !zMaster ){
@ -1321,7 +1319,7 @@ static int vdbeCommit(sqlite3 *db){
);
}
if( rc!=SQLITE_OK ){
sqlite3_free(zMaster);
sqlite3DbFree(db, zMaster);
return rc;
}
@ -1345,7 +1343,7 @@ static int vdbeCommit(sqlite3 *db){
if( rc!=SQLITE_OK ){
sqlite3OsCloseFree(pMaster);
sqlite3OsDelete(pVfs, zMaster, 0);
sqlite3_free(zMaster);
sqlite3DbFree(db, zMaster);
return rc;
}
}
@ -1360,7 +1358,7 @@ static int vdbeCommit(sqlite3 *db){
&& (rc=sqlite3OsSync(pMaster, SQLITE_SYNC_NORMAL))!=SQLITE_OK) ){
sqlite3OsCloseFree(pMaster);
sqlite3OsDelete(pVfs, zMaster, 0);
sqlite3_free(zMaster);
sqlite3DbFree(db, zMaster);
return rc;
}
@ -1382,7 +1380,7 @@ static int vdbeCommit(sqlite3 *db){
}
sqlite3OsCloseFree(pMaster);
if( rc!=SQLITE_OK ){
sqlite3_free(zMaster);
sqlite3DbFree(db, zMaster);
return rc;
}
@ -1391,7 +1389,7 @@ static int vdbeCommit(sqlite3 *db){
** transaction files are deleted.
*/
rc = sqlite3OsDelete(pVfs, zMaster, 1);
sqlite3_free(zMaster);
sqlite3DbFree(db, zMaster);
zMaster = 0;
if( rc ){
return rc;
@ -1590,7 +1588,7 @@ int sqlite3VdbeHalt(Vdbe *p){
** successful or hit an 'OR FAIL' constraint. This means a commit
** is required.
*/
int rc = vdbeCommit(db);
int rc = vdbeCommit(db, p);
if( rc==SQLITE_BUSY ){
sqlite3BtreeMutexArrayLeave(&p->aMutex);
return SQLITE_BUSY;
@ -1633,7 +1631,7 @@ int sqlite3VdbeHalt(Vdbe *p){
rc = xFunc(pBt);
if( rc && (p->rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT) ){
p->rc = rc;
sqlite3_free(p->zErrMsg);
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = 0;
}
}
@ -1694,7 +1692,7 @@ void sqlite3VdbeResetStepResult(Vdbe *p){
** virtual machine from VDBE_MAGIC_RUN or VDBE_MAGIC_HALT back to
** VDBE_MAGIC_INIT.
*/
int sqlite3VdbeReset(Vdbe *p, int freebuffers){
int sqlite3VdbeReset(Vdbe *p){
sqlite3 *db;
db = p->db;
@ -1713,8 +1711,9 @@ int sqlite3VdbeReset(Vdbe *p, int freebuffers){
*/
if( p->pc>=0 ){
if( p->zErrMsg ){
sqlite3ValueSetStr(db->pErr,-1,p->zErrMsg,SQLITE_UTF8,sqlite3_free);
sqlite3ValueSetStr(db->pErr,-1,p->zErrMsg,SQLITE_UTF8,SQLITE_TRANSIENT);
db->errCode = p->rc;
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = 0;
}else if( p->rc ){
sqlite3Error(db, p->rc, 0);
@ -1727,13 +1726,14 @@ int sqlite3VdbeReset(Vdbe *p, int freebuffers){
** called), set the database error in this case as well.
*/
sqlite3Error(db, p->rc, 0);
sqlite3ValueSetStr(db->pErr, -1, p->zErrMsg, SQLITE_UTF8, sqlite3_free);
sqlite3ValueSetStr(db->pErr, -1, p->zErrMsg, SQLITE_UTF8, SQLITE_TRANSIENT);
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = 0;
}
/* Reclaim all memory used by the VDBE
*/
Cleanup(p, freebuffers);
Cleanup(p);
/* Save profiling information from this VDBE run.
*/
@ -1760,7 +1760,6 @@ int sqlite3VdbeReset(Vdbe *p, int freebuffers){
}
#endif
p->magic = VDBE_MAGIC_INIT;
p->aborted = 0;
return p->rc & db->errMask;
}
@ -1771,12 +1770,11 @@ int sqlite3VdbeReset(Vdbe *p, int freebuffers){
int sqlite3VdbeFinalize(Vdbe *p){
int rc = SQLITE_OK;
if( p->magic==VDBE_MAGIC_RUN || p->magic==VDBE_MAGIC_HALT ){
rc = sqlite3VdbeReset(p, 1);
rc = sqlite3VdbeReset(p);
assert( (rc & p->db->errMask)==rc );
}else if( p->magic!=VDBE_MAGIC_INIT ){
return SQLITE_MISUSE;
}
releaseMemArray(&p->aMem[1], p->nMem, 1);
sqlite3VdbeDelete(p);
return rc;
}
@ -1805,13 +1803,15 @@ void sqlite3VdbeDeleteAuxData(VdbeFunc *pVdbeFunc, int mask){
*/
void sqlite3VdbeDelete(Vdbe *p){
int i;
sqlite3 *db;
if( p==0 ) return;
Cleanup(p, 1);
db = p->db;
if( p->pPrev ){
p->pPrev->pNext = p->pNext;
}else{
assert( p->db->pVdbe==p );
p->db->pVdbe = p->pNext;
assert( db->pVdbe==p );
db->pVdbe = p->pNext;
}
if( p->pNext ){
p->pNext->pPrev = p->pPrev;
@ -1819,23 +1819,23 @@ void sqlite3VdbeDelete(Vdbe *p){
if( p->aOp ){
Op *pOp = p->aOp;
for(i=0; i<p->nOp; i++, pOp++){
freeP4(pOp->p4type, pOp->p4.p);
freeP4(db, pOp->p4type, pOp->p4.p);
#ifdef SQLITE_DEBUG
sqlite3_free(pOp->zComment);
sqlite3DbFree(db, pOp->zComment);
#endif
}
sqlite3_free(p->aOp);
sqlite3DbFree(db, p->aOp);
}
releaseMemArray(p->aVar, p->nVar, 1);
sqlite3_free(p->aLabel);
releaseMemArray(p->aVar, p->nVar);
sqlite3DbFree(db, p->aLabel);
if( p->aMem ){
sqlite3_free(&p->aMem[1]);
sqlite3DbFree(db, &p->aMem[1]);
}
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N, 1);
sqlite3_free(p->aColName);
sqlite3_free(p->zSql);
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
sqlite3DbFree(db, p->aColName);
sqlite3DbFree(db, p->zSql);
p->magic = VDBE_MAGIC_DEAD;
sqlite3_free(p);
sqlite3DbFree(db, p);
}
/*
@ -1881,9 +1881,9 @@ int sqlite3VdbeCursorMoveto(Cursor *p){
**
** sqlite3VdbeSerialType()
** sqlite3VdbeSerialTypeLen()
** sqlite3VdbeSerialRead()
** sqlite3VdbeSerialLen()
** sqlite3VdbeSerialWrite()
** sqlite3VdbeSerialPut()
** sqlite3VdbeSerialGet()
**
** encapsulate the code that serializes values for storage in SQLite
** data and index records. Each serialized value consists of a
@ -2205,7 +2205,8 @@ UnpackedRecord *sqlite3VdbeRecordUnpack(
const unsigned char *aKey = (const unsigned char *)pKey;
UnpackedRecord *p;
int nByte;
int i, idx, d;
int idx, d;
u16 u; /* Unsigned loop counter */
u32 szHdr;
Mem *pMem;
@ -2225,8 +2226,8 @@ UnpackedRecord *sqlite3VdbeRecordUnpack(
p->aMem = pMem = &((Mem*)p)[1];
idx = getVarint32(aKey, szHdr);
d = szHdr;
i = 0;
while( idx<szHdr && i<p->nField ){
u = 0;
while( idx<szHdr && u<p->nField ){
u32 serial_type;
idx += getVarint32( aKey+idx, serial_type);
@ -2237,9 +2238,9 @@ UnpackedRecord *sqlite3VdbeRecordUnpack(
pMem->zMalloc = 0;
d += sqlite3VdbeSerialGet(&aKey[d], serial_type, pMem);
pMem++;
i++;
u++;
}
p->nField = i;
p->nField = u;
return (void*)p;
}
@ -2258,7 +2259,7 @@ void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord *p){
}
}
if( p->needFree ){
sqlite3_free(p);
sqlite3DbFree(p->pKeyInfo->db, p);
}
}
}
@ -2353,13 +2354,17 @@ int sqlite3VdbeRecordCompare(
** an integer rowid). This routine returns the number of bytes in
** that integer.
*/
int sqlite3VdbeIdxRowidLen(const u8 *aKey){
int sqlite3VdbeIdxRowidLen(const u8 *aKey, int nKey, int *pRowidLen){
u32 szHdr; /* Size of the header */
u32 typeRowid; /* Serial type of the rowid */
(void)getVarint32(aKey, szHdr);
if( szHdr>nKey ){
return SQLITE_CORRUPT_BKPT;
}
(void)getVarint32(&aKey[szHdr-1], typeRowid);
return sqlite3VdbeSerialTypeLen(typeRowid);
*pRowidLen = sqlite3VdbeSerialTypeLen(typeRowid);
return SQLITE_OK;
}
@ -2428,11 +2433,11 @@ int sqlite3VdbeIdxKeyCompare(
m.db = 0;
m.flags = 0;
m.zMalloc = 0;
rc = sqlite3VdbeMemFromBtree(pC->pCursor, 0, nCellKey, 1, &m);
if( rc ){
if( (rc = sqlite3VdbeMemFromBtree(pC->pCursor, 0, nCellKey, 1, &m))
|| (rc = sqlite3VdbeIdxRowidLen((u8*)m.z, m.n, &lenRowid))
){
return rc;
}
lenRowid = sqlite3VdbeIdxRowidLen((u8*)m.z);
if( !pUnpacked ){
pRec = sqlite3VdbeRecordUnpack(pC->pKeyInfo, nKey, pKey,
zSpace, sizeof(zSpace));

View File

@ -12,7 +12,7 @@
**
** This file contains code used to implement incremental BLOB I/O.
**
** $Id: vdbeblob.c,v 1.24 2008/07/10 00:32:42 drh Exp $
** $Id: vdbeblob.c,v 1.25 2008/07/28 19:34:54 drh Exp $
*/
#include "sqliteInt.h"
@ -117,7 +117,7 @@ int sqlite3_blob_open(
if( sParse.zErrMsg ){
sqlite3_snprintf(sizeof(zErr), zErr, "%s", sParse.zErrMsg);
}
sqlite3_free(sParse.zErrMsg);
sqlite3DbFree(db, sParse.zErrMsg);
rc = SQLITE_ERROR;
(void)sqlite3SafetyOff(db);
sqlite3BtreeLeaveAll(db);
@ -229,7 +229,7 @@ int sqlite3_blob_open(
}
pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob));
if( db->mallocFailed ){
sqlite3_free(pBlob);
sqlite3DbFree(db, pBlob);
goto blob_open_out;
}
pBlob->flags = flags;
@ -268,7 +268,7 @@ int sqlite3_blob_close(sqlite3_blob *pBlob){
int rc;
rc = sqlite3_finalize(p->pStmt);
sqlite3_free(p);
sqlite3DbFree(p->db, p);
return rc;
}

View File

@ -12,7 +12,7 @@
** This file implements a FIFO queue of rowids used for processing
** UPDATE and DELETE statements.
**
** $Id: vdbefifo.c,v 1.7 2008/06/15 02:51:48 drh Exp $
** $Id: vdbefifo.c,v 1.8 2008/07/28 19:34:54 drh Exp $
*/
#include "sqliteInt.h"
#include "vdbeInt.h"
@ -33,12 +33,12 @@
** Allocate a new FifoPage and return a pointer to it. Return NULL if
** we run out of memory. Leave space on the page for nEntry entries.
*/
static FifoPage *allocateFifoPage(int nEntry){
static FifoPage *allocateFifoPage(sqlite3 *db, int nEntry){
FifoPage *pPage;
if( nEntry>FIFOSIZE_MAX ){
nEntry = FIFOSIZE_MAX;
}
pPage = sqlite3Malloc( sizeof(FifoPage) + sizeof(i64)*(nEntry-1) );
pPage = sqlite3DbMallocRaw(db, sizeof(FifoPage) + sizeof(i64)*(nEntry-1) );
if( pPage ){
pPage->nSlot = nEntry;
pPage->iWrite = 0;
@ -51,8 +51,9 @@ static FifoPage *allocateFifoPage(int nEntry){
/*
** Initialize a Fifo structure.
*/
void sqlite3VdbeFifoInit(Fifo *pFifo){
void sqlite3VdbeFifoInit(Fifo *pFifo, sqlite3 *db){
memset(pFifo, 0, sizeof(*pFifo));
pFifo->db = db;
}
/*
@ -64,12 +65,13 @@ int sqlite3VdbeFifoPush(Fifo *pFifo, i64 val){
FifoPage *pPage;
pPage = pFifo->pLast;
if( pPage==0 ){
pPage = pFifo->pLast = pFifo->pFirst = allocateFifoPage(FIFOSIZE_FIRST);
pPage = pFifo->pLast = pFifo->pFirst =
allocateFifoPage(pFifo->db, FIFOSIZE_FIRST);
if( pPage==0 ){
return SQLITE_NOMEM;
}
}else if( pPage->iWrite>=pPage->nSlot ){
pPage->pNext = allocateFifoPage(pFifo->nEntry);
pPage->pNext = allocateFifoPage(pFifo->db, pFifo->nEntry);
if( pPage->pNext==0 ){
return SQLITE_NOMEM;
}
@ -101,7 +103,7 @@ int sqlite3VdbeFifoPop(Fifo *pFifo, i64 *pVal){
pFifo->nEntry--;
if( pPage->iRead>=pPage->iWrite ){
pFifo->pFirst = pPage->pNext;
sqlite3_free(pPage);
sqlite3DbFree(pFifo->db, pPage);
if( pFifo->nEntry==0 ){
assert( pFifo->pLast==pPage );
pFifo->pLast = 0;
@ -122,7 +124,7 @@ void sqlite3VdbeFifoClear(Fifo *pFifo){
FifoPage *pPage, *pNextPage;
for(pPage=pFifo->pFirst; pPage; pPage=pNextPage){
pNextPage = pPage->pNext;
sqlite3_free(pPage);
sqlite3DbFree(pFifo->db, pPage);
}
sqlite3VdbeFifoInit(pFifo);
sqlite3VdbeFifoInit(pFifo, pFifo->db);
}

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.118 2008/07/09 16:51:51 drh Exp $
** $Id: vdbemem.c,v 1.121 2008/08/01 20:10:09 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@ -83,7 +83,7 @@ int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve){
);
if( n<32 ) n = 32;
if( sqlite3MallocSize(pMem->zMalloc)<n ){
if( sqlite3DbMallocSize(pMem->db, pMem->zMalloc)<n ){
if( preserve && pMem->z==pMem->zMalloc ){
pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n);
if( !pMem->z ){
@ -91,7 +91,7 @@ int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve){
}
preserve = 0;
}else{
sqlite3_free(pMem->zMalloc);
sqlite3DbFree(pMem->db, pMem->zMalloc);
pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, n);
}
}
@ -110,11 +110,14 @@ int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve){
}
/*
** Make the given Mem object MEM_Dyn.
** Make the given Mem object MEM_Dyn. In other words, make it so
** that any TEXT or BLOB content is stored in memory obtained from
** malloc(). In this way, we know that the memory is safe to be
** overwritten or altered.
**
** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails.
*/
int sqlite3VdbeMemDynamicify(Mem *pMem){
int sqlite3VdbeMemMakeWriteable(Mem *pMem){
int f;
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
expandBlob(pMem);
@ -160,16 +163,6 @@ int sqlite3VdbeMemExpandBlob(Mem *pMem){
#endif
/*
** Make the given Mem object either MEM_Short or MEM_Dyn so that bytes
** of the Mem.z[] array can be modified.
**
** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails.
*/
int sqlite3VdbeMemMakeWriteable(Mem *pMem){
return sqlite3VdbeMemDynamicify(pMem);
}
/*
** Make sure the given Mem is \u0000 terminated.
*/
@ -255,7 +248,7 @@ int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
ctx.isError = 0;
pFunc->xFinalize(&ctx);
assert( 0==(pMem->flags&MEM_Dyn) && !pMem->xDel );
sqlite3_free(pMem->zMalloc);
sqlite3DbFree(pMem->db, pMem->zMalloc);
*pMem = ctx.s;
rc = (ctx.isError?SQLITE_ERROR:SQLITE_OK);
}
@ -286,7 +279,7 @@ void sqlite3VdbeMemReleaseExternal(Mem *p){
*/
void sqlite3VdbeMemRelease(Mem *p){
sqlite3VdbeMemReleaseExternal(p);
sqlite3_free(p->zMalloc);
sqlite3DbFree(p->db, p->zMalloc);
p->z = 0;
p->zMalloc = 0;
p->xDel = 0;
@ -631,6 +624,10 @@ int sqlite3VdbeMemSetStr(
return SQLITE_NOMEM;
}
memcpy(pMem->z, z, nAlloc);
}else if( xDel==SQLITE_DYNAMIC ){
sqlite3VdbeMemRelease(pMem);
pMem->zMalloc = pMem->z = (char *)z;
pMem->xDel = 0;
}else{
sqlite3VdbeMemRelease(pMem);
pMem->z = (char *)z;
@ -966,11 +963,11 @@ int sqlite3ValueFromExpr(
op = pExpr->op;
if( op==TK_STRING || op==TK_FLOAT || op==TK_INTEGER ){
zVal = sqlite3StrNDup((char*)pExpr->token.z, pExpr->token.n);
zVal = sqlite3DbStrNDup(db, (char*)pExpr->token.z, pExpr->token.n);
pVal = sqlite3ValueNew(db);
if( !zVal || !pVal ) goto no_mem;
sqlite3Dequote(zVal);
sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, sqlite3_free);
sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC);
if( (op==TK_INTEGER || op==TK_FLOAT ) && affinity==SQLITE_AFF_NONE ){
sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, enc);
}else{
@ -993,7 +990,7 @@ int sqlite3ValueFromExpr(
nVal = pExpr->token.n - 3;
zVal = (char*)pExpr->token.z + 2;
sqlite3VdbeMemSetStr(pVal, sqlite3HexToBlob(db, zVal, nVal), nVal/2,
0, sqlite3_free);
0, SQLITE_DYNAMIC);
}
#endif
@ -1002,7 +999,7 @@ int sqlite3ValueFromExpr(
no_mem:
db->mallocFailed = 1;
sqlite3_free(zVal);
sqlite3DbFree(db, zVal);
sqlite3ValueFree(pVal);
*ppVal = 0;
return SQLITE_NOMEM;
@ -1027,7 +1024,7 @@ void sqlite3ValueSetStr(
void sqlite3ValueFree(sqlite3_value *v){
if( !v ) return;
sqlite3VdbeMemRelease((Mem *)v);
sqlite3_free(v);
sqlite3DbFree(((Mem*)v)->db, v);
}
/*

View File

@ -11,7 +11,7 @@
*************************************************************************
** This file contains code used to help implement virtual tables.
**
** $Id: vtab.c,v 1.70 2008/06/23 17:44:19 danielk1977 Exp $
** $Id: vtab.c,v 1.74 2008/08/02 03:50:39 drh Exp $
*/
#ifndef SQLITE_OMIT_VIRTUALTABLE
#include "sqliteInt.h"
@ -41,7 +41,7 @@ static int createModule(
if( pDel && pDel->xDestroy ){
pDel->xDestroy(pDel->pAux);
}
sqlite3_free(pDel);
sqlite3DbFree(db, pDel);
if( pDel==pMod ){
db->mallocFailed = 1;
}
@ -116,17 +116,18 @@ void sqlite3VtabUnlock(sqlite3 *db, sqlite3_vtab *pVtab){
*/
void sqlite3VtabClear(Table *p){
sqlite3_vtab *pVtab = p->pVtab;
sqlite3 *db = p->db;
if( pVtab ){
assert( p->pMod && p->pMod->pModule );
sqlite3VtabUnlock(p->pSchema->db, pVtab);
sqlite3VtabUnlock(db, pVtab);
p->pVtab = 0;
}
if( p->azModuleArg ){
int i;
for(i=0; i<p->nModuleArg; i++){
sqlite3_free(p->azModuleArg[i]);
sqlite3DbFree(db, p->azModuleArg[i]);
}
sqlite3_free(p->azModuleArg);
sqlite3DbFree(db, p->azModuleArg);
}
}
@ -144,10 +145,10 @@ static void addModuleArgument(sqlite3 *db, Table *pTable, char *zArg){
if( azModuleArg==0 ){
int j;
for(j=0; j<i; j++){
sqlite3_free(pTable->azModuleArg[j]);
sqlite3DbFree(db, pTable->azModuleArg[j]);
}
sqlite3_free(zArg);
sqlite3_free(pTable->azModuleArg);
sqlite3DbFree(db, zArg);
sqlite3DbFree(db, pTable->azModuleArg);
pTable->nModuleArg = 0;
}else{
azModuleArg[i] = zArg;
@ -278,7 +279,7 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
zStmt,
pParse->regRowid
);
sqlite3_free(zStmt);
sqlite3DbFree(db, zStmt);
v = sqlite3GetVdbe(pParse);
sqlite3ChangeCookie(pParse, iDb);
@ -377,7 +378,7 @@ static int vtabCallConstructor(
*pzErr = sqlite3MPrintf(db, "vtable constructor failed: %s", zModuleName);
}else {
*pzErr = sqlite3MPrintf(db, "%s", zErr);
sqlite3_free(zErr);
sqlite3DbFree(db, zErr);
}
}else if( db->pVTab ){
const char *zFormat = "vtable constructor did not declare schema: %s";
@ -388,7 +389,7 @@ static int vtabCallConstructor(
rc = rc2;
}
db->pVTab = 0;
sqlite3_free(zModuleName);
sqlite3DbFree(db, zModuleName);
/* If everything went according to plan, loop through the columns
** of the table to see if any of them contain the token "hidden".
@ -457,7 +458,7 @@ int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
if( rc!=SQLITE_OK ){
sqlite3ErrorMsg(pParse, "%s", zErr);
}
sqlite3_free(zErr);
sqlite3DbFree(db, zErr);
}
return rc;
@ -493,7 +494,7 @@ static int addToVTrans(sqlite3 *db, sqlite3_vtab *pVtab){
**
** If an error occurs, *pzErr is set to point an an English language
** description of the error and an SQLITE_XXX error code is returned.
** In this case the caller must call sqlite3_free() on *pzErr.
** In this case the caller must call sqlite3DbFree(db, ) on *pzErr.
*/
int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){
int rc = SQLITE_OK;
@ -562,7 +563,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
db->pVTab = 0;
} else {
sqlite3Error(db, SQLITE_ERROR, zErr);
sqlite3_free(zErr);
sqlite3DbFree(db, zErr);
rc = SQLITE_ERROR;
}
sParse.declareVtab = 0;
@ -632,24 +633,25 @@ static void callFinaliser(sqlite3 *db, int offset){
if( x ) x(pVtab);
sqlite3VtabUnlock(db, pVtab);
}
sqlite3_free(db->aVTrans);
sqlite3DbFree(db, db->aVTrans);
db->nVTrans = 0;
db->aVTrans = 0;
}
}
/*
** If argument rc2 is not SQLITE_OK, then return it and do nothing.
** Otherwise, invoke the xSync method of all virtual tables in the
** sqlite3.aVTrans array. Return the error code for the first error
** that occurs, or SQLITE_OK if all xSync operations are successful.
** Invoke the xSync method of all virtual tables in the sqlite3.aVTrans
** array. Return the error code for the first error that occurs, or
** SQLITE_OK if all xSync operations are successful.
**
** Set *pzErrmsg to point to a buffer that should be released using
** sqlite3DbFree() containing an error message, if one is available.
*/
int sqlite3VtabSync(sqlite3 *db, int rc2){
int sqlite3VtabSync(sqlite3 *db, char **pzErrmsg){
int i;
int rc = SQLITE_OK;
int rcsafety;
sqlite3_vtab **aVTrans = db->aVTrans;
if( rc2!=SQLITE_OK ) return rc2;
rc = sqlite3SafetyOff(db);
db->aVTrans = 0;
@ -659,6 +661,9 @@ int sqlite3VtabSync(sqlite3 *db, int rc2){
x = pVtab->pModule->xSync;
if( x ){
rc = x(pVtab);
sqlite3DbFree(db, *pzErrmsg);
*pzErrmsg = pVtab->zErrMsg;
pVtab->zErrMsg = 0;
}
}
db->aVTrans = aVTrans;
@ -726,11 +731,9 @@ int sqlite3VtabBegin(sqlite3 *db, sqlite3_vtab *pVtab){
/* Invoke the xBegin method */
rc = pModule->xBegin(pVtab);
if( rc!=SQLITE_OK ){
return rc;
if( rc==SQLITE_OK ){
rc = addToVTrans(db, pVtab);
}
rc = addToVTrans(db, pVtab);
}
return rc;
}
@ -786,7 +789,12 @@ FuncDef *sqlite3VtabOverloadFunction(
*z = sqlite3UpperToLower[*z];
}
rc = pMod->xFindFunction(pVtab, nArg, zLowerName, &xFunc, &pArg);
sqlite3_free(zLowerName);
sqlite3DbFree(db, zLowerName);
if( pVtab->zErrMsg ){
sqlite3Error(db, rc, "%s", pVtab->zErrMsg);
sqlite3DbFree(db, pVtab->zErrMsg);
pVtab->zErrMsg = 0;
}
}
if( rc==0 ){
return pDef;

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.317 2008/07/12 14:52:20 drh Exp $
** $Id: where.c,v 1.319 2008/08/01 17:37:41 danielk1977 Exp $
*/
#include "sqliteInt.h"
@ -92,7 +92,7 @@ struct WhereTerm {
/*
** Allowed values of WhereTerm.flags
*/
#define TERM_DYNAMIC 0x01 /* Need to call sqlite3ExprDelete(pExpr) */
#define TERM_DYNAMIC 0x01 /* Need to call sqlite3ExprDelete(db, pExpr) */
#define TERM_VIRTUAL 0x02 /* Added by the optimizer. Do not code */
#define TERM_CODED 0x04 /* This term is already coded */
#define TERM_COPIED 0x08 /* Has a child */
@ -203,13 +203,14 @@ static void whereClauseInit(
static void whereClauseClear(WhereClause *pWC){
int i;
WhereTerm *a;
sqlite3 *db = pWC->pParse->db;
for(i=pWC->nTerm-1, a=pWC->a; i>=0; i--, a++){
if( a->flags & TERM_DYNAMIC ){
sqlite3ExprDelete(a->pExpr);
sqlite3ExprDelete(db, a->pExpr);
}
}
if( pWC->a!=pWC->aStatic ){
sqlite3_free(pWC->a);
sqlite3DbFree(db, pWC->a);
}
}
@ -230,18 +231,18 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, int flags){
int idx;
if( pWC->nTerm>=pWC->nSlot ){
WhereTerm *pOld = pWC->a;
pWC->a = sqlite3Malloc( sizeof(pWC->a[0])*pWC->nSlot*2 );
sqlite3 *db = pWC->pParse->db;
pWC->a = sqlite3DbMallocRaw(db, sizeof(pWC->a[0])*pWC->nSlot*2 );
if( pWC->a==0 ){
pWC->pParse->db->mallocFailed = 1;
if( flags & TERM_DYNAMIC ){
sqlite3ExprDelete(p);
sqlite3ExprDelete(db, p);
}
pWC->a = pOld;
return 0;
}
memcpy(pWC->a, pOld, sizeof(pWC->a[0])*pWC->nTerm);
if( pOld!=pWC->aStatic ){
sqlite3_free(pOld);
sqlite3DbFree(db, pOld);
}
pWC->nSlot *= 2;
}
@ -773,7 +774,7 @@ static void exprAnalyze(
int idxNew;
pDup = sqlite3ExprDup(db, pExpr);
if( db->mallocFailed ){
sqlite3ExprDelete(pDup);
sqlite3ExprDelete(db, pDup);
return;
}
idxNew = whereClauseInsert(pWC, pDup, TERM_VIRTUAL|TERM_DYNAMIC);
@ -889,7 +890,7 @@ static void exprAnalyze(
pWC->a[idxNew].iParent = idxTerm;
pTerm->nChild = 1;
}else{
sqlite3ExprListDelete(pList);
sqlite3ExprListDelete(db, pList);
}
}
or_not_possible:
@ -1258,6 +1259,7 @@ static double bestVirtualIndex(
sqlite3_index_info **ppIdxInfo /* Index information passed to xBestIndex */
){
Table *pTab = pSrc->pTab;
sqlite3_vtab *pVtab = pTab->pVtab;
sqlite3_index_info *pIdxInfo;
struct sqlite3_index_constraint *pIdxCons;
struct sqlite3_index_orderby *pIdxOrderBy;
@ -1369,7 +1371,7 @@ static double bestVirtualIndex(
** sqlite3ViewGetColumnNames() would have picked up the error.
*/
assert( pTab->azModuleArg && pTab->azModuleArg[0] );
assert( pTab->pVtab );
assert( pVtab );
#if 0
if( pTab->pVtab==0 ){
sqlite3ErrorMsg(pParse, "undefined module %s for table %s",
@ -1422,10 +1424,22 @@ static double bestVirtualIndex(
(void)sqlite3SafetyOff(pParse->db);
WHERETRACE(("xBestIndex for %s\n", pTab->zName));
TRACE_IDX_INPUTS(pIdxInfo);
rc = pTab->pVtab->pModule->xBestIndex(pTab->pVtab, pIdxInfo);
rc = pVtab->pModule->xBestIndex(pVtab, pIdxInfo);
TRACE_IDX_OUTPUTS(pIdxInfo);
(void)sqlite3SafetyOn(pParse->db);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_NOMEM ){
pParse->db->mallocFailed = 1;
}else if( !pVtab->zErrMsg ){
sqlite3ErrorMsg(pParse, "%s", sqlite3ErrStr(rc));
}else{
sqlite3ErrorMsg(pParse, "%s", pVtab->zErrMsg);
}
}
sqlite3DbFree(pParse->db, pVtab->zErrMsg);
pVtab->zErrMsg = 0;
for(i=0; i<pIdxInfo->nConstraint; i++){
if( !pIdxInfo->aConstraint[i].usable && pUsage[i].argvIndex>0 ){
sqlite3ErrorMsg(pParse,
@ -1434,15 +1448,7 @@ static double bestVirtualIndex(
}
}
if( rc!=SQLITE_OK ){
if( rc==SQLITE_NOMEM ){
pParse->db->mallocFailed = 1;
}else {
sqlite3ErrorMsg(pParse, "%s", sqlite3ErrStr(rc));
}
}
*(int*)&pIdxInfo->nOrderBy = nOrderBy;
return pIdxInfo->estimatedCost;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@ -1908,14 +1914,15 @@ static int nQPlan = 0; /* Next free slow in _query_plan[] */
static void whereInfoFree(WhereInfo *pWInfo){
if( pWInfo ){
int i;
sqlite3 *db = pWInfo->pParse->db;
for(i=0; i<pWInfo->nLevel; i++){
sqlite3_index_info *pInfo = pWInfo->a[i].pIdxInfo;
if( pInfo ){
assert( pInfo->needToFreeIdxStr==0 );
sqlite3_free(pInfo);
sqlite3DbFree(db, pInfo);
}
}
sqlite3_free(pWInfo);
sqlite3DbFree(db, pWInfo);
}
}
@ -2248,22 +2255,22 @@ WhereInfo *sqlite3WhereBegin(
struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom];
zMsg = sqlite3MPrintf(db, "TABLE %s", pItem->zName);
if( pItem->zAlias ){
zMsg = sqlite3MPrintf(db, "%z AS %s", zMsg, pItem->zAlias);
zMsg = sqlite3MAppendf(db, zMsg, "%s AS %s", zMsg, pItem->zAlias);
}
if( (pIx = pLevel->pIdx)!=0 ){
zMsg = sqlite3MPrintf(db, "%z WITH INDEX %s", zMsg, pIx->zName);
zMsg = sqlite3MAppendf(db, zMsg, "%s WITH INDEX %s", zMsg, pIx->zName);
}else if( pLevel->flags & (WHERE_ROWID_EQ|WHERE_ROWID_RANGE) ){
zMsg = sqlite3MPrintf(db, "%z USING PRIMARY KEY", zMsg);
zMsg = sqlite3MAppendf(db, zMsg, "%s USING PRIMARY KEY", zMsg);
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
else if( pLevel->pBestIdx ){
sqlite3_index_info *pBestIdx = pLevel->pBestIdx;
zMsg = sqlite3MPrintf(db, "%z VIRTUAL TABLE INDEX %d:%s", zMsg,
zMsg = sqlite3MAppendf(db, zMsg, "%s VIRTUAL TABLE INDEX %d:%s", zMsg,
pBestIdx->idxNum, pBestIdx->idxStr);
}
#endif
if( pLevel->flags & WHERE_ORDERBY ){
zMsg = sqlite3MPrintf(db, "%z ORDER BY", zMsg);
zMsg = sqlite3MAppendf(db, zMsg, "%s ORDER BY", zMsg);
}
sqlite3VdbeAddOp4(v, OP_Explain, i, pLevel->iFrom, 0, zMsg, P4_DYNAMIC);
}
@ -2779,14 +2786,16 @@ whereBeginNoMem:
** sqlite3WhereBegin() for additional information.
*/
void sqlite3WhereEnd(WhereInfo *pWInfo){
Vdbe *v = pWInfo->pParse->pVdbe;
Parse *pParse = pWInfo->pParse;
Vdbe *v = pParse->pVdbe;
int i;
WhereLevel *pLevel;
SrcList *pTabList = pWInfo->pTabList;
sqlite3 *db = pParse->db;
/* Generate loop termination code.
*/
sqlite3ExprClearColumnCache(pWInfo->pParse, -1);
sqlite3ExprClearColumnCache(pParse, -1);
for(i=pTabList->nSrc-1; i>=0; i--){
pLevel = &pWInfo->a[i];
sqlite3VdbeResolveLabel(v, pLevel->cont);
@ -2802,7 +2811,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
sqlite3VdbeAddOp2(v, OP_Next, pIn->iCur, pIn->topAddr);
sqlite3VdbeJumpHere(v, pIn->topAddr-1);
}
sqlite3_free(pLevel->aInLoop);
sqlite3DbFree(db, pLevel->aInLoop);
}
sqlite3VdbeResolveLabel(v, pLevel->brk);
if( pLevel->iLeftJoin ){

View File

@ -12,7 +12,7 @@
# focus of this script is testing the ALTER TABLE statement and
# specifically out-of-memory conditions within that command.
#
# $Id: altermalloc.test,v 1.7 2007/10/03 08:46:45 danielk1977 Exp $
# $Id: altermalloc.test,v 1.9 2008/08/04 20:13:27 drh Exp $
#
set testdir [file dirname $argv0]
@ -32,6 +32,7 @@ do_malloc_test altermalloc-1 -tclprep {
if {[catch {sqlite3 db test.db}]} {
error "out of memory"
}
sqlite3_db_config_lookaside db 0 0 0
sqlite3_extended_result_codes db 1
} -sqlbody {
CREATE TABLE t1(a int);
@ -45,6 +46,7 @@ do_malloc_test altermalloc-1 -tclprep {
ifcapable vtab {
do_malloc_test altermalloc-vtab -tclprep {
sqlite3 db2 test.db
sqlite3_db_config_lookaside db2 0 0 0
sqlite3_extended_result_codes db2 1
register_echo_module [sqlite3_connection_pointer db2]
db2 eval {

View File

@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library.
# This file implements tests for the ANALYZE command.
#
# $Id: analyze.test,v 1.7 2008/04/11 17:11:27 danielk1977 Exp $
# $Id: analyze.test,v 1.8 2008/08/01 18:47:02 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@ -266,6 +266,16 @@ do_test analyze-4.2 {
SELECT * FROM t4 WHERE x=1234;
}
} {}
do_test analyze-4.3 {
execsql {
INSERT INTO sqlite_stat1 VALUES('t4','xyzzy','0 1 2 3');
}
db close
sqlite3 db test.db
execsql {
SELECT * FROM t4 WHERE x=1234;
}
} {}
# This test corrupts the database file so it must be the last test
# in the series.

View File

@ -12,7 +12,7 @@
# focus of this script is testing the ATTACH statement and
# specifically out-of-memory conditions within that command.
#
# $Id: attachmalloc.test,v 1.7 2007/10/09 08:29:32 danielk1977 Exp $
# $Id: attachmalloc.test,v 1.9 2008/08/04 20:13:27 drh Exp $
#
set testdir [file dirname $argv0]
@ -35,6 +35,7 @@ do_malloc_test attachmalloc-1 -tclprep {
if {[catch {sqlite3 db test.db}]} {
error "out of memory"
}
sqlite3_db_config_lookaside db 0 0 0
sqlite3_extended_result_codes db 1
} -sqlbody {
ATTACH 'test2.db' AS two;

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.26 2007/04/07 15:03:17 danielk1977 Exp $
# $Id: autovacuum.test,v 1.27 2008/08/02 03:50:39 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@ -643,4 +643,23 @@ do_test autovacuum-7.3 {
expr {[file size test.db] / 1024}
} {286}
#------------------------------------------------------------------------
# Additional tests.
#
# Try to determine the autovacuum setting for a database that is locked.
#
do_test autovacuum-8.1 {
db close
sqlite3 db test.db
sqlite3 db2 test.db
db eval {PRAGMA auto_vacuum}
} {1}
do_test autovacuum-8.2 {
db eval {BEGIN EXCLUSIVE}
catchsql {PRAGMA auto_vacuum} db2
} {1 {database is locked}}
catch {db2 close}
catch {db eval {COMMIT}}
finish_test

View File

@ -13,7 +13,7 @@
# The focus of this file is testing how SQLite generates the names
# of columns in a result set.
#
# $Id: colname.test,v 1.1 2008/07/15 20:56:17 drh Exp $
# $Id: colname.test,v 1.4 2008/08/02 20:09:37 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@ -175,7 +175,6 @@ do_test colname-3.11 {
# Test for short=OFF and full=ON
#
do_test colname-4.1 {
breakpoint
db eval {
PRAGMA short_column_names=OFF;
PRAGMA full_column_names=ON;
@ -239,7 +238,6 @@ do_test colname-4.11 {
}
} {v4.a 1 v4.x 4 v4.a:1 11 v4.x:1 14 v4.a:2 1 v4.b 2 v4.c 3 v4.x:2 4 v4.y 5 v4.z 6 v4.a:3 11 v4.b:1 12 v4.c:1 13 v4.x:3 14 v4.y:1 15 v4.z:1 16}
do_test colname-4.12 {
breakpoint
execsql2 {
SELECT * FROM v5 ORDER BY 2;
}
@ -250,5 +248,11 @@ do_test colname-4.13 {
}
} {v6.a 1 v6.x 4 v6.a:1 11 v6.x:1 14 v6.a:2 1 v6.b 2 v6.c 3 v6.x:2 4 v6.y 5 v6.z 6 v6.a:3 11 v6.b:1 12 v6.c:1 13 v6.x:3 14 v6.y:1 15 v6.z:1 16}
# ticket #3229
do_test colname-5.1 {
lreplace [db eval {
SELECT x.* FROM sqlite_master X LIMIT 1;
}] 3 3 x
} {table tabc tabc x {CREATE TABLE tabc(a,b,c)}}
finish_test

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.13 2008/07/08 17:13:59 danielk1977 Exp $
# $Id: corrupt2.test,v 1.14 2008/08/02 20:09:37 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@ -23,6 +23,8 @@ source $testdir/tester.tcl
#
do_test corrupt2-1.1 {
execsql {
PRAGMA auto_vacuum=0;
PRAGMA page_size=1024;
CREATE TABLE abc(a, b, c);
}
} {}
@ -183,6 +185,7 @@ do_test corrupt2-5.1 {
sqlite3 db2 corrupt.db
execsql {
PRAGMA auto_vacuum = 0;
PRAGMA page_size = 1024;
CREATE TABLE t1(a, b, c);
CREATE TABLE t2(a, b, c);
@ -338,6 +341,7 @@ ifcapable autovacuum {
set sqlprep {
PRAGMA auto_vacuum = 0;
PRAGMA page_size = 1024;
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
CREATE INDEX i1 ON t1(b);

View File

@ -14,7 +14,7 @@
# segfault if it sees a corrupt database file. It specifically focuses
# on corrupt cell offsets in a btree page.
#
# $Id: corrupt7.test,v 1.2 2008/06/11 18:56:42 drh Exp $
# $Id: corrupt7.test,v 1.4 2008/07/26 18:26:10 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@ -63,13 +63,40 @@ do_test corrupt7-2.1 {
sqlite3 db test.db
db eval {PRAGMA integrity_check(1)}
} {{*** in database main ***
Page 2: sqlite3BtreeInitPage() returns error code 11}}
Corruption detected in cell 15 on page 2}}
do_test corrupt7-2.2 {
db close
hexio_write test.db 1062 04
sqlite3 db test.db
db eval {PRAGMA integrity_check(1)}
} {{*** in database main ***
Page 2: sqlite3BtreeInitPage() returns error code 11}}
Corruption detected in cell 15 on page 2}}
do_test corrupt7-3.1 {
execsql {
DROP TABLE t1;
CREATE TABLE t1(a, b);
INSERT INTO t1 VALUES(1, 'one');
INSERT INTO t1 VALUES(100, 'one hundred');
INSERT INTO t1 VALUES(100000, 'one hundred thousand');
CREATE INDEX i1 ON t1(b);
}
db close
# Locate the 3rd cell in the index.
set cell_offset [hexio_get_int [hexio_read test.db [expr 1024*2 + 12] 2]]
incr cell_offset [expr 1024*2]
incr cell_offset 1
# This write corrupts the "header-size" field of the database record
# stored in the index cell. At one point this was causing sqlite to
# reference invalid memory.
hexio_write test.db $cell_offset FFFF7F
sqlite3 db test.db
catchsql {
SELECT b FROM t1 WHERE b > 'o' AND b < 'p';
}
} {1 {database disk image is malformed}}
finish_test

View File

@ -13,7 +13,7 @@
# factoring constant expressions out of loops and for
# common subexpression eliminations.
#
# $Id: cse.test,v 1.5 2008/04/01 18:04:11 drh Exp $
# $Id: cse.test,v 1.6 2008/08/04 03:51:24 danielk1977 Exp $
#
set testdir [file dirname $argv0]
@ -94,20 +94,22 @@ do_test cse-1.10 {
SELECT CAST(b AS integer), typeof(b), CAST(b AS text), typeof(b) FROM t1
}
} {11 integer 11 integer 21 integer 21 integer}
do_test cse-1.11 {
execsql {
SELECT *,* FROM t1 WHERE a=2
UNION ALL
SELECT *,* FROM t1 WHERE a=1
}
} {2 21 22 23 24 25 2 21 22 23 24 25 1 11 12 13 14 15 1 11 12 13 14 15}
do_test cse-1.12 {
execsql {
SELECT coalesce(b,c,d,e), a, b, c, d, e FROM t1 WHERE a=2
UNION ALL
SELECT coalesce(e,d,c,b), e, d, c, b, a FROM t1 WHERE a=1
}
} {21 2 21 22 23 24 14 14 13 12 11 1}
ifcapable compound {
do_test cse-1.11 {
execsql {
SELECT *,* FROM t1 WHERE a=2
UNION ALL
SELECT *,* FROM t1 WHERE a=1
}
} {2 21 22 23 24 25 2 21 22 23 24 25 1 11 12 13 14 15 1 11 12 13 14 15}
do_test cse-1.12 {
execsql {
SELECT coalesce(b,c,d,e), a, b, c, d, e FROM t1 WHERE a=2
UNION ALL
SELECT coalesce(e,d,c,b), e, d, c, b, a FROM t1 WHERE a=1
}
} {21 2 21 22 23 24 14 14 13 12 11 1}
}
do_test cse-1.13 {
execsql {
SELECT upper(b), typeof(b), b FROM t1

View File

@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The
# focus of this file is testing expressions.
#
# $Id: expr.test,v 1.63 2008/07/15 00:27:35 drh Exp $
# $Id: expr.test,v 1.64 2008/07/30 13:27:11 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@ -703,4 +703,45 @@ do_test expr-13.1 {
}
} {1.23456789012346e+19}
# Implicit String->Integer conversion is used when possible.
#
do_test expr-13.2 {
execsql {
SELECT 0+'9223372036854775807'
}
} {9223372036854775807}
do_test expr-13.3 {
execsql {
SELECT '9223372036854775807'+0
}
} {9223372036854775807}
# If the value is too large, use String->Float conversion.
#
do_test expr-13.4 {
execsql {
SELECT 0+'9223372036854775808'
}
} {9.22337203685478e+18}
do_test expr-13.5 {
execsql {
SELECT '9223372036854775808'+0
}
} {9.22337203685478e+18}
# Use String->float conversion if the value is explicitly a floating
# point value.
#
do_test expr-13.6 {
execsql {
SELECT 0+'9223372036854775807.0'
}
} {9.22337203685478e+18}
do_test expr-13.7 {
execsql {
SELECT '9223372036854775807.0'+0
}
} {9.22337203685478e+18}
finish_test

68
test/fts2.test Normal file
View File

@ -0,0 +1,68 @@
# 2008 July 22
#
# 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 runs all tests.
#
# $Id: fts2.test,v 1.2 2008/07/23 18:17:32 drh Exp $
proc lshift {lvar} {
upvar $lvar l
set ret [lindex $l 0]
set l [lrange $l 1 end]
return $ret
}
while {[set arg [lshift argv]] != ""} {
switch -- $arg {
-sharedpagercache {
sqlite3_enable_shared_cache 1
}
-soak {
set SOAKTEST 1
}
default {
set argv [linsert $argv 0 $arg]
break
}
}
}
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# If SQLITE_ENABLE_FTS2 is defined, omit this file.
ifcapable !fts2 {
return
}
rename finish_test really_finish_test
proc finish_test {} {}
set ISQUICK 1
set EXCLUDE {
fts2.test
}
# Files to include in the test. If this list is empty then everything
# that is not in the EXCLUDE list is run.
#
set INCLUDE {
}
foreach testfile [lsort -dictionary [glob $testdir/fts2*.test]] {
set tail [file tail $testfile]
if {[lsearch -exact $EXCLUDE $tail]>=0} continue
if {[llength $INCLUDE]>0 && [lsearch -exact $INCLUDE $tail]<0} continue
source $testfile
catch {db close}
if {$sqlite_open_file_count>0} {
puts "$tail did not close all files: $sqlite_open_file_count"
incr nErr
lappend ::failList $tail
set sqlite_open_file_count 0
}
}
set sqlite_open_file_count 0
really_finish_test

357
test/fts2p.test Normal file
View File

@ -0,0 +1,357 @@
# 2008 June 26
#
# 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 exercises some new testing functions in the FTS2 module,
# and then uses them to do some basic tests that FTS2 is internally
# working as expected.
#
# $Id: fts2p.test,v 1.1 2008/07/22 23:32:28 shess Exp $
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# If SQLITE_ENABLE_FTS2 is not defined, omit this file.
ifcapable !fts2 {
finish_test
return
}
#*************************************************************************
# Probe to see if support for these functions is compiled in.
# TODO(shess): Change main.mk to do the right thing and remove this test.
db eval {
DROP TABLE IF EXISTS t1;
CREATE VIRTUAL TABLE t1 USING fts2(c);
INSERT INTO t1 (rowid, c) VALUES (1, 'x');
}
set s {SELECT dump_terms(t1, 1) FROM t1 LIMIT 1}
set r {1 {unable to use function dump_terms in the requested context}}
if {[catchsql $s]==$r} {
finish_test
return
}
#*************************************************************************
# Test that the new functions give appropriate errors.
do_test fts2p-0.0 {
catchsql {
SELECT dump_terms(t1, 1) FROM t1 LIMIT 1;
}
} {1 {dump_terms: incorrect arguments}}
do_test fts2p-0.1 {
catchsql {
SELECT dump_terms(t1, 0, 0, 0) FROM t1 LIMIT 1;
}
} {1 {dump_terms: incorrect arguments}}
do_test fts2p-0.2 {
catchsql {
SELECT dump_terms(1, t1) FROM t1 LIMIT 1;
}
} {1 {unable to use function dump_terms in the requested context}}
do_test fts2p-0.3 {
catchsql {
SELECT dump_terms(t1, 16, 16) FROM t1 LIMIT 1;
}
} {1 {dump_terms: segment not found}}
do_test fts2p-0.4 {
catchsql {
SELECT dump_doclist(t1) FROM t1 LIMIT 1;
}
} {1 {dump_doclist: incorrect arguments}}
do_test fts2p-0.5 {
catchsql {
SELECT dump_doclist(t1, NULL) FROM t1 LIMIT 1;
}
} {1 {dump_doclist: empty second argument}}
do_test fts2p-0.6 {
catchsql {
SELECT dump_doclist(t1, '') FROM t1 LIMIT 1;
}
} {1 {dump_doclist: empty second argument}}
do_test fts2p-0.7 {
catchsql {
SELECT dump_doclist(t1, 'a', 0) FROM t1 LIMIT 1;
}
} {1 {dump_doclist: incorrect arguments}}
do_test fts2p-0.8 {
catchsql {
SELECT dump_doclist(t1, 'a', 0, 0, 0) FROM t1 LIMIT 1;
}
} {1 {dump_doclist: incorrect arguments}}
do_test fts2p-0.9 {
catchsql {
SELECT dump_doclist(t1, 'a', 16, 16) FROM t1 LIMIT 1;
}
} {1 {dump_doclist: segment not found}}
#*************************************************************************
# Utility function to check for the expected terms in the segment
# level/index. _all version does same but for entire index.
proc check_terms {test level index terms} {
# TODO(shess): Figure out why uplevel in do_test can't catch
# $level and $index directly.
set ::level $level
set ::index $index
do_test $test.terms {
execsql {
SELECT dump_terms(t1, $::level, $::index) FROM t1 LIMIT 1;
}
} [list $terms]
}
proc check_terms_all {test terms} {
do_test $test.terms {
execsql {
SELECT dump_terms(t1) FROM t1 LIMIT 1;
}
} [list $terms]
}
# Utility function to check for the expected doclist for the term in
# segment level/index. _all version does same for entire index.
proc check_doclist {test level index term doclist} {
# TODO(shess): Again, why can't the non-:: versions work?
set ::term $term
set ::level $level
set ::index $index
do_test $test {
execsql {
SELECT dump_doclist(t1, $::term, $::level, $::index) FROM t1 LIMIT 1;
}
} [list $doclist]
}
proc check_doclist_all {test term doclist} {
set ::term $term
do_test $test {
execsql {
SELECT dump_doclist(t1, $::term) FROM t1 LIMIT 1;
}
} [list $doclist]
}
#*************************************************************************
# Test the segments resulting from straight-forward inserts.
db eval {
DROP TABLE IF EXISTS t1;
CREATE VIRTUAL TABLE t1 USING fts2(c);
INSERT INTO t1 (rowid, c) VALUES (1, 'This is a test');
INSERT INTO t1 (rowid, c) VALUES (2, 'That was a test');
INSERT INTO t1 (rowid, c) VALUES (3, 'This is a test');
}
# Check for expected segments and expected matches.
do_test fts2p-1.0.segments {
execsql {
SELECT level, idx FROM t1_segdir ORDER BY level, idx;
}
} {0 0 0 1 0 2}
do_test fts2p-1.0.matches {
execsql {
SELECT OFFSETS(t1) FROM t1
WHERE t1 MATCH 'this OR that OR was OR a OR is OR test' ORDER BY rowid;
}
} [list {0 0 0 4 0 4 5 2 0 3 8 1 0 5 10 4} \
{0 1 0 4 0 2 5 3 0 3 9 1 0 5 11 4} \
{0 0 0 4 0 4 5 2 0 3 8 1 0 5 10 4}]
# Check the specifics of the segments constructed.
# Logical view of entire index.
check_terms_all fts2p-1.0.1 {a is test that this was}
check_doclist_all fts2p-1.0.1.1 a {[1 0[2]] [2 0[2]] [3 0[2]]}
check_doclist_all fts2p-1.0.1.2 is {[1 0[1]] [3 0[1]]}
check_doclist_all fts2p-1.0.1.3 test {[1 0[3]] [2 0[3]] [3 0[3]]}
check_doclist_all fts2p-1.0.1.4 that {[2 0[0]]}
check_doclist_all fts2p-1.0.1.5 this {[1 0[0]] [3 0[0]]}
check_doclist_all fts2p-1.0.1.6 was {[2 0[1]]}
# Segment 0,0
check_terms fts2p-1.0.2 0 0 {a is test this}
check_doclist fts2p-1.0.2.1 0 0 a {[1 0[2]]}
check_doclist fts2p-1.0.2.2 0 0 is {[1 0[1]]}
check_doclist fts2p-1.0.2.3 0 0 test {[1 0[3]]}
check_doclist fts2p-1.0.2.4 0 0 this {[1 0[0]]}
# Segment 0,1
check_terms fts2p-1.0.3 0 1 {a test that was}
check_doclist fts2p-1.0.3.1 0 1 a {[2 0[2]]}
check_doclist fts2p-1.0.3.2 0 1 test {[2 0[3]]}
check_doclist fts2p-1.0.3.3 0 1 that {[2 0[0]]}
check_doclist fts2p-1.0.3.4 0 1 was {[2 0[1]]}
# Segment 0,2
check_terms fts2p-1.0.4 0 2 {a is test this}
check_doclist fts2p-1.0.4.1 0 2 a {[3 0[2]]}
check_doclist fts2p-1.0.4.2 0 2 is {[3 0[1]]}
check_doclist fts2p-1.0.4.3 0 2 test {[3 0[3]]}
check_doclist fts2p-1.0.4.4 0 2 this {[3 0[0]]}
#*************************************************************************
# Test the segments resulting from inserts followed by a delete.
db eval {
DROP TABLE IF EXISTS t1;
CREATE VIRTUAL TABLE t1 USING fts2(c);
INSERT INTO t1 (rowid, c) VALUES (1, 'This is a test');
INSERT INTO t1 (rowid, c) VALUES (2, 'That was a test');
INSERT INTO t1 (rowid, c) VALUES (3, 'This is a test');
DELETE FROM t1 WHERE rowid = 1;
}
do_test fts2p-1.1.segments {
execsql {
SELECT level, idx FROM t1_segdir ORDER BY level, idx;
}
} {0 0 0 1 0 2 0 3}
do_test fts2p-1.1.matches {
execsql {
SELECT OFFSETS(t1) FROM t1
WHERE t1 MATCH 'this OR that OR was OR a OR is OR test' ORDER BY rowid;
}
} {{0 1 0 4 0 2 5 3 0 3 9 1 0 5 11 4} {0 0 0 4 0 4 5 2 0 3 8 1 0 5 10 4}}
check_terms_all fts2p-1.1.1 {a is test that this was}
check_doclist_all fts2p-1.1.1.1 a {[2 0[2]] [3 0[2]]}
check_doclist_all fts2p-1.1.1.2 is {[3 0[1]]}
check_doclist_all fts2p-1.1.1.3 test {[2 0[3]] [3 0[3]]}
check_doclist_all fts2p-1.1.1.4 that {[2 0[0]]}
check_doclist_all fts2p-1.1.1.5 this {[3 0[0]]}
check_doclist_all fts2p-1.1.1.6 was {[2 0[1]]}
check_terms fts2p-1.1.2 0 0 {a is test this}
check_doclist fts2p-1.1.2.1 0 0 a {[1 0[2]]}
check_doclist fts2p-1.1.2.2 0 0 is {[1 0[1]]}
check_doclist fts2p-1.1.2.3 0 0 test {[1 0[3]]}
check_doclist fts2p-1.1.2.4 0 0 this {[1 0[0]]}
check_terms fts2p-1.1.3 0 1 {a test that was}
check_doclist fts2p-1.1.3.1 0 1 a {[2 0[2]]}
check_doclist fts2p-1.1.3.2 0 1 test {[2 0[3]]}
check_doclist fts2p-1.1.3.3 0 1 that {[2 0[0]]}
check_doclist fts2p-1.1.3.4 0 1 was {[2 0[1]]}
check_terms fts2p-1.1.4 0 2 {a is test this}
check_doclist fts2p-1.1.4.1 0 2 a {[3 0[2]]}
check_doclist fts2p-1.1.4.2 0 2 is {[3 0[1]]}
check_doclist fts2p-1.1.4.3 0 2 test {[3 0[3]]}
check_doclist fts2p-1.1.4.4 0 2 this {[3 0[0]]}
check_terms fts2p-1.1.5 0 3 {a is test this}
check_doclist fts2p-1.1.5.1 0 3 a {[1]}
check_doclist fts2p-1.1.5.2 0 3 is {[1]}
check_doclist fts2p-1.1.5.3 0 3 test {[1]}
check_doclist fts2p-1.1.5.4 0 3 this {[1]}
#*************************************************************************
# Test results when all references to certain tokens are deleted.
db eval {
DROP TABLE IF EXISTS t1;
CREATE VIRTUAL TABLE t1 USING fts2(c);
INSERT INTO t1 (rowid, c) VALUES (1, 'This is a test');
INSERT INTO t1 (rowid, c) VALUES (2, 'That was a test');
INSERT INTO t1 (rowid, c) VALUES (3, 'This is a test');
DELETE FROM t1 WHERE rowid IN (1,3);
}
# Still 4 segments because 0,3 will contain deletes for rowid 1 and 3.
do_test fts2p-1.2.segments {
execsql {
SELECT level, idx FROM t1_segdir ORDER BY level, idx;
}
} {0 0 0 1 0 2 0 3}
do_test fts2p-1.2.matches {
execsql {
SELECT OFFSETS(t1) FROM t1
WHERE t1 MATCH 'this OR that OR was OR a OR is OR test' ORDER BY rowid;
}
} {{0 1 0 4 0 2 5 3 0 3 9 1 0 5 11 4}}
check_terms_all fts2p-1.2.1 {a is test that this was}
check_doclist_all fts2p-1.2.1.1 a {[2 0[2]]}
check_doclist_all fts2p-1.2.1.2 is {}
check_doclist_all fts2p-1.2.1.3 test {[2 0[3]]}
check_doclist_all fts2p-1.2.1.4 that {[2 0[0]]}
check_doclist_all fts2p-1.2.1.5 this {}
check_doclist_all fts2p-1.2.1.6 was {[2 0[1]]}
check_terms fts2p-1.2.2 0 0 {a is test this}
check_doclist fts2p-1.2.2.1 0 0 a {[1 0[2]]}
check_doclist fts2p-1.2.2.2 0 0 is {[1 0[1]]}
check_doclist fts2p-1.2.2.3 0 0 test {[1 0[3]]}
check_doclist fts2p-1.2.2.4 0 0 this {[1 0[0]]}
check_terms fts2p-1.2.3 0 1 {a test that was}
check_doclist fts2p-1.2.3.1 0 1 a {[2 0[2]]}
check_doclist fts2p-1.2.3.2 0 1 test {[2 0[3]]}
check_doclist fts2p-1.2.3.3 0 1 that {[2 0[0]]}
check_doclist fts2p-1.2.3.4 0 1 was {[2 0[1]]}
check_terms fts2p-1.2.4 0 2 {a is test this}
check_doclist fts2p-1.2.4.1 0 2 a {[3 0[2]]}
check_doclist fts2p-1.2.4.2 0 2 is {[3 0[1]]}
check_doclist fts2p-1.2.4.3 0 2 test {[3 0[3]]}
check_doclist fts2p-1.2.4.4 0 2 this {[3 0[0]]}
check_terms fts2p-1.2.5 0 3 {a is test this}
check_doclist fts2p-1.2.5.1 0 3 a {[1] [3]}
check_doclist fts2p-1.2.5.2 0 3 is {[1] [3]}
check_doclist fts2p-1.2.5.3 0 3 test {[1] [3]}
check_doclist fts2p-1.2.5.4 0 3 this {[1] [3]}
#*************************************************************************
# Test results when everything is optimized manually.
db eval {
DROP TABLE IF EXISTS t1;
CREATE VIRTUAL TABLE t1 USING fts2(c);
INSERT INTO t1 (rowid, c) VALUES (1, 'This is a test');
INSERT INTO t1 (rowid, c) VALUES (2, 'That was a test');
INSERT INTO t1 (rowid, c) VALUES (3, 'This is a test');
DELETE FROM t1 WHERE rowid IN (1,3);
DROP TABLE IF EXISTS t1old;
ALTER TABLE t1 RENAME TO t1old;
CREATE VIRTUAL TABLE t1 USING fts2(c);
INSERT INTO t1 (rowid, c) SELECT rowid, c FROM t1old;
DROP TABLE t1old;
}
# Should be a single optimal segment with the same logical results.
do_test fts2p-1.3.segments {
execsql {
SELECT level, idx FROM t1_segdir ORDER BY level, idx;
}
} {0 0}
do_test fts2p-1.3.matches {
execsql {
SELECT OFFSETS(t1) FROM t1
WHERE t1 MATCH 'this OR that OR was OR a OR is OR test' ORDER BY rowid;
}
} {{0 1 0 4 0 2 5 3 0 3 9 1 0 5 11 4}}
check_terms_all fts2p-1.3.1 {a test that was}
check_doclist_all fts2p-1.3.1.1 a {[2 0[2]]}
check_doclist_all fts2p-1.3.1.2 test {[2 0[3]]}
check_doclist_all fts2p-1.3.1.3 that {[2 0[0]]}
check_doclist_all fts2p-1.3.1.4 was {[2 0[1]]}
check_terms fts2p-1.3.2 0 0 {a test that was}
check_doclist fts2p-1.3.2.1 0 0 a {[2 0[2]]}
check_doclist fts2p-1.3.2.2 0 0 test {[2 0[3]]}
check_doclist fts2p-1.3.2.3 0 0 that {[2 0[0]]}
check_doclist fts2p-1.3.2.4 0 0 was {[2 0[1]]}
finish_test

346
test/fts2q.test Normal file
View File

@ -0,0 +1,346 @@
# 2008 June 26
#
# 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 implements regression tests for SQLite library. The focus
# of this script is testing the FTS2 module's optimize() function.
#
# $Id: fts2q.test,v 1.2 2008/07/22 23:49:44 shess Exp $
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# If SQLITE_ENABLE_FTS2 is not defined, omit this file.
ifcapable !fts2 {
finish_test
return
}
#*************************************************************************
# Probe to see if support for the FTS2 dump_* functions is compiled in.
# TODO(shess): Change main.mk to do the right thing and remove this test.
db eval {
DROP TABLE IF EXISTS t1;
CREATE VIRTUAL TABLE t1 USING fts2(c);
INSERT INTO t1 (rowid, c) VALUES (1, 'x');
}
set s {SELECT dump_terms(t1, 1) FROM t1 LIMIT 1}
set r {1 {unable to use function dump_terms in the requested context}}
if {[catchsql $s]==$r} {
finish_test
return
}
#*************************************************************************
# Utility function to check for the expected terms in the segment
# level/index. _all version does same but for entire index.
proc check_terms {test level index terms} {
# TODO(shess): Figure out why uplevel in do_test can't catch
# $level and $index directly.
set ::level $level
set ::index $index
do_test $test.terms {
execsql {
SELECT dump_terms(t1, $::level, $::index) FROM t1 LIMIT 1;
}
} [list $terms]
}
proc check_terms_all {test terms} {
do_test $test.terms {
execsql {
SELECT dump_terms(t1) FROM t1 LIMIT 1;
}
} [list $terms]
}
# Utility function to check for the expected doclist for the term in
# segment level/index. _all version does same for entire index.
proc check_doclist {test level index term doclist} {
# TODO(shess): Again, why can't the non-:: versions work?
set ::term $term
set ::level $level
set ::index $index
do_test $test {
execsql {
SELECT dump_doclist(t1, $::term, $::level, $::index) FROM t1 LIMIT 1;
}
} [list $doclist]
}
proc check_doclist_all {test term doclist} {
set ::term $term
do_test $test {
execsql {
SELECT dump_doclist(t1, $::term) FROM t1 LIMIT 1;
}
} [list $doclist]
}
#*************************************************************************
# Test results when all rows are deleted and one is added back.
# Previously older segments would continue to exist, but now the index
# should be dropped when the table is empty. The results should look
# exactly like we never added the earlier rows in the first place.
db eval {
DROP TABLE IF EXISTS t1;
CREATE VIRTUAL TABLE t1 USING fts2(c);
INSERT INTO t1 (rowid, c) VALUES (1, 'This is a test');
INSERT INTO t1 (rowid, c) VALUES (2, 'That was a test');
INSERT INTO t1 (rowid, c) VALUES (3, 'This is a test');
DELETE FROM t1 WHERE 1=1; -- Delete each row rather than dropping table.
INSERT INTO t1 (rowid, c) VALUES (1, 'This is a test');
}
# Should be a single initial segment.
do_test fts2q-1.segments {
execsql {
SELECT level, idx FROM t1_segdir ORDER BY level, idx;
}
} {0 0}
do_test fts2q-1.matches {
execsql {
SELECT OFFSETS(t1) FROM t1
WHERE t1 MATCH 'this OR that OR was OR a OR is OR test' ORDER BY rowid;
}
} {{0 0 0 4 0 4 5 2 0 3 8 1 0 5 10 4}}
check_terms_all fts2q-1.1 {a is test this}
check_doclist_all fts2q-1.1.1 a {[1 0[2]]}
check_doclist_all fts2q-1.1.2 is {[1 0[1]]}
check_doclist_all fts2q-1.1.3 test {[1 0[3]]}
check_doclist_all fts2q-1.1.4 this {[1 0[0]]}
check_terms fts2q-1.2 0 0 {a is test this}
check_doclist fts2q-1.2.1 0 0 a {[1 0[2]]}
check_doclist fts2q-1.2.2 0 0 is {[1 0[1]]}
check_doclist fts2q-1.2.3 0 0 test {[1 0[3]]}
check_doclist fts2q-1.2.4 0 0 this {[1 0[0]]}
#*************************************************************************
# Test results when everything is optimized manually.
# NOTE(shess): This is a copy of fts2c-1.3. I've pulled a copy here
# because fts2q-2 and fts2q-3 should have identical results.
db eval {
DROP TABLE IF EXISTS t1;
CREATE VIRTUAL TABLE t1 USING fts2(c);
INSERT INTO t1 (rowid, c) VALUES (1, 'This is a test');
INSERT INTO t1 (rowid, c) VALUES (2, 'That was a test');
INSERT INTO t1 (rowid, c) VALUES (3, 'This is a test');
DELETE FROM t1 WHERE rowid IN (1,3);
DROP TABLE IF EXISTS t1old;
ALTER TABLE t1 RENAME TO t1old;
CREATE VIRTUAL TABLE t1 USING fts2(c);
INSERT INTO t1 (rowid, c) SELECT rowid, c FROM t1old;
DROP TABLE t1old;
}
# Should be a single optimal segment with the same logical results.
do_test fts2q-2.segments {
execsql {
SELECT level, idx FROM t1_segdir ORDER BY level, idx;
}
} {0 0}
do_test fts2q-2.matches {
execsql {
SELECT OFFSETS(t1) FROM t1
WHERE t1 MATCH 'this OR that OR was OR a OR is OR test' ORDER BY rowid;
}
} {{0 1 0 4 0 2 5 3 0 3 9 1 0 5 11 4}}
check_terms_all fts2q-2.1 {a test that was}
check_doclist_all fts2q-2.1.1 a {[2 0[2]]}
check_doclist_all fts2q-2.1.2 test {[2 0[3]]}
check_doclist_all fts2q-2.1.3 that {[2 0[0]]}
check_doclist_all fts2q-2.1.4 was {[2 0[1]]}
check_terms fts2q-2.2 0 0 {a test that was}
check_doclist fts2q-2.2.1 0 0 a {[2 0[2]]}
check_doclist fts2q-2.2.2 0 0 test {[2 0[3]]}
check_doclist fts2q-2.2.3 0 0 that {[2 0[0]]}
check_doclist fts2q-2.2.4 0 0 was {[2 0[1]]}
#*************************************************************************
# Test results when everything is optimized via optimize().
db eval {
DROP TABLE IF EXISTS t1;
CREATE VIRTUAL TABLE t1 USING fts2(c);
INSERT INTO t1 (rowid, c) VALUES (1, 'This is a test');
INSERT INTO t1 (rowid, c) VALUES (2, 'That was a test');
INSERT INTO t1 (rowid, c) VALUES (3, 'This is a test');
DELETE FROM t1 WHERE rowid IN (1,3);
SELECT OPTIMIZE(t1) FROM t1 LIMIT 1;
}
# Should be a single optimal segment with the same logical results.
do_test fts2q-3.segments {
execsql {
SELECT level, idx FROM t1_segdir ORDER BY level, idx;
}
} {0 0}
do_test fts2q-3.matches {
execsql {
SELECT OFFSETS(t1) FROM t1
WHERE t1 MATCH 'this OR that OR was OR a OR is OR test' ORDER BY rowid;
}
} {{0 1 0 4 0 2 5 3 0 3 9 1 0 5 11 4}}
check_terms_all fts2q-3.1 {a test that was}
check_doclist_all fts2q-3.1.1 a {[2 0[2]]}
check_doclist_all fts2q-3.1.2 test {[2 0[3]]}
check_doclist_all fts2q-3.1.3 that {[2 0[0]]}
check_doclist_all fts2q-3.1.4 was {[2 0[1]]}
check_terms fts2q-3.2 0 0 {a test that was}
check_doclist fts2q-3.2.1 0 0 a {[2 0[2]]}
check_doclist fts2q-3.2.2 0 0 test {[2 0[3]]}
check_doclist fts2q-3.2.3 0 0 that {[2 0[0]]}
check_doclist fts2q-3.2.4 0 0 was {[2 0[1]]}
#*************************************************************************
# Test optimize() against a table involving segment merges.
# NOTE(shess): Since there's no transaction, each of the INSERT/UPDATE
# statements generates a segment.
db eval {
DROP TABLE IF EXISTS t1;
CREATE VIRTUAL TABLE t1 USING fts2(c);
INSERT INTO t1 (rowid, c) VALUES (1, 'This is a test');
INSERT INTO t1 (rowid, c) VALUES (2, 'That was a test');
INSERT INTO t1 (rowid, c) VALUES (3, 'This is a test');
UPDATE t1 SET c = 'This is a test one' WHERE rowid = 1;
UPDATE t1 SET c = 'That was a test one' WHERE rowid = 2;
UPDATE t1 SET c = 'This is a test one' WHERE rowid = 3;
UPDATE t1 SET c = 'This is a test two' WHERE rowid = 1;
UPDATE t1 SET c = 'That was a test two' WHERE rowid = 2;
UPDATE t1 SET c = 'This is a test two' WHERE rowid = 3;
UPDATE t1 SET c = 'This is a test three' WHERE rowid = 1;
UPDATE t1 SET c = 'That was a test three' WHERE rowid = 2;
UPDATE t1 SET c = 'This is a test three' WHERE rowid = 3;
UPDATE t1 SET c = 'This is a test four' WHERE rowid = 1;
UPDATE t1 SET c = 'That was a test four' WHERE rowid = 2;
UPDATE t1 SET c = 'This is a test four' WHERE rowid = 3;
UPDATE t1 SET c = 'This is a test' WHERE rowid = 1;
UPDATE t1 SET c = 'That was a test' WHERE rowid = 2;
UPDATE t1 SET c = 'This is a test' WHERE rowid = 3;
}
# 2 segments in level 0, 1 in level 1 (18 segments created, 16
# merged).
do_test fts2q-4.segments {
execsql {
SELECT level, idx FROM t1_segdir ORDER BY level, idx;
}
} {0 0 0 1 1 0}
do_test fts2q-4.matches {
execsql {
SELECT OFFSETS(t1) FROM t1
WHERE t1 MATCH 'this OR that OR was OR a OR is OR test' ORDER BY rowid;
}
} [list {0 0 0 4 0 4 5 2 0 3 8 1 0 5 10 4} \
{0 1 0 4 0 2 5 3 0 3 9 1 0 5 11 4} \
{0 0 0 4 0 4 5 2 0 3 8 1 0 5 10 4}]
check_terms_all fts2q-4.1 {a four is one test that this three two was}
check_doclist_all fts2q-4.1.1 a {[1 0[2]] [2 0[2]] [3 0[2]]}
check_doclist_all fts2q-4.1.2 four {}
check_doclist_all fts2q-4.1.3 is {[1 0[1]] [3 0[1]]}
check_doclist_all fts2q-4.1.4 one {}
check_doclist_all fts2q-4.1.5 test {[1 0[3]] [2 0[3]] [3 0[3]]}
check_doclist_all fts2q-4.1.6 that {[2 0[0]]}
check_doclist_all fts2q-4.1.7 this {[1 0[0]] [3 0[0]]}
check_doclist_all fts2q-4.1.8 three {}
check_doclist_all fts2q-4.1.9 two {}
check_doclist_all fts2q-4.1.10 was {[2 0[1]]}
check_terms fts2q-4.2 0 0 {a four test that was}
check_doclist fts2q-4.2.1 0 0 a {[2 0[2]]}
check_doclist fts2q-4.2.2 0 0 four {[2]}
check_doclist fts2q-4.2.3 0 0 test {[2 0[3]]}
check_doclist fts2q-4.2.4 0 0 that {[2 0[0]]}
check_doclist fts2q-4.2.5 0 0 was {[2 0[1]]}
check_terms fts2q-4.3 0 1 {a four is test this}
check_doclist fts2q-4.3.1 0 1 a {[3 0[2]]}
check_doclist fts2q-4.3.2 0 1 four {[3]}
check_doclist fts2q-4.3.3 0 1 is {[3 0[1]]}
check_doclist fts2q-4.3.4 0 1 test {[3 0[3]]}
check_doclist fts2q-4.3.5 0 1 this {[3 0[0]]}
check_terms fts2q-4.4 1 0 {a four is one test that this three two was}
check_doclist fts2q-4.4.1 1 0 a {[1 0[2]] [2 0[2]] [3 0[2]]}
check_doclist fts2q-4.4.2 1 0 four {[1] [2 0[4]] [3 0[4]]}
check_doclist fts2q-4.4.3 1 0 is {[1 0[1]] [3 0[1]]}
check_doclist fts2q-4.4.4 1 0 one {[1] [2] [3]}
check_doclist fts2q-4.4.5 1 0 test {[1 0[3]] [2 0[3]] [3 0[3]]}
check_doclist fts2q-4.4.6 1 0 that {[2 0[0]]}
check_doclist fts2q-4.4.7 1 0 this {[1 0[0]] [3 0[0]]}
check_doclist fts2q-4.4.8 1 0 three {[1] [2] [3]}
check_doclist fts2q-4.4.9 1 0 two {[1] [2] [3]}
check_doclist fts2q-4.4.10 1 0 was {[2 0[1]]}
# Optimize should leave the result in the level of the highest-level
# prior segment.
do_test fts2q-4.5 {
execsql {
SELECT OPTIMIZE(t1) FROM t1 LIMIT 1;
SELECT level, idx FROM t1_segdir ORDER BY level, idx;
}
} {{Index optimized} 1 0}
# Identical to fts2q-4.matches.
do_test fts2q-4.5.matches {
execsql {
SELECT OFFSETS(t1) FROM t1
WHERE t1 MATCH 'this OR that OR was OR a OR is OR test' ORDER BY rowid;
}
} [list {0 0 0 4 0 4 5 2 0 3 8 1 0 5 10 4} \
{0 1 0 4 0 2 5 3 0 3 9 1 0 5 11 4} \
{0 0 0 4 0 4 5 2 0 3 8 1 0 5 10 4}]
check_terms_all fts2q-4.5.1 {a is test that this was}
check_doclist_all fts2q-4.5.1.1 a {[1 0[2]] [2 0[2]] [3 0[2]]}
check_doclist_all fts2q-4.5.1.2 is {[1 0[1]] [3 0[1]]}
check_doclist_all fts2q-4.5.1.3 test {[1 0[3]] [2 0[3]] [3 0[3]]}
check_doclist_all fts2q-4.5.1.4 that {[2 0[0]]}
check_doclist_all fts2q-4.5.1.5 this {[1 0[0]] [3 0[0]]}
check_doclist_all fts2q-4.5.1.6 was {[2 0[1]]}
check_terms fts2q-4.5.2 1 0 {a is test that this was}
check_doclist fts2q-4.5.2.1 1 0 a {[1 0[2]] [2 0[2]] [3 0[2]]}
check_doclist fts2q-4.5.2.2 1 0 is {[1 0[1]] [3 0[1]]}
check_doclist fts2q-4.5.2.3 1 0 test {[1 0[3]] [2 0[3]] [3 0[3]]}
check_doclist fts2q-4.5.2.4 1 0 that {[2 0[0]]}
check_doclist fts2q-4.5.2.5 1 0 this {[1 0[0]] [3 0[0]]}
check_doclist fts2q-4.5.2.6 1 0 was {[2 0[1]]}
# Re-optimizing does nothing.
do_test fts2q-5.0 {
execsql {
SELECT OPTIMIZE(t1) FROM t1 LIMIT 1;
SELECT level, idx FROM t1_segdir ORDER BY level, idx;
}
} {{Index already optimal} 1 0}
# Even if we move things around, still does nothing.
do_test fts2q-5.1 {
execsql {
UPDATE t1_segdir SET level = 2 WHERE level = 1 AND idx = 0;
SELECT OPTIMIZE(t1) FROM t1 LIMIT 1;
SELECT level, idx FROM t1_segdir ORDER BY level, idx;
}
} {{Index already optimal} 2 0}
finish_test

121
test/fts2r.test Normal file
View File

@ -0,0 +1,121 @@
# 2008 July 29
#
# 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.
#
#*************************************************************************
# These tests exercise the various types of fts2 cursors.
#
# $Id: fts2r.test,v 1.1 2008/07/29 20:38:18 shess Exp $
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# If SQLITE_ENABLE_FTS2 is not defined, omit this file.
ifcapable !fts2 {
finish_test
return
}
#*************************************************************************
# Test table scan (QUERY_GENERIC). This kind of query happens for
# queries with no WHERE clause, or for WHERE clauses which cannot be
# satisfied by an index.
db eval {
DROP TABLE IF EXISTS t1;
CREATE VIRTUAL TABLE t1 USING fts2(c);
INSERT INTO t1 (rowid, c) VALUES (1, 'This is a test');
INSERT INTO t1 (rowid, c) VALUES (2, 'That was a test');
INSERT INTO t1 (rowid, c) VALUES (3, 'This is a test');
}
do_test fts2e-1.1 {
execsql {
SELECT rowid FROM t1 ORDER BY rowid;
}
} {1 2 3}
do_test fts2e-1.2 {
execsql {
SELECT rowid FROM t1 WHERE c LIKE '%test' ORDER BY rowid;
}
} {1 2 3}
do_test fts2e-1.3 {
execsql {
SELECT rowid FROM t1 WHERE c LIKE 'That%' ORDER BY rowid;
}
} {2}
#*************************************************************************
# Test lookup by rowid (QUERY_ROWID). This kind of query happens for
# queries which select by the rowid implicit index.
db eval {
DROP TABLE IF EXISTS t1;
DROP TABLE IF EXISTS t2;
CREATE VIRTUAL TABLE t1 USING fts2(c);
CREATE TABLE t2(id INTEGER PRIMARY KEY AUTOINCREMENT, weight INTEGER UNIQUE);
INSERT INTO t2 VALUES (null, 10);
INSERT INTO t1 (rowid, c) VALUES (last_insert_rowid(), 'This is a test');
INSERT INTO t2 VALUES (null, 5);
INSERT INTO t1 (rowid, c) VALUES (last_insert_rowid(), 'That was a test');
INSERT INTO t2 VALUES (null, 20);
INSERT INTO t1 (rowid, c) VALUES (last_insert_rowid(), 'This is a test');
}
# TODO(shess): This actually is doing QUERY_GENERIC? I'd have
# expected QUERY_ROWID in this case, as for a very large table the
# full scan is less efficient.
do_test fts2e-2.1 {
execsql {
SELECT rowid FROM t1 WHERE rowid in (1, 2, 10);
}
} {1 2}
do_test fts2e-2.2 {
execsql {
SELECT t1.rowid, weight FROM t1, t2 WHERE t2.id = t1.rowid ORDER BY weight;
}
} {2 5 1 10 3 20}
do_test fts2e-2.3 {
execsql {
SELECT t1.rowid, weight FROM t1, t2
WHERE t2.weight>5 AND t2.id = t1.rowid ORDER BY weight;
}
} {1 10 3 20}
#*************************************************************************
# Test lookup by MATCH (QUERY_FULLTEXT). This is the fulltext index.
db eval {
DROP TABLE IF EXISTS t1;
DROP TABLE IF EXISTS t2;
CREATE VIRTUAL TABLE t1 USING fts2(c);
CREATE TABLE t2(id INTEGER PRIMARY KEY AUTOINCREMENT, weight INTEGER UNIQUE);
INSERT INTO t2 VALUES (null, 10);
INSERT INTO t1 (rowid, c) VALUES (last_insert_rowid(), 'This is a test');
INSERT INTO t2 VALUES (null, 5);
INSERT INTO t1 (rowid, c) VALUES (last_insert_rowid(), 'That was a test');
INSERT INTO t2 VALUES (null, 20);
INSERT INTO t1 (rowid, c) VALUES (last_insert_rowid(), 'This is a test');
}
do_test fts2e-3.1 {
execsql {
SELECT rowid FROM t1 WHERE t1 MATCH 'this' ORDER BY rowid;
}
} {1 3}
do_test fts2e-3.2 {
execsql {
SELECT t1.rowid, weight FROM t1, t2
WHERE t1 MATCH 'this' AND t1.rowid = t2.id ORDER BY weight;
}
} {1 10 3 20}
finish_test

View File

@ -1,3 +1,4 @@
# 2007 November 23
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
@ -6,7 +7,7 @@
#***********************************************************************
# This file runs all tests.
#
# $Id: fts3.test,v 1.1 2007/11/23 17:31:19 drh Exp $
# $Id: fts3.test,v 1.2 2008/07/23 18:17:32 drh Exp $
proc lshift {lvar} {
upvar $lvar l
@ -33,8 +34,7 @@ set testdir [file dirname $argv0]
source $testdir/tester.tcl
# If SQLITE_ENABLE_FTS3 is defined, omit this file.
ifcapable !fts3 {
puts stderr "this build does not include FTS3 capability"
exit 1
return
}
rename finish_test really_finish_test
proc finish_test {} {}

125
test/fts3e.test Normal file
View File

@ -0,0 +1,125 @@
# 2008 July 29
#
# 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.
#
#*************************************************************************
# These tests exercise the various types of fts3 cursors.
#
# $Id: fts3e.test,v 1.1 2008/07/29 20:24:46 shess Exp $
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# If SQLITE_ENABLE_FTS3 is not defined, omit this file.
ifcapable !fts3 {
finish_test
return
}
#*************************************************************************
# Test table scan (QUERY_GENERIC). This kind of query happens for
# queries with no WHERE clause, or for WHERE clauses which cannot be
# satisfied by an index.
db eval {
DROP TABLE IF EXISTS t1;
CREATE VIRTUAL TABLE t1 USING fts3(c);
INSERT INTO t1 (docid, c) VALUES (1, 'This is a test');
INSERT INTO t1 (docid, c) VALUES (2, 'That was a test');
INSERT INTO t1 (docid, c) VALUES (3, 'This is a test');
}
do_test fts3e-1.1 {
execsql {
SELECT docid FROM t1 ORDER BY docid;
}
} {1 2 3}
do_test fts3e-1.2 {
execsql {
SELECT docid FROM t1 WHERE c LIKE '%test' ORDER BY docid;
}
} {1 2 3}
do_test fts3e-1.3 {
execsql {
SELECT docid FROM t1 WHERE c LIKE 'That%' ORDER BY docid;
}
} {2}
#*************************************************************************
# Test lookup by docid (QUERY_DOCID). This kind of query happens for
# queries which select by the docid/rowid implicit index.
db eval {
DROP TABLE IF EXISTS t1;
DROP TABLE IF EXISTS t2;
CREATE VIRTUAL TABLE t1 USING fts3(c);
CREATE TABLE t2(id INTEGER PRIMARY KEY AUTOINCREMENT, weight INTEGER UNIQUE);
INSERT INTO t2 VALUES (null, 10);
INSERT INTO t1 (docid, c) VALUES (last_insert_rowid(), 'This is a test');
INSERT INTO t2 VALUES (null, 5);
INSERT INTO t1 (docid, c) VALUES (last_insert_rowid(), 'That was a test');
INSERT INTO t2 VALUES (null, 20);
INSERT INTO t1 (docid, c) VALUES (last_insert_rowid(), 'This is a test');
}
# TODO(shess): This actually is doing QUERY_GENERIC? I'd have
# expected QUERY_DOCID in this case, as for a very large table the
# full scan is less efficient.
do_test fts3e-2.1 {
execsql {
SELECT docid FROM t1 WHERE docid in (1, 2, 10);
SELECT rowid FROM t1 WHERE rowid in (1, 2, 10);
}
} {1 2 1 2}
do_test fts3e-2.2 {
execsql {
SELECT docid, weight FROM t1, t2 WHERE t2.id = t1.docid ORDER BY weight;
SELECT t1.rowid, weight FROM t1, t2 WHERE t2.id = t1.rowid ORDER BY weight;
}
} {2 5 1 10 3 20 2 5 1 10 3 20}
do_test fts3e-2.3 {
execsql {
SELECT docid, weight FROM t1, t2
WHERE t2.weight>5 AND t2.id = t1.docid ORDER BY weight;
SELECT t1.rowid, weight FROM t1, t2
WHERE t2.weight>5 AND t2.id = t1.rowid ORDER BY weight;
}
} {1 10 3 20 1 10 3 20}
#*************************************************************************
# Test lookup by MATCH (QUERY_FULLTEXT). This is the fulltext index.
db eval {
DROP TABLE IF EXISTS t1;
DROP TABLE IF EXISTS t2;
CREATE VIRTUAL TABLE t1 USING fts3(c);
CREATE TABLE t2(id INTEGER PRIMARY KEY AUTOINCREMENT, weight INTEGER UNIQUE);
INSERT INTO t2 VALUES (null, 10);
INSERT INTO t1 (docid, c) VALUES (last_insert_rowid(), 'This is a test');
INSERT INTO t2 VALUES (null, 5);
INSERT INTO t1 (docid, c) VALUES (last_insert_rowid(), 'That was a test');
INSERT INTO t2 VALUES (null, 20);
INSERT INTO t1 (docid, c) VALUES (last_insert_rowid(), 'This is a test');
}
do_test fts3e-3.1 {
execsql {
SELECT docid FROM t1 WHERE t1 MATCH 'this' ORDER BY docid;
}
} {1 3}
do_test fts3e-3.2 {
execsql {
SELECT docid, weight FROM t1, t2
WHERE t1 MATCH 'this' AND t1.docid = t2.id ORDER BY weight;
}
} {1 10 3 20}
finish_test

View File

@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The
# focus of this file is testing built-in functions.
#
# $Id: func.test,v 1.82 2008/07/15 00:27:35 drh Exp $
# $Id: func.test,v 1.86 2008/08/04 03:51:24 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@ -290,18 +290,32 @@ do_test func-8.4 {
SELECT max('z+'||a||'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP') FROM t3;
}
} {z+67890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP}
do_test func-8.5 {
execsql {
SELECT sum(x) FROM (SELECT '9223372036' || '854775807' AS x
UNION ALL SELECT -9223372036854775807)
}
} {0}
do_test func-8.6 {
execsql {
SELECT sum(x) FROM (SELECT '9223372036' || '854775808' AS x
UNION ALL SELECT -9223372036854775807)
}
} {1.0}
ifcapable compound {
do_test func-8.5 {
execsql {
SELECT sum(x) FROM (SELECT '9223372036' || '854775807' AS x
UNION ALL SELECT -9223372036854775807)
}
} {0}
do_test func-8.6 {
execsql {
SELECT typeof(sum(x)) FROM (SELECT '9223372036' || '854775807' AS x
UNION ALL SELECT -9223372036854775807)
}
} {integer}
do_test func-8.7 {
execsql {
SELECT typeof(sum(x)) FROM (SELECT '9223372036' || '854775808' AS x
UNION ALL SELECT -9223372036854775807)
}
} {real}
do_test func-8.8 {
execsql {
SELECT sum(x)>0.0 FROM (SELECT '9223372036' || '854775808' AS x
UNION ALL SELECT -9223372036850000000)
}
} {1}
}
# How do you test the random() function in a meaningful, deterministic way?
#
@ -443,11 +457,13 @@ if {[db eval {PRAGMA encoding}]=="UTF-8"} {
}
} {{hello world} 1}
} else {
do_test func-12.1-utf16 {
execsql {
SELECT test_destructor16('hello world'), test_destructor_count();
ifcapable {utf16} {
do_test func-12.1-utf16 {
execsql {
SELECT test_destructor16('hello world'), test_destructor_count();
}
} {{hello world} 1}
}
} {{hello world} 1}
}
do_test func-12.2 {
execsql {

View File

@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The
# focus of this file is testing the IN and BETWEEN operator.
#
# $Id: in.test,v 1.21 2008/06/26 18:04:03 danielk1977 Exp $
# $Id: in.test,v 1.22 2008/08/04 03:51:24 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@ -366,6 +366,7 @@ do_test in-11.6 {
# Test error conditions with expressions of the form IN(<compound select>).
#
ifcapable compound {
do_test in-12.1 {
execsql {
CREATE TABLE t2(a, b, c);
@ -428,6 +429,7 @@ do_test in-12.9 {
);
}
} {1 {SELECTs to the left and right of INTERSECT do not have the same number of result columns}}
}
#------------------------------------------------------------------------

View File

@ -13,7 +13,7 @@
#
# <value> IN (SELECT <column> FROM <table>)
#
# $Id: in3.test,v 1.4 2008/03/12 10:39:00 danielk1977 Exp $
# $Id: in3.test,v 1.5 2008/08/04 03:51:24 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@ -103,13 +103,15 @@ do_test in3-1.12 {
# Has to use a temp-table because of the compound sub-select.
#
do_test in3-1.13 {
exec_neph {
SELECT a FROM t1 WHERE a IN (
SELECT a FROM t1 UNION ALL SELECT a FROM t1
)
}
} {1 1 3 5}
ifcapable compound {
do_test in3-1.13 {
exec_neph {
SELECT a FROM t1 WHERE a IN (
SELECT a FROM t1 UNION ALL SELECT a FROM t1
)
}
} {1 1 3 5}
}
# The first of these queries has to use the temp-table, because the
# collation sequence used for the index on "t1.a" does not match the

View File

@ -9,7 +9,7 @@
#
#***********************************************************************
#
# $Id: incrblob_err.test,v 1.12 2008/07/08 17:43:57 danielk1977 Exp $
# $Id: incrblob_err.test,v 1.14 2008/07/18 17:16:27 drh Exp $
#
set testdir [file dirname $argv0]
@ -115,6 +115,7 @@ do_ioerr_test incrblob_err-7 -cksum 1 -sqlprep {
sqlite3_blob_read $::blob [expr 500*1020-20] 20
close $::blob
}
catch {db2 close}
do_ioerr_test incrblob_err-8 -cksum 1 -sqlprep {
PRAGMA auto_vacuum = 1;
@ -131,6 +132,6 @@ do_ioerr_test incrblob_err-8 -cksum 1 -sqlprep {
close $::blob
}
db2 close
catch {db2 close}
finish_test

View File

@ -14,7 +14,7 @@
# Note: There are also some tests for incremental vacuum and IO
# errors in incrvacuum_ioerr.test.
#
# $Id: incrvacuum.test,v 1.18 2008/01/21 16:22:46 drh Exp $
# $Id: incrvacuum.test,v 1.19 2008/07/30 17:28:04 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@ -35,7 +35,10 @@ do_test incrvacuum-1.1 {
}
} $sqlite_options(default_autovacuum)
do_test incrvacuum-1.2.0 {
expr {[file size test.db] > 0}
# File size is sometimes 1 instead of 0 due to the hack we put in
# to work around ticket #3260. Search for comments on #3260 in
# os_unix.c.
expr {[file size test.db] > 1}
} {0}
do_test incrvacuum-1.2 {
# This command will create the database.
@ -689,7 +692,10 @@ sqlite3 db test.db ; set ::DB [sqlite3_connection_pointer db]
sqlite3 db2 test.db
do_test incrvacuum-13.1 {
expr {[file size test.db]>0}
# File size is sometimes 1 instead of 0 due to the hack we put in
# to work around ticket #3260. Search for comments on #3260 in
# os_unix.c.
expr {[file size test.db]>1}
} {0}
do_test incrvacuum-13.2 {
set ::STMT [sqlite3_prepare $::DB {PRAGMA auto_vacuum = 2} -1 DUMMY]

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