On Wed, 1 Sep 2004, D. Richard Hipp wrote:
>Christian Smith wrote:
>> Created ticket #884, with patch against latest cvs:
>> http://www.sqlite.org/cvstrac/tktview?tn=884
>>
>
>I fear that your patch has been overcome by events.
>A subtle bug has been uncovered in another area
>of locking which is going to require reworking large
>sections of the commit/rollback logic. It is very
>doubtful that your patch will survive this rework.
No problem. As I said, it was mainly a RFC, for such things as the SQL
syntax. The implementation was broken anyway, just enough to get the
desired semantics in a single session. I was hoping it *wouldn't* go into
the release code as is:)
My patch was mainly at the parser/vdbe level. I've not got in to the
details of the btree code or where I could plug such read only transaction
functionality in, so I hacked it in around the vdbe. Hence my comments
earlier about it being broken.
Could more robust read only transaction support be done as part of this
work? In the meantime, I've attached the final patch I'll do for now, for
people to play with, as well as updated the now closed ticket 884.
>
> <snip bug>
>
Christian
--
/"\
\ / ASCII RIBBON CAMPAIGN - AGAINST HTML MAIL
X - AGAINST MS ATTACHMENTS
/ \
Index: src/build.c
===================================================================
RCS file: /sqlite/sqlite/src/build.c,v
retrieving revision 1.250
diff -c -p -r1.250 build.c
*** src/build.c 31 Aug 2004 13:45:11 -0000 1.250
--- src/build.c 1 Sep 2004 22:49:59 -0000
*************** void sqlite3FinishCoding(Parse *pParse){
*** 74,81 ****
int iDb;
sqlite3VdbeChangeP2(v, pParse->cookieGoto-1, sqlite3VdbeCurrentAddr(v));
for(iDb=0, mask=1; iDb<db->nDb; mask<<=1, iDb++){
if( (mask & pParse->cookieMask)==0 ) continue;
! sqlite3VdbeAddOp(v, OP_Transaction, iDb, (mask & pParse->writeMask)!=0);
sqlite3VdbeAddOp(v, OP_VerifyCookie, iDb, pParse->cookieValue[iDb]);
}
sqlite3VdbeAddOp(v, OP_Goto, 0, pParse->cookieGoto);
--- 74,83 ----
int iDb;
sqlite3VdbeChangeP2(v, pParse->cookieGoto-1, sqlite3VdbeCurrentAddr(v));
for(iDb=0, mask=1; iDb<db->nDb; mask<<=1, iDb++){
+ int wr;
if( (mask & pParse->cookieMask)==0 ) continue;
! wr = ( (mask & pParse->writeMask)!=0 && 0==db->roTrans );
! sqlite3VdbeAddOp(v, OP_Transaction, iDb, wr);
sqlite3VdbeAddOp(v, OP_VerifyCookie, iDb, pParse->cookieValue[iDb]);
}
sqlite3VdbeAddOp(v, OP_Goto, 0, pParse->cookieGoto);
*************** void sqlite3BeginTransaction(Parse *pPar
*** 2418,2423 ****
--- 2420,2441 ----
}
/*
+ ** Begin a read only transaction
+ */
+ void sqlite3BeginReadOnlyTransaction(Parse *pParse){
+ sqlite *db;
+ Vdbe *v;
+
+ if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
+ if( pParse->nErr || sqlite3_malloc_failed ) return;
+ if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0, 0) ) return;
+
+ v = sqlite3GetVdbe(pParse);
+ if( !v ) return;
+ sqlite3VdbeAddOp(v, OP_AutoCommit, -1, 0);
+ }
+
+ /*
** Commit a transaction
*/
void sqlite3CommitTransaction(Parse *pParse){
Index: src/parse.y
===================================================================
RCS file: /sqlite/sqlite/src/parse.y,v
retrieving revision 1.135
diff -c -p -r1.135 parse.y
*** src/parse.y 25 Aug 2004 04:07:02 -0000 1.135
--- src/parse.y 1 Sep 2004 22:49:59 -0000
*************** explain ::= . { sqlite3BeginPa
*** 82,87 ****
--- 82,88 ----
//
cmd ::= BEGIN trans_opt. {sqlite3BeginTransaction(pParse);}
+ cmd ::= BEGIN trans_opt FOR READ ONLY. {sqlite3BeginReadOnlyTransaction(pParse);}
trans_opt ::= .
trans_opt ::= TRANSACTION.
trans_opt ::= TRANSACTION nm.
Index: src/sqliteInt.h
===================================================================
RCS file: /sqlite/sqlite/src/sqliteInt.h,v
retrieving revision 1.318
diff -c -p -r1.318 sqliteInt.h
*** src/sqliteInt.h 1 Sep 2004 03:06:35 -0000 1.318
--- src/sqliteInt.h 1 Sep 2004 22:49:59 -0000
*************** struct sqlite {
*** 389,394 ****
--- 389,395 ----
int errCode; /* Most recent error code (SQLITE_*) */
u8 enc; /* Text encoding for this database. */
u8 autoCommit; /* The auto-commit flag. */
+ u8 roTrans; /* Read-only transaction in progress */
void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*);
void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*);
void *pCollNeededArg;
*************** void sqlite3Randomness(int, void*);
*** 1283,1288 ****
--- 1284,1290 ----
void sqlite3RollbackAll(sqlite*);
void sqlite3CodeVerifySchema(Parse*, int);
void sqlite3BeginTransaction(Parse*);
+ void sqlite3BeginReadOnlyTransaction(Parse*);
void sqlite3CommitTransaction(Parse*);
void sqlite3RollbackTransaction(Parse*);
int sqlite3ExprIsConstant(Expr*);
Index: src/tokenize.c
===================================================================
RCS file: /sqlite/sqlite/src/tokenize.c,v
retrieving revision 1.84
diff -c -p -r1.84 tokenize.c
*** src/tokenize.c 25 Aug 2004 04:07:02 -0000 1.84
--- src/tokenize.c 1 Sep 2004 22:49:59 -0000
*************** static Keyword aKeywordTable[] = {
*** 106,117 ****
--- 106,119 ----
{ "OF", TK_OF, },
{ "OFFSET", TK_OFFSET, },
{ "ON", TK_ON, },
+ { "ONLY", TK_ONLY, },
{ "OR", TK_OR, },
{ "ORDER", TK_ORDER, },
{ "OUTER", TK_JOIN_KW, },
{ "PRAGMA", TK_PRAGMA, },
{ "PRIMARY", TK_PRIMARY, },
{ "RAISE", TK_RAISE, },
+ { "READ", TK_READ, },
{ "REFERENCES", TK_REFERENCES, },
{ "REPLACE", TK_REPLACE, },
{ "RESTRICT", TK_RESTRICT, },
Index: src/vdbe.c
===================================================================
RCS file: /sqlite/sqlite/src/vdbe.c,v
retrieving revision 1.412
diff -c -p -r1.412 vdbe.c
*** src/vdbe.c 31 Aug 2004 13:45:12 -0000 1.412
--- src/vdbe.c 1 Sep 2004 22:50:00 -0000
*************** case OP_Statement: {
*** 2120,2126 ****
** VMs (apart from this one), then the COMMIT or ROLLBACK statement fails.
*/
case OP_AutoCommit: {
! u8 i = pOp->p1;
u8 rollback = pOp->p2;
assert( i==1 || i==0 );
--- 2120,2127 ----
** VMs (apart from this one), then the COMMIT or ROLLBACK statement fails.
*/
case OP_AutoCommit: {
! u8 i = pOp->p1 > 0;
! u8 ro = pOp->p1 < 0;
u8 rollback = pOp->p2;
assert( i==1 || i==0 );
*************** case OP_AutoCommit: {
*** 2138,2143 ****
--- 2139,2145 ----
rc = SQLITE_ERROR;
}else if( i!=db->autoCommit ){
db->autoCommit = i;
+ db->roTrans = ro;
p->autoCommitOn |= i;
if( pOp->p2 ){
sqlite3RollbackAll(db);
*************** case OP_OpenWrite: {
*** 2349,2354 ****
--- 2351,2360 ----
pX = db->aDb[iDb].pBt;
assert( pX!=0 );
wrFlag = pOp->opcode==OP_OpenWrite;
+ if ( wrFlag && db->roTrans ) {
+ rc = SQLITE_PERM;
+ break;
+ }
if( p2<=0 ){
assert( pTos>=p->aStack );
Integerify(pTos);
*************** case OP_IdxIsNull: {
*** 3609,3615 ****
** See also: Clear
*/
case OP_Destroy: {
! rc = sqlite3BtreeDropTable(db->aDb[pOp->p2].pBt, pOp->p1);
break;
}
--- 3615,3625 ----
** See also: Clear
*/
case OP_Destroy: {
! if ( db->roTrans ) {
! rc = SQLITE_PERM;
! } else {
! rc = sqlite3BtreeDropTable(db->aDb[pOp->p2].pBt, pOp->p1);
! }
break;
}
*************** case OP_Destroy: {
*** 3626,3632 ****
** See also: Destroy
*/
case OP_Clear: {
! rc = sqlite3BtreeClearTable(db->aDb[pOp->p2].pBt, pOp->p1);
break;
}
--- 3636,3646 ----
** See also: Destroy
*/
case OP_Clear: {
! if ( db->roTrans ) {
! rc = SQLITE_PERM;
! } else {
! rc = sqlite3BtreeClearTable(db->aDb[pOp->p2].pBt, pOp->p1);
! }
break;
}
Index: src/vdbeaux.c
===================================================================
RCS file: /sqlite/sqlite/src/vdbeaux.c,v
retrieving revision 1.138
diff -c -p -r1.138 vdbeaux.c
*** src/vdbeaux.c 21 Aug 2004 17:54:45 -0000 1.138
--- src/vdbeaux.c 1 Sep 2004 22:50:00 -0000
*************** static int vdbeCommit(sqlite *db){
*** 936,941 ****
--- 936,943 ----
}
}
+ assert( needXcommit || 0==db->roTrans );
+
/* If there are any write-transactions at all, invoke the commit hook */
if( needXcommit && db->xCommitCallback ){
if( db->xCommitCallback(db->pCommitArg) ){
*************** static int vdbeCommit(sqlite *db){
*** 1100,1105 ****
--- 1102,1109 ----
}
}
+ db->roTrans = 0;
+
return rc;
}