Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix handling of attempts to modify the database schema, application_id or user_version within an UNLOCKED transaction. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | begin-concurrent |
Files: | files | file ages | folders |
SHA1: |
5b9f272113d21fd606903509d6f830fe |
User & Date: | dan 2015-08-24 19:08:10.037 |
Context
2015-08-24
| ||
19:56 | Change "BEGIN UNLOCKED" to "BEGIN CONCURRENT". (check-in: ba1ab858e2 user: dan tags: begin-concurrent) | |
19:08 | Fix handling of attempts to modify the database schema, application_id or user_version within an UNLOCKED transaction. (check-in: 5b9f272113 user: dan tags: begin-concurrent) | |
16:00 | Fix compilation without SQLITE_ENABLE_UNLOCKED. Also other code organization issues. (check-in: 0411355754 user: dan tags: begin-concurrent) | |
Changes
Changes to src/vdbe.c.
︙ | |||
3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 | 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 | + + + + + + + + + + + - - - - - - - - - + + + + - | assert( DbMaskTest(p->btreeMask, pOp->p1) ); assert( p->readOnly==0 ); pDb = &db->aDb[pOp->p1]; assert( pDb->pBt!=0 ); assert( sqlite3SchemaMutexHeld(db, pOp->p1, 0) ); pIn3 = &aMem[pOp->p3]; sqlite3VdbeMemIntegerify(pIn3); #ifdef SQLITE_ENABLE_UNLOCKED if( db->bUnlocked && (pOp->p2==BTREE_USER_VERSION || pOp->p2==BTREE_APPLICATION_ID) ){ rc = SQLITE_ERROR; sqlite3VdbeError(p, "cannot modify %s within UNLOCKED transaction", pOp->p2==BTREE_USER_VERSION ? "user_version" : "application_id" ); break; } #endif /* See note about index shifting on OP_ReadCookie */ rc = sqlite3BtreeUpdateMeta(pDb->pBt, pOp->p2, (int)pIn3->u.i); if( pOp->p2==BTREE_SCHEMA_VERSION ){ |
︙ | |||
6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 | 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 | + + + + + + + + + | ** P2 contains the root-page of the table to lock. ** ** P4 contains a pointer to the name of the table being locked. This is only ** used to generate an error message if the lock cannot be obtained. */ case OP_TableLock: { u8 isWriteLock = (u8)pOp->p3; #ifdef SQLITE_ENABLE_UNLOCKED if( isWriteLock && db->bUnlocked && pOp->p2==1 ){ rc = SQLITE_ERROR; sqlite3VdbeError(p, "cannot modify database schema within UNLOCKED transaction"); rc = SQLITE_ERROR; break; } #endif if( isWriteLock || 0==(db->flags&SQLITE_ReadUncommitted) ){ int p1 = pOp->p1; assert( p1>=0 && p1<db->nDb ); assert( DbMaskTest(p->btreeMask, p1) ); assert( isWriteLock==0 || isWriteLock==1 ); rc = sqlite3BtreeLockTable(db->aDb[p1].pBt, pOp->p2, isWriteLock); if( (rc&0xFF)==SQLITE_LOCKED ){ |
︙ |
Changes to src/wal.c.
︙ | |||
1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 | 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + - - - - + - - - - - - - - - - - - - - - - - + - - - - - - - | } WALTRACE(("WAL%p: closed\n", pWal)); sqlite3_free((void *)pWal->apWiData); sqlite3_free(pWal); } return rc; } /* ** Try to copy the wal-index header from shared-memory into (*pHdr). Return ** zero if successful or non-zero otherwise. If the header is corrupted ** (either because the two copies are inconsistent or because the checksum ** values are incorrect), the read fails and non-zero is returned. */ static int walIndexLoadHdr(Wal *pWal, WalIndexHdr *pHdr){ u32 aCksum[2]; /* Checksum on the header content */ WalIndexHdr h2; /* Second copy of the header content */ WalIndexHdr volatile *aHdr; /* Header in shared memory */ /* The first page of the wal-index must be mapped at this point. */ assert( pWal->nWiData>0 && pWal->apWiData[0] ); /* Read the header. This might happen concurrently with a write to the ** same area of shared memory on a different CPU in a SMP, ** meaning it is possible that an inconsistent snapshot is read ** from the file. If this happens, return non-zero. ** ** There are two copies of the header at the beginning of the wal-index. ** When reading, read [0] first then [1]. Writes are in the reverse order. ** Memory barriers are used to prevent the compiler or the hardware from ** reordering the reads and writes. */ aHdr = walIndexHdr(pWal); memcpy(pHdr, (void *)&aHdr[0], sizeof(h2)); walShmBarrier(pWal); memcpy(&h2, (void *)&aHdr[1], sizeof(h2)); if( memcmp(&h2, pHdr, sizeof(h2))!=0 ){ return 1; /* Dirty read */ } if( h2.isInit==0 ){ return 1; /* Malformed header - probably all zeros */ } walChecksumBytes(1, (u8*)&h2, sizeof(h2)-sizeof(h2.aCksum), 0, aCksum); if( aCksum[0]!=h2.aCksum[0] || aCksum[1]!=h2.aCksum[1] ){ return 1; /* Checksum does not match */ } return 0; } /* ** Try to read the wal-index header. Return 0 on success and 1 if ** there is a problem. ** ** The wal-index is in shared memory. Another thread or process might ** be writing the header at the same time this procedure is trying to ** read it, which might result in inconsistency. A dirty read is detected ** by verifying that both copies of the header are the same and also by ** a checksum on the header. ** ** If and only if the read is consistent and the header is different from ** pWal->hdr, then pWal->hdr is updated to the content of the new header ** and *pChanged is set to 1. ** ** If the checksum cannot be verified return non-zero. If the header ** is read successfully and the checksum verified, return zero. */ static int walIndexTryHdr(Wal *pWal, int *pChanged){ |
︙ | |||
2632 2633 2634 2635 2636 2637 2638 | 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 | - - + - - - + + + + + + + - + - + - + | ** a) None of the pages in pList have been modified since the ** transaction opened, and ** ** b) The database schema cookie has not been modified since the ** transaction was started. */ if( rc==SQLITE_OK ){ |
︙ |
Changes to test/unlocked.test.
︙ | |||
106 107 108 109 110 111 112 113 114 115 116 | 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | + + + - + + + + + + - + | #------------------------------------------------------------------------- # UNLOCKED transactions may not modify the db schema. # foreach {tn sql} { 1 { CREATE TABLE xx(a, b) } 2 { DROP TABLE t1 } 3 { CREATE INDEX i1 ON t1(a) } 4 { CREATE VIEW v1 AS SELECT * FROM t1 } 5 { CREATE TEMP TABLE xx(a, b) } } { do_catchsql_test 1.7.$tn.1 " BEGIN UNLOCKED; $sql |
︙ | |||
404 405 406 407 408 409 410 | 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 | + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | do_test 2.$tn.7.3 { list [catch { sql1 { COMMIT } } msg] $msg [sqlite3_errcode db] } {0 {} SQLITE_OK} do_test 2.$tn.7.4 { sql3 { PRAGMA integrity_check } } ok } #------------------------------------------------------------------------- # Unlocked transactions may not modify the user_version or application_id. |