Hi,

When SQLite fails to create a file it tries reopening readonly and only if that 
fails too it logs the error.
However by that time the original error (for file creation) is lost.

Testcase:

$ cat >testcase.sh <<END
mkdir /tmp/foo && sqlite3 /tmp/foo/x.db <<EOF
pragma journal_mode=wal;
create table x(x int);
EOF
chmod -w /tmp/foo
gcc sqlite3.c testcase.c -ldl -DSQLITE_THREADSAFE=0 -o testcase
strace -e open ./testcase /tmp/foo/x.db
END

$ cat >testcase.c <<EOF
#include <sqlite3.h>
#include <stdio.h>

static void qlog(void *parg, int errcode, const char *msg)
{
    fprintf(stderr,"SQLite error %x: %s\n", errcode, msg);
}

int main(int argc, char *argv[])
{
    const char *path = argv[1];
    sqlite3 *handle = NULL;
    int ret = 0;
    char *errmsg = NULL;

    if (argc != 2) {
        fprintf(stderr,"Usage: %s </path/to/db>\n", argv[0]);
        return 1;
    }

    sqlite3_config(SQLITE_CONFIG_LOG, qlog, NULL);
    if (sqlite3_open_v2(path, &handle, SQLITE_OPEN_READWRITE, NULL)) {
        fprintf(stderr, "Failed to open database: %s\n", 
sqlite3_errmsg(handle));
        ret = 2;
    } else if (sqlite3_exec(handle, "PRAGMA synchronous = NORMAL", NULL, NULL, 
&errmsg)) {
        fprintf(stderr, "exec failed: %s\n", errmsg);
        sqlite3_free(errmsg);
        ret = 3;
    }
    sqlite3_close(handle);
    return ret;
}
EOF

$ sh testcase.sh
wal
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
open("/lib/x86_64-linux-gnu/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
open("/tmp/foo/x.db", O_RDWR|O_CLOEXEC) = 3
open("/tmp/foo/x.db-wal", O_RDWR|O_CREAT|O_CLOEXEC, 0644) = -1 EACCES 
(Permission denied)
open("/tmp/foo/x.db-wal", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or 
directory)
SQLite error e: cannot open file at line 30945 of [f73337e3e2]
SQLite error e: os_unix.c:30945: (2) open(/tmp/foo/x.db-wal) - No such file or 
directory
SQLite error e: unable to open database file
exec failed: unable to open database file
+++ exited with 3 +++


Would it be possible to save the errno when 1st robust_open fails, and report 
both errno when the 2nd open fails here?

 fd = robust_open(zName, openFlags, openMode);
    OSTRACE(("OPENX   %-3d %s 0%o\n", fd, zName, openFlags));
    if( fd<0 && errno!=EISDIR && isReadWrite && !isExclusive ){
      /* Failed to open the file for read/write access. Try read-only. */
      flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
      openFlags &= ~(O_RDWR|O_CREAT);
      flags |= SQLITE_OPEN_READONLY;
      openFlags |= O_RDONLY;
      isReadonly = 1;
      fd = robust_open(zName, openFlags, openMode);
    }
    if( fd<0 ){
      rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName);
      goto open_finished;
    }

Best regards,
--Edwin

Reply via email to