Index: Makefile.linux-gcc =================================================================== --- Makefile.linux-gcc 2009-09-03 13:32:06.000000000 -0700 +++ Makefile.linux-gcc 2009-07-01 12:08:39.000000000 -0700 @@ -14,7 +14,7 @@ #### The toplevel directory of the source tree. This is the directory # that contains this "Makefile.in" and the "configure.in" script. # -TOP = ../sqlite +TOP = .. #### C Compiler and options for use in building executables that # will run on the platform that is doing the build. @@ -33,13 +33,13 @@ # appropriately: # #THREADSAFE = -DTHREADSAFE=1 -THREADSAFE = -DTHREADSAFE=0 +THREADSAFE = -DTHREADSAFE=1 #### Specify any extra linker options needed to make the library # thread safe # #THREADLIB = -lpthread -THREADLIB = +THREADLIB = -lpthread #### Specify any extra libraries needed to access required functions. # @@ -57,8 +57,29 @@ #OPTS = -DSQLITE_DEBUG=2 #OPTS = -DSQLITE_DEBUG=1 #OPTS = -OPTS = -DNDEBUG=1 -OPTS += -DHAVE_FDATASYNC=1 + +# These flags match those for SQLITE_CFLAGS in config.mk. + +OPTS += -DNDEBUG +OPTS += -DSQLITE_CORE +OPTS += -DSQLITE_ENABLE_FTS1 -DSQLITE_ENABLE_BROKEN_FTS1 +OPTS += -DSQLITE_ENABLE_FTS2 -DSQLITE_ENABLE_BROKEN_FTS2 +OPTS += -DSQLITE_DEFAULT_FILE_PERMISSIONS=0600 +OPTS += -DHAVE_USLEEP=1 + +# Additional SQLite tests. +OPTS += -DSQLITE_MEMDEBUG=1 + +# Don't include these ones, they break the SQLite tests. +# -DSQLITE_OMIT_ATTACH=1 \ +# -DSQLITE_OMIT_LOAD_EXTENSION=1 \ +# -DSQLITE_OMIT_VACUUM=1 \ +# -DSQLITE_TRANSACTION_DEFAULT_IMMEDIATE=1 \ + +SHELL_ICU = $(TOP)/src/shell_icu_linux.c -licuuc + +# TODO(shess) I can't see why I need this setting. +OPTS += -DOS_UNIX=1 #### The suffix to add to executable files. ".exe" for windows. # Nothing for unix. @@ -91,16 +112,16 @@ #### Extra compiler options needed for programs that use the TCL library. # -#TCL_FLAGS = +TCL_FLAGS = -I/usr/include/tcl8.4 #TCL_FLAGS = -DSTATIC_BUILD=1 -TCL_FLAGS = -I/home/drh/tcltk/8.4linux +#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 = -ltcl8.4 -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 Index: ext/fts1/fts1.c =================================================================== --- ext/fts1/fts1.c 2009-09-04 13:37:41.000000000 -0700 +++ ext/fts1/fts1.c 2009-09-14 18:16:55.000000000 -0700 @@ -1225,10 +1225,6 @@ break; } return rc; - - err: - sqlite3_finalize(s); - return rc; } /* Like sql_step_statement(), but convert SQLITE_DONE to SQLITE_OK. Index: ext/icu/icu.c =================================================================== --- ext/icu/icu.c 2009-09-03 13:32:06.000000000 -0700 +++ ext/icu/icu.c 2009-07-01 12:08:37.000000000 -0700 @@ -38,6 +38,11 @@ #include +// TODO(evanm): this is cut'n'pasted from fts2.c. Why is it necessary? +#if !defined(SQLITE_CORE) +# define SQLITE_CORE 1 +#endif + #ifndef SQLITE_CORE #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 Index: main.mk =================================================================== --- main.mk 2009-09-10 12:18:17.000000000 -0700 +++ main.mk 2009-09-15 11:45:21.000000000 -0700 @@ -69,6 +69,16 @@ walker.o where.o utf.o vtab.o +LIBOBJ += fts1.o \ + fts1_hash.o \ + fts1_tokenizer1.o \ + fts1_porter.o +LIBOBJ += fts2.o \ + fts2_hash.o \ + fts2_icu.o \ + fts2_porter.o \ + fts2_tokenizer.o \ + fts2_tokenizer1.o # All of the source code files. # @@ -243,6 +253,25 @@ $(TOP)/src/test_thread.c \ $(TOP)/src/test_wsd.c +TESTSRC += \ + $(TOP)/ext/fts1/fts1.c \ + $(TOP)/ext/fts1/fts1.h \ + $(TOP)/ext/fts1/fts1_hash.c \ + $(TOP)/ext/fts1/fts1_hash.h \ + $(TOP)/ext/fts1/fts1_porter.c \ + $(TOP)/ext/fts1/fts1_tokenizer.h \ + $(TOP)/ext/fts1/fts1_tokenizer1.c +TESTSRC += \ + $(TOP)/ext/fts2/fts2.c \ + $(TOP)/ext/fts2/fts2.h \ + $(TOP)/ext/fts2/fts2_hash.c \ + $(TOP)/ext/fts2/fts2_hash.h \ + $(TOP)/ext/fts2/fts2_icu.c \ + $(TOP)/ext/fts2/fts2_porter.c \ + $(TOP)/ext/fts2/fts2_tokenizer.h \ + $(TOP)/ext/fts2/fts2_tokenizer.c \ + $(TOP)/ext/fts2/fts2_tokenizer1.c + #TESTSRC += $(TOP)/ext/fts2/fts2_tokenizer.c #TESTSRC += $(TOP)/ext/fts3/fts3_tokenizer.c @@ -314,8 +343,8 @@ sqlite3$(EXE): $(TOP)/src/shell.c libsqlite3.a sqlite3.h $(TCCX) $(READLINE_FLAGS) -o sqlite3$(EXE) \ - $(TOP)/src/shell.c \ - libsqlite3.a $(LIBREADLINE) $(TLIBS) $(THREADLIB) + $(TOP)/src/shell.c $(SHELL_ICU) \ + libsqlite3.a $(LIBREADLINE) $(TLIBS) $(THREADLIB) -ldl objects: $(LIBOBJ_ORIG) @@ -447,6 +476,20 @@ $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/rtree/rtree.c + + +fts1.o: $(TOP)/ext/fts1/fts1.c $(HDR) $(EXTHDR) + $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts1/fts1.c + +fts1_hash.o: $(TOP)/ext/fts1/fts1_hash.c $(HDR) $(EXTHDR) + $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts1/fts1_hash.c + +fts1_tokenizer1.o: $(TOP)/ext/fts1/fts1_tokenizer1.c $(HDR) $(EXTHDR) + $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts1/fts1_tokenizer1.c + +fts1_porter.o: $(TOP)/ext/fts1/fts1_porter.c $(HDR) $(EXTHDR) + $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts1/fts1_porter.c + # Rules for building test programs and for running tests # tclsqlite3: $(TOP)/src/tclsqlite.c libsqlite3.a @@ -484,6 +527,15 @@ test: testfixture$(EXE) sqlite3$(EXE) ./testfixture$(EXE) $(TOP)/test/veryquick.test +ftstest: testfixture$(EXE) sqlite3$(EXE) + ./testfixture$(EXE) $(TOP)/test/fts.test + +fts1test: testfixture$(EXE) sqlite3$(EXE) + ./testfixture$(EXE) $(TOP)/test/fts1.test + +fts2test: testfixture$(EXE) sqlite3$(EXE) + ./testfixture$(EXE) $(TOP)/test/fts2.test + sqlite3_analyzer$(EXE): $(TOP)/src/tclsqlite.c sqlite3.c $(TESTSRC) \ $(TOP)/tool/spaceanal.tcl sed \ Index: src/expr.c =================================================================== --- src/expr.c 2009-09-08 12:16:11.000000000 -0700 +++ src/expr.c 2009-09-23 16:58:47.000000000 -0700 @@ -804,7 +804,9 @@ }else{ int nSize = exprStructSize(p); memcpy(zAlloc, p, nSize); - memset(&zAlloc[nSize], 0, EXPR_FULLSIZE-nSize); + if( EXPR_FULLSIZE>nSize ){ + memset(&zAlloc[nSize], 0, EXPR_FULLSIZE-nSize); + } } /* Set the EP_Reduced, EP_TokenOnly, and EP_Static flags appropriately. */ Index: src/func.c =================================================================== --- src/func.c 2009-09-04 13:37:42.000000000 -0700 +++ src/func.c 2009-09-14 18:18:18.000000000 -0700 @@ -1020,7 +1020,7 @@ } } if( zCharSet ){ - sqlite3_free(azChar); + sqlite3_free((void*)azChar); } } sqlite3_result_text(context, (char*)zIn, nIn, SQLITE_TRANSIENT); Index: src/os.h =================================================================== --- src/os.h 2009-09-04 13:37:42.000000000 -0700 +++ src/os.h 2009-09-14 18:18:24.000000000 -0700 @@ -29,6 +29,10 @@ ** will defined to either 1 or 0. One of the four will be 1. The other ** three will be 0. */ +#ifdef OS_SYMBIAN +# define SQLITE_OS_SYMBIAN 1 +# define SQLITE_OS_OTHER 1 +#endif #if defined(SQLITE_OS_OTHER) # if SQLITE_OS_OTHER==1 # undef SQLITE_OS_UNIX Index: src/os_unix.c =================================================================== --- src/os_unix.c 2009-09-10 12:14:55.000000000 -0700 +++ src/os_unix.c 2009-09-15 16:50:43.000000000 -0700 @@ -3215,6 +3215,7 @@ ********************** End sqlite3_file Methods ******************************* ******************************************************************************/ + /* ** This division contains definitions of sqlite3_io_methods objects that ** implement various file locking strategies. It also contains definitions @@ -3496,9 +3497,16 @@ */ /* +** Initializes a unixFile structure with zeros. +*/ +void initUnixFile(sqlite3_file* file) { + memset(file, 0, sizeof(unixFile)); +} + +/* ** Initialize the contents of the unixFile structure pointed to by pId. */ -static int fillInUnixFile( +int fillInUnixFile( sqlite3_vfs *pVfs, /* Pointer to vfs object */ int h, /* Open file descriptor of file being opened */ int dirfd, /* Directory file descriptor */ Index: src/os_win.c =================================================================== --- src/os_win.c 2009-09-10 15:08:39.000000000 -0700 +++ src/os_win.c 2009-09-14 18:26:16.000000000 -0700 @@ -1890,4 +1890,11 @@ return SQLITE_OK; } +void chromium_sqlite3_initialize_win_sqlite3_file(sqlite3_file* file, HANDLE handle) { + winFile* winSQLite3File = (winFile*)file; + memset(file, 0, sizeof(*file)); + winSQLite3File->pMethod = &winIoMethod; + winSQLite3File->h = handle; +} + #endif /* SQLITE_OS_WIN */ Index: src/pcache.c =================================================================== --- src/pcache.c 2009-09-04 13:37:42.000000000 -0700 +++ src/pcache.c 2009-09-15 16:41:55.000000000 -0700 @@ -542,14 +542,12 @@ return nPage; } -#ifdef SQLITE_TEST /* ** Get the suggested cache-size value. */ int sqlite3PcacheGetCachesize(PCache *pCache){ return pCache->nMax; } -#endif /* ** Set the suggested cache-size value. Index: src/pcache.h =================================================================== --- src/pcache.h 2009-09-04 13:37:42.000000000 -0700 +++ src/pcache.h 2009-09-15 16:41:52.000000000 -0700 @@ -139,9 +139,7 @@ ** of the suggested cache-sizes. */ void sqlite3PcacheSetCachesize(PCache *, int); -#ifdef SQLITE_TEST int sqlite3PcacheGetCachesize(PCache *); -#endif #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT /* Try to return memory used by the pcache module to the main memory heap */ Index: src/shell.c =================================================================== --- src/shell.c 2009-09-04 13:37:43.000000000 -0700 +++ src/shell.c 2009-09-15 11:32:08.000000000 -0700 @@ -3007,6 +3007,18 @@ int i; int rc = 0; + /* Begin evanm patch. */ +#ifdef SQLITE_GEARS_DISABLE_SHELL_ICU + /* Gears doesn't use this. */ +#else + extern int sqlite_shell_init_icu(); + if( !sqlite_shell_init_icu() ){ + fprintf(stderr, "%s: warning: couldn't find icudt38.dll; " + "queries against ICU FTS tables will fail.\n", argv[0]); + } +#endif + /* End evanm patch. */ + Argv0 = argv[0]; main_init(&data); stdin_is_interactive = isatty(0); Index: src/sqlite3ext.h =================================================================== --- src/sqlite3ext.h 2009-09-03 13:32:06.000000000 -0700 +++ src/sqlite3ext.h 2009-09-15 11:34:43.000000000 -0700 @@ -372,9 +372,15 @@ #define sqlite3_next_stmt sqlite3_api->next_stmt #define sqlite3_sql sqlite3_api->sql #define sqlite3_status sqlite3_api->status -#endif /* SQLITE_CORE */ #define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api = 0; #define SQLITE_EXTENSION_INIT2(v) sqlite3_api = v; +#else + +#define SQLITE_EXTENSION_INIT1 +#define SQLITE_EXTENSION_INIT2(v) + +#endif /* SQLITE_CORE */ + #endif /* _SQLITE3EXT_H_ */ Index: src/test_autoext.c =================================================================== --- src/test_autoext.c 2009-09-03 13:32:06.000000000 -0700 +++ src/test_autoext.c 2009-09-15 18:14:35.000000000 -0700 @@ -17,7 +17,9 @@ #include "sqlite3ext.h" #ifndef SQLITE_OMIT_LOAD_EXTENSION +#ifndef SQLITE_CORE static SQLITE_EXTENSION_INIT1 +#endif /* ** The sqr() SQL function returns the square of its input value. Index: src/quick.test =================================================================== --- test/quick.test 2009-09-04 13:37:44.000000000 -0700 +++ test/quick.test 2009-09-15 11:34:54.000000000 -0700 @@ -58,6 +58,9 @@ crash7.test delete3.test fts3.test + fts.test + fts1.test + fts2.test fuzz.test fuzz3.test fuzz_malloc.test Index: src/os_symbian.cc =================================================================== --- src/os_symbian.cc 1969-12-31 16:00:00.000000000 -0800 +++ src/os_symbian.cc 2009-07-01 12:08:37.000000000 -0700 @@ -0,0 +1,579 @@ +// Copyright 2008, Google Inc. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// 3. Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This file contains code that is specific to Symbian. +// Differently from the rest of SQLite, it is implemented in C++ as this is +// the native language of the OS and all interfaces we need to use are C++. +// +// This file follows the Gears code style guidelines. + +#ifdef OS_SYMBIAN +#include +#include +#include +#include + +extern "C" { +#include "sqliteInt.h" +#include "os_common.h" +} + +const TInt kFileLockAttempts = 3; + +// The global file system session. +RFs g_fs_session; + +static TInt UTF8ToUTF16(const char *in, TDes *out16) { + assert(in); + TPtrC8 in_des(reinterpret_cast(in)); + return CnvUtfConverter::ConvertToUnicodeFromUtf8(*out16, in_des); +} + +static TInt UTF16ToUTF8(const TDesC16& in16, TDes8 *out8) { + return CnvUtfConverter::ConvertFromUnicodeToUtf8(*out8, in16); +} + +// The SymbianFile structure is a subclass of sqlite3_file* specific to the +// Symbian portability layer. +struct SymbianFile { + const sqlite3_io_methods *methods; + RFile handle; // The file handle + TUint8 lock_type; // Type of lock currently held on this file + TUint16 shared_lock_byte; // Randomly chosen byte used as a shared lock +}; + +static SymbianFile* ConvertToSymbianFile(sqlite3_file* const id) { + assert(id); + return reinterpret_cast(id); +} + +static int SymbianClose(sqlite3_file *id) { + SymbianFile *file_id = ConvertToSymbianFile(id); + file_id->handle.Close(); + OpenCounter(-1); + return SQLITE_OK; +} + +static int SymbianRead(sqlite3_file *id, + void *buffer, + int amount, + sqlite3_int64 offset) { + assert(buffer); + assert(amount >=0); + assert(offset >=0); + + SymbianFile* file_id = ConvertToSymbianFile(id); + TPtr8 dest(static_cast(buffer), amount); + + if (KErrNone == file_id->handle.Read(offset, dest, amount)) { + if (dest.Length() == amount) { + return SQLITE_OK; + } else { + return SQLITE_IOERR_SHORT_READ; + } + } else { + return SQLITE_IOERR; + } +} + +static int SymbianWrite(sqlite3_file *id, + const void *buffer, + int amount, + sqlite3_int64 offset) { + assert(buffer); + assert(amount >=0); + assert(offset >=0); + + SymbianFile *file_id = ConvertToSymbianFile(id); + TPtrC8 src(static_cast(buffer), amount); + if (file_id->handle.Write(offset, src) != KErrNone) { + return SQLITE_IOERR_WRITE; + } + + return SQLITE_OK; +} + +static int SymbianTruncate(sqlite3_file *id, sqlite3_int64 bytes) { + assert(bytes >=0); + + SymbianFile *file_id = ConvertToSymbianFile(id); + if (file_id->handle.SetSize(bytes) != KErrNone) { + return SQLITE_IOERR; + } + return SQLITE_OK; +} + +static int SymbianSync(sqlite3_file *id, int /*flags*/) { + SymbianFile *file_id = ConvertToSymbianFile(id); + if (file_id->handle.Flush() != KErrNone) { + return SQLITE_IOERR; + } else { + return SQLITE_OK; + } +} + +static int SymbianFileSize(sqlite3_file *id, sqlite3_int64 *size) { + assert(size); + + SymbianFile *file_id = ConvertToSymbianFile(id); + TInt size_tmp; + if (file_id->handle.Size(size_tmp) != KErrNone) { + return SQLITE_IOERR; + } + *size = size_tmp; + return SQLITE_OK; +} + +// File lock/unlock functions; see os_win.c for a description +// of the algorithm used. +static int GetReadLock(SymbianFile *file) { + file->shared_lock_byte = Math::Random() % (SHARED_SIZE - 1); + return file->handle.Lock(SHARED_FIRST + file->shared_lock_byte, 1); +} + +static int UnlockReadLock(SymbianFile *file) { + return file->handle.UnLock(SHARED_FIRST + file->shared_lock_byte, 1); +} + +static int SymbianLock(sqlite3_file *id, int lock_type) { + SymbianFile *file = ConvertToSymbianFile(id); + if (file->lock_type >= lock_type) { + return SQLITE_OK; + } + + // Make sure the locking sequence is correct + assert(file->lock_type != NO_LOCK || lock_type == SHARED_LOCK); + assert(lock_type != PENDING_LOCK); + assert(lock_type != RESERVED_LOCK || file->lock_type == SHARED_LOCK); + + // Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or + // a SHARED lock. If we are acquiring a SHARED lock, the acquisition of + // the PENDING_LOCK byte is temporary. + int new_lock_type = file->lock_type; + int got_pending_lock = 0; + int res = KErrNone; + if (file->lock_type == NO_LOCK || + (lock_type == EXCLUSIVE_LOCK && file->lock_type == RESERVED_LOCK)) { + int count = kFileLockAttempts; + while (count-- > 0 && + (res = file->handle.Lock(PENDING_BYTE, 1)) != KErrNone ) { + // Try 3 times to get the pending lock. The pending lock might be + // held by another reader process who will release it momentarily. + OSTRACE2("could not get a PENDING lock. cnt=%d\n", cnt); + User::After(1000); + } + got_pending_lock = (res == KErrNone? 1 : 0); + } + + // Acquire a shared lock + if (lock_type == SHARED_LOCK && res == KErrNone) { + assert(file->lock_type == NO_LOCK); + res = GetReadLock(file); + if (res == KErrNone) { + new_lock_type = SHARED_LOCK; + } + } + + // Acquire a RESERVED lock + if (lock_type == RESERVED_LOCK && res == KErrNone) { + assert(file->lock_type == SHARED_LOCK); + res = file->handle.Lock(RESERVED_BYTE, 1); + if (res == KErrNone) { + new_lock_type = RESERVED_LOCK; + } + } + + // Acquire a PENDING lock + if (lock_type == EXCLUSIVE_LOCK && res == KErrNone) { + new_lock_type = PENDING_LOCK; + got_pending_lock = 0; + } + + // Acquire an EXCLUSIVE lock + if (lock_type == EXCLUSIVE_LOCK && res == KErrNone) { + assert(file->lock_type >= SHARED_LOCK); + res = UnlockReadLock(file); + OSTRACE2("unreadlock = %d\n", res); + res = file->handle.Lock(SHARED_FIRST, SHARED_SIZE); + if (res == KErrNone) { + new_lock_type = EXCLUSIVE_LOCK; + } else { + OSTRACE2("error-code = %d\n", GetLastError()); + GetReadLock(file); + } + } + + // If we are holding a PENDING lock that ought to be released, then + // release it now. + if (got_pending_lock && lock_type == SHARED_LOCK) { + file->handle.UnLock(PENDING_BYTE, 1); + } + + // Update the state of the lock held in the file descriptor, then + // return the appropriate result code. + file->lock_type = new_lock_type; + if (res == KErrNone) { + return SQLITE_OK; + } else { + OSTRACE4("LOCK FAILED %d trying for %d but got %d\n", file->handle, + lock_type, new_lock_type); + return SQLITE_BUSY; + } +} + +static int SymbianUnlock(sqlite3_file *id, int lock_type) { + int type; + int rc = SQLITE_OK; + SymbianFile *file = ConvertToSymbianFile(id); + assert(lock_type <= SHARED_LOCK); + OSTRACE5("UNLOCK %d to %d was %d(%d)\n", file->handle, lock_type, + file->lock_type, file->shared_lock_byte); + type = file->lock_type; + if (type >= EXCLUSIVE_LOCK) { + file->handle.UnLock(SHARED_FIRST, SHARED_SIZE); + if (lock_type == SHARED_LOCK && GetReadLock(file) != KErrNone) { + // This should never happen. We should always be able to + // reacquire the read lock + rc = SQLITE_IOERR_UNLOCK; + } + } + if (type >= RESERVED_LOCK) { + file->handle.UnLock(RESERVED_BYTE, 1); + } + if (lock_type == NO_LOCK && type >= SHARED_LOCK) { + UnlockReadLock(file); + } + if (type >= PENDING_LOCK) { + file->handle.UnLock(PENDING_BYTE, 1); + } + file->lock_type = lock_type; + return rc; +} + +static int SymbianCheckReservedLock(sqlite3_file *id, int *result) { + int rc; + SymbianFile *file = ConvertToSymbianFile(id); + if (file->lock_type >= RESERVED_LOCK) { + rc = 1; + OSTRACE3("TEST WR-LOCK %d %d (local)\n", pFile->h, rc); + } else { + rc = file->handle.Lock(RESERVED_BYTE, 1); + if (rc == KErrNone) { + file->handle.UnLock(RESERVED_BYTE, 1); + } + rc = !rc; + OSTRACE3("TEST WR-LOCK %d %d (remote)\n", file->handle, rc); + } + *result = rc; + return SQLITE_OK; +} + +static int SymbianFileControl(sqlite3_file */*id*/, + int /*op*/, + void */*arg*/) { + return SQLITE_OK; +} + +static int SymbianSectorSize(sqlite3_file */*id*/) { + return SQLITE_DEFAULT_SECTOR_SIZE; +} + +static int SymbianDeviceCharacteristics(sqlite3_file */*id*/) { + return 0; +} + +/* +** This vector defines all the methods that can operate on a +** sqlite3_file for Symbian. +*/ +static const sqlite3_io_methods SymbianIoMethod = { + 1, // iVersion + SymbianClose, + SymbianRead, + SymbianWrite, + SymbianTruncate, + SymbianSync, + SymbianFileSize, + SymbianLock, + SymbianUnlock, + SymbianCheckReservedLock, + SymbianFileControl, + SymbianSectorSize, + SymbianDeviceCharacteristics +}; + +// ============================================================================ +// vfs methods begin here +// ============================================================================ +static int SymbianOpen(sqlite3_vfs */*vfs*/, + const char *name, + sqlite3_file *id, + int flags, + int *out_flags) { + TUint desired_access; + TUint share_mode; + TInt err = KErrNone; + TFileName name_utf16; + SymbianFile *file = ConvertToSymbianFile(id); + + if (out_flags) { + *out_flags = flags; + } + + // if the name is NULL we have to open a temporary file. + if (!name) { + TPath private_path; + TFileName file_name; + if (g_fs_session.PrivatePath(private_path) != KErrNone) { + return SQLITE_CANTOPEN; + } + if (file->handle.Temp(g_fs_session, + private_path, + file_name, + EFileWrite) != + KErrNone) { + return SQLITE_CANTOPEN; + } + file->methods = &SymbianIoMethod; + file->lock_type = NO_LOCK; + file->shared_lock_byte = 0; + OpenCounter(+1); + return SQLITE_OK; + } + + if (UTF8ToUTF16(name, &name_utf16) != KErrNone) + return SQLITE_CANTOPEN; + + if (flags & SQLITE_OPEN_READWRITE) { + desired_access = EFileWrite; + } else { + desired_access = EFileRead; + } + if (flags & SQLITE_OPEN_MAIN_DB) { + share_mode = EFileShareReadersOrWriters; + } else { + share_mode = 0; + } + + if (flags & SQLITE_OPEN_CREATE) { + err = file->handle.Create(g_fs_session, + name_utf16, + desired_access | share_mode); + if (err != KErrNone && err != KErrAlreadyExists) { + return SQLITE_CANTOPEN; + } + } + + if (err != KErrNone) { + err = file->handle.Open(g_fs_session, + name_utf16, + desired_access | share_mode); + if (err != KErrNone && flags & SQLITE_OPEN_READWRITE) { + if (out_flags) { + *out_flags = (flags | SQLITE_OPEN_READONLY) & ~SQLITE_OPEN_READWRITE; + } + desired_access = EFileRead; + err = file->handle.Open(g_fs_session, + name_utf16, + desired_access | share_mode); + } + if (err != KErrNone) { + return SQLITE_CANTOPEN; + } + } + file->methods = &SymbianIoMethod; + file->lock_type = NO_LOCK; + file->shared_lock_byte = 0; + OpenCounter(+1); + return SQLITE_OK; +} + +static int SymbianDelete(sqlite3_vfs */*vfs*/, + const char *file_name, + int /*sync_dir*/) { + assert(file_name); + TFileName file_name_utf16; + + if (UTF8ToUTF16(file_name, &file_name_utf16) != KErrNone) { + return SQLITE_ERROR; + } + + TInt result = g_fs_session.Delete(file_name_utf16); + return (result == KErrNone || result == KErrPathNotFound)? + SQLITE_OK : SQLITE_IOERR_DELETE; +} + +static int SymbianAccess(sqlite3_vfs */*vfs*/, + const char *file_name, + int flags, + int *result) { + assert(file_name); + TEntry entry; + TFileName file_name_utf16; + + if (UTF8ToUTF16(file_name, &file_name_utf16) != KErrNone) { + return SQLITE_ERROR; + } + + if (g_fs_session.Entry(file_name_utf16, entry) != KErrNone) { + *result = 0; + return SQLITE_OK; + } + + switch (flags) { + case SQLITE_ACCESS_READ: + case SQLITE_ACCESS_EXISTS: + *result = !entry.IsDir(); + break; + case SQLITE_ACCESS_READWRITE: + *result = !entry.IsDir() && !entry.IsReadOnly(); + break; + default: + return SQLITE_ERROR; + } + + return SQLITE_OK; +} + +static int SymbianFullPathname(sqlite3_vfs */*vfs*/, + const char *relative, + int full_len, + char *full) { + assert(relative); + assert(full); + + TParse parse; + TPath relative_utf16; + TPath base_path; + TPtr8 full_utf8(reinterpret_cast(full), full_len); + + g_fs_session.PrivatePath(base_path); + + if (UTF8ToUTF16(relative, &relative_utf16) != KErrNone) { + return SQLITE_ERROR; + } + + if (parse.Set(relative_utf16, &base_path, NULL) != KErrNone) { + return SQLITE_ERROR; + } + + TDesC full_utf16(parse.FullName()); + if (UTF16ToUTF8(relative_utf16, &full_utf8) != KErrNone) { + return SQLITE_ERROR; + } + + full_utf8.PtrZ(); + return SQLITE_OK; +} + +static int SymbianRandomness(sqlite3_vfs */*vfs*/, int buf_len, char *buffer) { + assert(buffer); + TInt64 seed = User::TickCount(); + for (TInt i = 0; i < buf_len; i++) { + buffer[i] = Math::Rand(seed) % 255; + } + return SQLITE_OK; +} + +static int SymbianSleep(sqlite3_vfs */*vfs*/, int microsec) { + User::After(microsec); + return SQLITE_OK; +} + +int SymbianCurrentTime(sqlite3_vfs */*vfs*/, double *now) { + _LIT(kEpoch, "19700101:000000.000000"); + assert(now); + TTime time; + TTime epoch_time(kEpoch); + TTimeIntervalSeconds interval; + + time.HomeTime(); + // calculate seconds elapsed since 1-1-1970 + time.SecondsFrom(epoch_time, interval); + + // Julian date @ 1-1-1970 = 2440587.5 + // seconds per day = 86400.0 + *now = interval.Int()/86400.0 + 2440587.5; + return SQLITE_OK; +} + +static int SymbianGetLastError(sqlite3_vfs */*vfs*/, + int /*buf_len*/, + char */*buf*/) { + assert(buf[0] == '\0'); + return 0; +} + +// Interfaces for opening a shared library, finding entry points +// within the shared library, and closing the shared library. +// TODO(marcogelmi): implement. +#define SymbianDlOpen 0 +#define SymbianDlError 0 +#define SymbianDlSym 0 +#define SymbianDlClose 0 + +// Initialize and deinitialize the operating system interface. +int sqlite3_os_init(void) { + static sqlite3_vfs symbian_vfs = { + 1, // iVersion + sizeof(SymbianFile), // szOsFile + KMaxPath, // mxPathname + 0, // pNext + "symbian", // name + 0, // pAppData + + SymbianOpen, // xOpen + SymbianDelete, // xDelete + SymbianAccess, // xAccess + SymbianFullPathname, // xFullPathname + SymbianDlOpen, // xDlOpen + SymbianDlError, // xDlError + SymbianDlSym, // xDlSym + SymbianDlClose, // xDlClose + SymbianRandomness, // xRandomness + SymbianSleep, // xSleep + SymbianCurrentTime, // xCurrentTime + SymbianGetLastError // xGetLastError + }; + + if (g_fs_session.Connect() != KErrNone) { + return SQLITE_ERROR; + } + + if (g_fs_session.ShareAuto() != KErrNone) { + g_fs_session.Close(); + return SQLITE_ERROR; + } + + sqlite3_vfs_register(&symbian_vfs, 1); + return SQLITE_OK; +} + +int sqlite3_os_end(void) { + g_fs_session.Close(); + return SQLITE_OK; +} + +#endif /* OS_SYMBIAN*/ Index: src/shell_icu_linux.c =================================================================== --- src/shell_icu_linux.c 1969-12-31 16:00:00.000000000 -0800 +++ src/shell_icu_linux.c 2009-09-17 13:48:49.000000000 -0700 @@ -0,0 +1,26 @@ +/* Copyright 2007 Google Inc. All Rights Reserved. +**/ + +#include +#include +#include "unicode/udata.h" + +/* +** This function attempts to load the ICU data tables from a data file. +** Returns 0 on failure, nonzero on success. +** This a hack job of icu_utils.cc:Initialize(). It's Chrome-specific code. +*/ +int sqlite_shell_init_icu() { + char bin_dir[PATH_MAX + 1]; + int bin_dir_size = readlink("/proc/self/exe", bin_dir, PATH_MAX); + if (bin_dir_size < 0 || bin_dir_size > PATH_MAX) + return 0; + bin_dir[bin_dir_size] = 0;; + + u_setDataDirectory(bin_dir); + // Only look for the packaged data file; + // the default behavior is to look for individual files. + UErrorCode err = U_ZERO_ERROR; + udata_setFileAccess(UDATA_ONLY_PACKAGES, &err); + return err == U_ZERO_ERROR; +} Index: src/shell_icu_win.c =================================================================== --- src/shell_icu_win.c 1969-12-31 16:00:00.000000000 -0800 +++ src/shell_icu_win.c 2009-09-09 12:29:11.000000000 -0700 @@ -0,0 +1,34 @@ +/* Copyright 2007 Google Inc. All Rights Reserved. +**/ + +#include +#include "unicode/udata.h" + +/* +** This function attempts to load the ICU data tables from a DLL. +** Returns 0 on failure, nonzero on success. +** This a hack job of icu_utils.cc:Initialize(). It's Chrome-specific code. +*/ + +#define ICU_DATA_SYMBOL "icudt" U_ICU_VERSION_SHORT "_dat" +int sqlite_shell_init_icu() { + HMODULE module; + FARPROC addr; + UErrorCode err; + + wchar_t dll_name[12]; + wsprintf(dll_name, L"icudt%2S.dll", U_ICU_VERSION_SHORT); + dll_name[11] = L'\0'; + module = LoadLibrary(dll_name); + if (!module) + return 0; + + addr = GetProcAddress(module, ICU_DATA_SYMBOL); + if (!addr) + return 0; + + err = U_ZERO_ERROR; + udata_setCommonData(addr, &err); + + return 1; +} Index: test/fts.test =================================================================== --- test/fts.test 1969-12-31 16:00:00.000000000 -0800 +++ test/fts.test 2009-07-01 12:08:39.000000000 -0700 @@ -0,0 +1,61 @@ +# +# 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 the fts tests. +# +# $Id$ + +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 + } + default { + set argv [linsert $argv 0 $arg] + break + } + } +} + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +rename finish_test really_finish_test +proc finish_test {} {} +set ISQUICK 1 + +set EXCLUDE { + fts.test + fts1.test + fts2.test +} + +if {[sqlite3 -has-codec]} { + # lappend EXCLUDE \ + # conflict.test +} + +foreach testfile [lsort -dictionary [glob $testdir/fts*.test]] { + set tail [file tail $testfile] + puts "test: $tail" + if {[lsearch -exact $EXCLUDE $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 + } +} +source $testdir/misuse.test + +set sqlite_open_file_count 0 +really_finish_test Index: test/fts1.test =================================================================== --- test/fts1.test 1969-12-31 16:00:00.000000000 -0800 +++ test/fts1.test 2009-07-01 12:08:39.000000000 -0700 @@ -0,0 +1,61 @@ +# +# 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 the fts tests. +# +# $Id$ + +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 + } + default { + set argv [linsert $argv 0 $arg] + break + } + } +} + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +rename finish_test really_finish_test +proc finish_test {} {} +set ISQUICK 1 + +set EXCLUDE { + fts.test + fts1.test + fts2.test +} + +if {[sqlite3 -has-codec]} { + # lappend EXCLUDE \ + # conflict.test +} + +foreach testfile [lsort -dictionary [glob $testdir/fts1*.test]] { + set tail [file tail $testfile] + puts "test: $tail" + if {[lsearch -exact $EXCLUDE $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 + } +} +source $testdir/misuse.test + +set sqlite_open_file_count 0 +really_finish_test