-C Pull\sin\sthe\sfix\sto\sSTAT2\sprocessing\sfrom\scheck-in\n[70a3d81742f].
-D 2011-02-20T21:03:04.537
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA1
+
+C Backport\sthe\sos_unix.c\serror\slogging\senhancements\sfrom\ncheck-in\s[01076528a43b61a].
+D 2011-02-23T14:05:08.407
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 4547616ad2286053af6ccccefa242dc925e49bf0
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
F src/os.h 9dbed8c2b9c1f2f2ebabc09e49829d4777c26bf9
F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f
F src/os_os2.c 72d0b2e562952a2464308c4ce5f7913ac10bef3e
-F src/os_unix.c 0240c5b547b4cf585c8cac351a95c3e85ce00772
+F src/os_unix.c c9f2a09124d78e2accd5738c78aabbccc07cb2f4
F src/os_win.c 2f90f7bdec714fad51cd31b4ecad3cc1b4bb5aad
F src/pager.c 5b2210b4307c626a3b3ed7312161ec533958c094
F src/pager.h 0ea59db2a33bc6c2c02cae34de33367e1effdf76
F test/notnull.test cc7c78340328e6112a13c3e311a9ab3127114347
F test/null.test a8b09b8ed87852742343b33441a9240022108993
F test/openv2.test af02ed0a9cbc0d2a61b8f35171d4d117e588e4ec
+F test/oserror.test 5775264a41039856d211168713d916949227fedd
F test/pager1.test e066fb2e2dc1ac1cd9ef2b44a28ae3cc79a9150f
F test/pager2.test 0fbb6b6dc40ce1fecfe758c555a748ad2e9beaa3
F test/pager3.test 3856d9c80839be0668efee1b74811b1b7f7fc95f
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P e2616004dfaf61d776e448693971b6478552a635
-R d8e085383636be2d77c988420d503189
+P 692aafb17e7fca4e303ca14da2925cb95a22f71e
+R 6770e6a4b417ada2ff6c98dd3dca2daa
U drh
-Z 0dcddd6d0b789a4a9ef8c5f0f596ab90
+Z 9c3c0b89eea505163f9778dd289c331f
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.4.6 (GNU/Linux)
+
+iD8DBQFNZRQXoxKgR168RlERAqTcAJ4i0CBz9MzbV5ibLtQ/BGYBaqlYuwCfXQoY
+oux3l0HUdLba9EsW1zRLA/k=
+=uIBr
+-----END PGP SIGNATURE-----
*/
static unixInodeInfo *inodeList = 0;
+/*
+**
+** This function - unixLogError_x(), is only ever called via the macro
+** unixLogError().
+**
+** It is invoked after an error occurs in an OS function and errno has been
+** set. It logs a message using sqlite3_log() containing the current value of
+** errno and, if possible, the human-readable equivalent from strerror() or
+** strerror_r().
+**
+** The first argument passed to the macro should be the error code that
+** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN).
+** The two subsequent arguments should be the name of the OS function that
+** failed (e.g. "unlink", "open") and the the associated file-system path,
+** if any.
+*/
+#define unixLogError(a,b,c) unixLogError_x(a,b,c,__LINE__)
+static int unixLogError_x(
+ int errcode, /* SQLite error code */
+ const char *zFunc, /* Name of OS function that failed */
+ const char *zPath, /* File path associated with error */
+ int iLine /* Source line number where error occurred */
+){
+ char *zErr; /* Message from strerror() or equivalent */
+
+ /* If this is not a threadsafe build (SQLITE_THREADSAFE==0), then use
+ ** the strerror() function to obtain the human-readable error message
+ ** equivalent to errno. Otherwise, use strerror_r().
+ */
+#if SQLITE_THREADSAFE && defined(HAVE_STRERROR_R)
+ char aErr[80];
+ memset(aErr, 0, sizeof(aErr));
+ zErr = aErr;
+
+ /* If STRERROR_R_CHAR_P (set by autoconf scripts) or __USE_GNU is defined,
+ ** assume that the system provides the the GNU version of strerror_r() that
+ ** returns a pointer to a buffer containing the error message. That pointer
+ ** may point to aErr[], or it may point to some static storage somewhere.
+ ** Otherwise, assume that the system provides the POSIX version of
+ ** strerror_r(), which always writes an error message into aErr[].
+ **
+ ** If the code incorrectly assumes that it is the POSIX version that is
+ ** available, the error message will often be an empty string. Not a
+ ** huge problem. Incorrectly concluding that the GNU version is available
+ ** could lead to a segfault though.
+ */
+#if defined(STRERROR_R_CHAR_P) || defined(__USE_GNU)
+ zErr =
+# endif
+ strerror_r(errno, aErr, sizeof(aErr)-1);
+
+#elif SQLITE_THREADSAFE
+ /* This is a threadsafe build, but strerror_r() is not available. */
+ zErr = "";
+#else
+ /* Non-threadsafe build, use strerror(). */
+ zErr = strerror(errno);
+#endif
+
+ assert( errcode!=SQLITE_OK );
+ sqlite3_log(errcode,
+ "os_unix.c: %s() at line %d - \"%s\" errno=%d path=%s",
+ zFunc, iLine, zErr, errno, (zPath ? zPath : "n/a")
+ );
+
+ return errcode;
+}
+
+
/*
** Close all file descriptors accumuated in the unixInodeInfo->pUnused list.
** If all such file descriptors are closed without error, the list is
pNext = p->pNext;
if( close(p->fd) ){
pFile->lastErrno = errno;
- rc = SQLITE_IOERR_CLOSE;
+ rc = unixLogError(SQLITE_IOERR_CLOSE, "close", pFile->zPath);
p->pNext = pError;
pError = p;
}else{
int err = close(pFile->dirfd);
if( err ){
pFile->lastErrno = errno;
- return SQLITE_IOERR_DIR_CLOSE;
+ return unixLogError(SQLITE_IOERR_DIR_CLOSE, "close", pFile->zPath);
}else{
pFile->dirfd=-1;
}
int err = close(pFile->h);
if( err ){
pFile->lastErrno = errno;
- return SQLITE_IOERR_CLOSE;
+ return unixLogError(SQLITE_IOERR_CLOSE, "close", pFile->zPath);
}
}
#if OS_VXWORKS
SimulateIOError( rc=1 );
if( rc ){
pFile->lastErrno = errno;
- return SQLITE_IOERR_FSYNC;
+ return unixLogError(SQLITE_IOERR_FSYNC, "full_fsync", pFile->zPath);
}
if( pFile->dirfd>=0 ){
int err;
pFile->dirfd = -1;
}else{
pFile->lastErrno = errno;
- rc = SQLITE_IOERR_DIR_CLOSE;
+ rc = unixLogError(SQLITE_IOERR_DIR_CLOSE, "close", pFile->zPath);
}
}
return rc;
rc = ftruncate(pFile->h, (off_t)nByte);
if( rc ){
pFile->lastErrno = errno;
- return SQLITE_IOERR_TRUNCATE;
+ return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
}else{
#ifndef NDEBUG
/* If we are doing a normal write to a database file (as opposed to
if( ftruncate(pFile->h, nSize) ){
pFile->lastErrno = errno;
- return SQLITE_IOERR_TRUNCATE;
+ return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
}
iWrite = ((buf.st_size + 2*nBlk - 1)/nBlk)*nBlk-1;
do {
pShmNode->h = open(zShmFilename, O_RDWR|O_CREAT, (sStat.st_mode & 0777));
if( pShmNode->h<0 ){
- rc = SQLITE_CANTOPEN_BKPT;
+ rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShmFilename);
goto shm_open_err;
}
rc = SQLITE_OK;
if( unixShmSystemLock(pShmNode, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){
if( ftruncate(pShmNode->h, 0) ){
- rc = SQLITE_IOERR_SHMOPEN;
+ rc = unixLogError(SQLITE_IOERR_SHMOPEN, "ftruncate", zShmFilename);
}
}
if( rc==SQLITE_OK ){
*/
if( !bExtend ) goto shmpage_out;
if( ftruncate(pShmNode->h, nByte) ){
- rc = SQLITE_IOERR_SHMSIZE;
+ rc = unixLogError(SQLITE_IOERR_SHMSIZE,"ftruncate",pShmNode->zFilename);
goto shmpage_out;
}
}
}
}
*pFd = fd;
- return (fd>=0?SQLITE_OK:SQLITE_CANTOPEN_BKPT);
+ return (fd>=0?SQLITE_OK:unixLogError(SQLITE_CANTOPEN_BKPT, "open", zDirname));
}
/*
fd = open(zName, openFlags, openMode);
}
if( fd<0 ){
- rc = SQLITE_CANTOPEN_BKPT;
+ rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName);
goto open_finished;
}
}
UNUSED_PARAMETER(NotUsed);
SimulateIOError(return SQLITE_IOERR_DELETE);
if( unlink(zPath)==(-1) && errno!=ENOENT ){
- return SQLITE_IOERR_DELETE;
+ return unixLogError(SQLITE_IOERR_DELETE, "unlink", zPath);
}
#ifndef SQLITE_DISABLE_DIRSYNC
if( dirSync ){
if( fsync(fd) )
#endif
{
- rc = SQLITE_IOERR_DIR_FSYNC;
+ rc = unixLogError(SQLITE_IOERR_DIR_FSYNC, "fsync", zPath);
}
if( close(fd)&&!rc ){
- rc = SQLITE_IOERR_DIR_CLOSE;
+ rc = unixLogError(SQLITE_IOERR_DIR_CLOSE, "close", zPath);
}
}
}
}else{
int nCwd;
if( getcwd(zOut, nOut-1)==0 ){
- return SQLITE_CANTOPEN_BKPT;
+ return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath);
}
nCwd = (int)strlen(zOut);
sqlite3_snprintf(nOut-nCwd, &zOut[nCwd], "/%s", zPath);
--- /dev/null
+# 2011 February 19
+#
+# 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 file is testing that error messages are logged via the
+# sqlite3_log() mechanism when certain errors are encountered in the
+# default unix or windows VFS modules.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+if {$::tcl_platform(platform)!="unix"} { finish_test ; return }
+set ::testprefix oserror
+
+db close
+sqlite3_shutdown
+test_sqlite3_log xLog
+proc xLog {error_code msg} {
+ if {[string match os_* $msg]} {
+ lappend ::log $msg
+ }
+}
+
+proc do_re_test {tn script expression} {
+ uplevel do_test $tn [list [subst -nocommands {
+ set res [eval { $script }]
+ if {[regexp {$expression} [set res]]} {
+ set {} {$expression}
+ } else {
+ set res
+ }
+ }]] [list $expression]
+
+}
+
+#--------------------------------------------------------------------------
+# Tests oserror-1.* test failures in the open() system call.
+#
+
+# Test a failure in open() due to too many files.
+#
+do_test 1.1.1 {
+ set ::log [list]
+ list [catch {
+ for {set i 0} {$i < 2000} {incr i} { sqlite3 dbh_$i test.db -readonly 1 }
+ } msg] $msg
+} {1 {unable to open database file}}
+do_test 1.1.2 {
+ catch { for {set i 0} {$i < 2000} {incr i} { dbh_$i close } }
+} {1}
+
+do_re_test 1.1.3 { lindex $::log 0 } {^os_unix.c: open.*test.db$}
+
+
+# Test a failure in open() due to the path being a directory.
+#
+do_test 1.2.1 {
+ file mkdir dir.db
+ set ::log [list]
+ list [catch { sqlite3 dbh dir.db } msg] $msg
+} {1 {unable to open database file}}
+
+do_re_test 1.2.2 { lindex $::log 0 } {^os_unix.c: open.*dir.db$}
+
+# Test a failure in open() due to the path not existing.
+#
+do_test 1.3.1 {
+ set ::log [list]
+ list [catch { sqlite3 dbh /x/y/z/test.db } msg] $msg
+} {1 {unable to open database file}}
+
+do_re_test 1.3.2 { lindex $::log 0 } {^os_unix.c: open.*test.db$}
+
+# Test a failure in open() due to the path not existing.
+#
+do_test 1.4.1 {
+ set ::log [list]
+ list [catch { sqlite3 dbh /root/test.db } msg] $msg
+} {1 {unable to open database file}}
+
+do_re_test 1.4.2 { lindex $::log 0 } {^os_unix.c: open.*test.db$}
+
+#--------------------------------------------------------------------------
+# Tests oserror-1.* test failures in the unlink() system call.
+#
+do_test 2.1.1 {
+ set ::log [list]
+ file mkdir test.db-wal
+ forcedelete test.db
+ sqlite3 dbh test.db
+ catchsql { SELECT * FROM sqlite_master } dbh
+} {1 {disk I/O error}}
+
+do_re_test 2.1.2 { lindex $::log 0 } {^os_unix.c: unlink.*test.db-wal$}
+do_test 2.1.3 {
+ dbh close
+ forcedelete test.db-wal
+} {}
+
+
+sqlite3_shutdown
+test_sqlite3_log
+sqlite3_initialize
+finish_test
+