# # # patch "ChangeLog" # from [5936f83fd67862dfb87abb0de129240ebe96b00d] # to [23e8ec657c8562daf5420597f6674400be498e54] # # patch "database.cc" # from [7424f331f0f71d7b0c04a1701734db8d68711294] # to [b29f1d375abb09db0ec39e2190a28051bb0b086b] # # patch "sqlite/btree.c" # from [e7d1694ad0844918e20b802a249533789bf811dc] # to [3d1fd3a87683ecd195c72f757faf3fbb960b2f29] # # patch "sqlite/pager.c" # from [48296c371c44bf43f1c02e221142149797f33072] # to [1e9580475b4a858a923930473d59263067bf4bfc] # # patch "tests/fail_cleanly_on_unreadable_db/__driver__.lua" # from [813cc5983532111581d06fbb05eca58e34a63524] # to [62b282400e59896964a7b32e123b14c68971b71b] # ============================================================ --- ChangeLog 5936f83fd67862dfb87abb0de129240ebe96b00d +++ ChangeLog 23e8ec657c8562daf5420597f6674400be498e54 @@ -1,5 +1,12 @@ 2007-01-13 Zack Weinberg + * sqlite/pager.c, sqlite/btree.c: Apply upstream change #3563 - + fixes crash when db is writable but directory isn't. + * database.cc (assert_sqlite_ok): Give helpful additional message + for more sqlite error codes. + * tests/fail_cleanly_on_unreadable_db: Test unwritable db, + unwritable directory, and -r+wx directory too. + * schema_migration.cc (logged_sqlite3_prepare, report_sqlite_error) (logged_sqlite3_exec_int, sqlite3_column_string): New functions. (logged_sqlite3_exec, calculate_schema_id) ============================================================ --- database.cc 7424f331f0f71d7b0c04a1701734db8d68711294 +++ database.cc b29f1d375abb09db0ec39e2190a28051bb0b086b @@ -266,13 +266,21 @@ assert_sqlite3_ok(sqlite3 *s) // sometimes sqlite is not very helpful // so we keep a table of errors people have gotten and more helpful versions - // note: if you update this, try to keep calculate_schema_id() in + // note: if you update this, try to keep the similar function in // schema_migration.cc consistent. - string auxiliary_message = ""; - if (errcode == SQLITE_ERROR) + const char * auxiliary_message = ""; + switch (errcode) { - auxiliary_message += _("make sure database and containing directory are writeable\n" - "and you have not run out of disk space"); + case SQLITE_ERROR: + case SQLITE_IOERR: + case SQLITE_CANTOPEN: + case SQLITE_PROTOCOL: + auxiliary_message + = _("make sure database and containing directory are writeable\n" + "and you have not run out of disk space"); + break; + default: + break; } // if the last message is empty, the \n will be stripped off too E(false, F("sqlite error: %s\n%s") % errmsg % auxiliary_message); ============================================================ --- sqlite/btree.c e7d1694ad0844918e20b802a249533789bf811dc +++ sqlite/btree.c 3d1fd3a87683ecd195c72f757faf3fbb960b2f29 @@ -1931,13 +1931,15 @@ static void unlockBtreeIfUnused(BtShared */ static void unlockBtreeIfUnused(BtShared *pBt){ if( pBt->inTransaction==TRANS_NONE && pBt->pCursor==0 && pBt->pPage1!=0 ){ - if( pBt->pPage1->aData==0 ){ - MemPage *pPage = pBt->pPage1; - pPage->aData = &((u8*)pPage)[-pBt->pageSize]; - pPage->pBt = pBt; - pPage->pgno = 1; + if( sqlite3pager_refcount(pBt->pPager)>=1 ){ + if( pBt->pPage1->aData==0 ){ + MemPage *pPage = pBt->pPage1; + pPage->aData = &((u8*)pPage)[-pBt->pageSize]; + pPage->pBt = pBt; + pPage->pgno = 1; + } + releasePage(pBt->pPage1); } - releasePage(pBt->pPage1); pBt->pPage1 = 0; pBt->inStmt = 0; } @@ -6424,7 +6426,6 @@ int sqlite3BtreeCopyFile(Btree *pTo, Btr rc = sqlite3pager_get(pBtFrom->pPager, i, &pPage); if( rc ) break; rc = sqlite3pager_overwrite(pBtTo->pPager, i, pPage); - if( rc ) break; sqlite3pager_unref(pPage); } for(i=nPage+1; rc==SQLITE_OK && i<=nToPage; i++){ ============================================================ --- sqlite/pager.c 48296c371c44bf43f1c02e221142149797f33072 +++ sqlite/pager.c 1e9580475b4a858a923930473d59263067bf4bfc @@ -379,8 +379,8 @@ static const unsigned char aJournalMagic static int cnt = 0; if( !pager3_refinfo_enable ) return; sqlite3DebugPrintf( - "REFCNT: %4d addr=%p nRef=%d\n", - p->pgno, PGHDR_TO_DATA(p), p->nRef + "REFCNT: %4d addr=%p nRef=%-3d total=%d\n", + p->pgno, PGHDR_TO_DATA(p), p->nRef, p->pPager->nRef ); cnt++; /* Something to set a breakpoint on */ } ============================================================ --- tests/fail_cleanly_on_unreadable_db/__driver__.lua 813cc5983532111581d06fbb05eca58e34a63524 +++ tests/fail_cleanly_on_unreadable_db/__driver__.lua 62b282400e59896964a7b32e123b14c68971b71b @@ -6,7 +6,7 @@ addfile("testfile", "blah blah") addfile("testfile", "blah blah") -- unreadable file -check({"chmod", "a-rwx", "test.db"}) +check({"chmod", "a-rw", "test.db"}) check(mtn(), 2, false, false) check(mtn("ls", "branches"), 1, false, false) check(mtn("db", "info"), 1, false, false) @@ -14,8 +14,19 @@ check(mtn("db", "load"), 1, false, false check(mtn("db", "migrate"), 1, false, false) check(mtn("commit", "-mfoo"), 1, false, false) check(mtn("db", "load"), 1, false, false) -check({"chmod", "a+rwx", "test.db"}) +check({"chmod", "a+rw", "test.db"}) +-- unwritable file (read-only operations succeed) +check({"chmod", "a-w", "test.db"}) +check(mtn(), 2, false, false) +check(mtn("ls", "branches"), 0, false, false) +check(mtn("db", "info"), 0, false, false) +check(mtn("db", "version"), 0, false, false) +check(mtn("db", "migrate"), 1, false, false) +check(mtn("commit", "-mfoo"), 1, false, false) +check(mtn("db", "load"), 1, false, false) +check({"chmod", "a+w", "test.db"}) + mkdir("subdir") check(mtn("--db=subdir/foo.db", "db", "init"), 0, false, false) @@ -26,6 +37,28 @@ check(mtn("--db=subdir/foo.db", "db", "m check(mtn("--db=subdir/foo.db", "db", "info"), 1, false, false) check(mtn("--db=subdir/foo.db", "db", "version"), 1, false, false) check(mtn("--db=subdir/foo.db", "db", "migrate"), 1, false, false) -check(mtn("--db=subdir/foo.db", "db", "load"), 1, false, false) -check(mtn("--db=subdir/bar.db", "db", "init"), 1, false, false) +check(mtn("--db=subdir/bar.db", "db", "load"), 1, false, false) +check(mtn("--db=subdir/baz.db", "db", "init"), 1, false, false) check({"chmod", "a+rwx", "subdir"}) + +-- unwritable directory (read-only operations succeed) +check({"chmod", "a-w", "subdir"}) +check(mtn("--db=subdir/foo.db"), 2, false, false) +check(mtn("--db=subdir/foo.db", "ls", "branches"), 0, false, false) +check(mtn("--db=subdir/foo.db", "db", "info"), 0, false, false) +check(mtn("--db=subdir/foo.db", "db", "version"), 0, false, false) +check(mtn("--db=subdir/foo.db", "db", "migrate"), 1, false, false) +check(mtn("--db=subdir/bar.db", "db", "load"), 1, false, false) +check(mtn("--db=subdir/baz.db", "db", "init"), 1, false, false) +check({"chmod", "a+w", "subdir"}) + +-- search-only directory (-r, +x) (all operations succeed) +check({"chmod", "a-r", "subdir"}) +check(mtn("--db=subdir/foo.db"), 2, false, false) +check(mtn("--db=subdir/foo.db", "ls", "branches"), 0, false, false) +check(mtn("--db=subdir/foo.db", "db", "info"), 0, false, false) +check(mtn("--db=subdir/foo.db", "db", "version"), 0, false, false) +check(mtn("--db=subdir/foo.db", "db", "migrate"), 0, false, false) +check(mtn("--db=subdir/bar.db", "db", "load"), 0, false, false) +check(mtn("--db=subdir/baz.db", "db", "init"), 0, false, false) +check({"chmod", "a+r", "subdir"})