SQLite

Check-in [0fb6d91cea]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Allow "BEGIN CONCURRENT" transactions to modify the temp schema.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | begin-concurrent
Files: files | file ages | folders
SHA3-256: 0fb6d91cea347384fc081ce4c79582b365801dd4f56f5bf2ed40922bbfca0344
User & Date: dan 2017-11-06 10:04:45.041
Context
2017-11-06
20:02
Merge latest trunk changes into this branch. (check-in: 7f217edab4 user: dan tags: begin-concurrent)
10:04
Allow "BEGIN CONCURRENT" transactions to modify the temp schema. (check-in: 0fb6d91cea user: dan tags: begin-concurrent)
2017-09-22
11:09
Cherrypick [ec37ad6d08] into this branch. With this patch, if SQLITE_SHARED_MAPPING is defined at build-time SQLite will use a single memory mapping for multiple connections to the same database file within a single process. (check-in: c7a5880d6d user: dan tags: begin-concurrent)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/vdbe.c.
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
    goto abort_due_to_error;
  }
#endif
  /* See note about index shifting on OP_ReadCookie */
  rc = sqlite3BtreeUpdateMeta(pDb->pBt, pOp->p2, pOp->p3);
  if( pOp->p2==BTREE_SCHEMA_VERSION ){
    /* When the schema cookie changes, record the new cookie internally */
    assert( db->bConcurrent==0 );
    pDb->pSchema->schema_cookie = pOp->p3;
    db->mDbFlags |= DBFLAG_SchemaChange;
  }else if( pOp->p2==BTREE_FILE_FORMAT ){
    /* Record changes in the file format */
    pDb->pSchema->file_format = pOp->p3;
  }
  if( pOp->p1==1 ){







|







3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
    goto abort_due_to_error;
  }
#endif
  /* See note about index shifting on OP_ReadCookie */
  rc = sqlite3BtreeUpdateMeta(pDb->pBt, pOp->p2, pOp->p3);
  if( pOp->p2==BTREE_SCHEMA_VERSION ){
    /* When the schema cookie changes, record the new cookie internally */
    assert( pOp->p1==1 || db->bConcurrent==0 );
    pDb->pSchema->schema_cookie = pOp->p3;
    db->mDbFlags |= DBFLAG_SchemaChange;
  }else if( pOp->p2==BTREE_FILE_FORMAT ){
    /* Record changes in the file format */
    pDb->pSchema->file_format = pOp->p3;
  }
  if( pOp->p1==1 ){
6505
6506
6507
6508
6509
6510
6511
6512
6513
6514
6515
6516
6517
6518
6519
**
** 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;
#ifndef SQLITE_OMIT_CONCURRENT
  if( isWriteLock && db->bConcurrent && pOp->p2==1 ){
    rc = SQLITE_ERROR;
    sqlite3VdbeError(p, 
        "cannot modify database schema within CONCURRENT transaction");
    goto abort_due_to_error;
  }
#endif
  if( isWriteLock || 0==(db->flags&SQLITE_ReadUncommit) ){







|







6505
6506
6507
6508
6509
6510
6511
6512
6513
6514
6515
6516
6517
6518
6519
**
** 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;
#ifndef SQLITE_OMIT_CONCURRENT
  if( isWriteLock && db->bConcurrent && pOp->p2==1 && pOp->p1!=1 ){
    rc = SQLITE_ERROR;
    sqlite3VdbeError(p, 
        "cannot modify database schema within CONCURRENT transaction");
    goto abort_due_to_error;
  }
#endif
  if( isWriteLock || 0==(db->flags&SQLITE_ReadUncommit) ){
Changes to test/concurrent.test.
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
# CONCURRENT 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 CONCURRENT;
    $sql
  " {1 {cannot modify database schema within CONCURRENT transaction}}

  do_execsql_test 1.7.$tn.2 {
    SELECT sql FROM sqlite_master;
    SELECT sql FROM sqlite_temp_master;
  } {{CREATE TABLE t1(a, b)}}






















  do_execsql_test 1.7.$tn.3 COMMIT








}

#-------------------------------------------------------------------------
# If an auto-vacuum database is written within an CONCURRENT transaction, it
# is handled in the same way as for a non-CONCURRENT transaction.
#
reset_db







<

|




|




>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>







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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# CONCURRENT 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 }

} {
  do_catchsql_test 1.7.0.$tn.1 "
    BEGIN CONCURRENT;
    $sql
  " {1 {cannot modify database schema within CONCURRENT transaction}}

  do_execsql_test 1.7.0.$tn.2 {
    SELECT sql FROM sqlite_master;
    SELECT sql FROM sqlite_temp_master;
  } {{CREATE TABLE t1(a, b)}}

  do_execsql_test 1.7.0.$tn.3 COMMIT
}

# Except the temp db schema.
foreach {tn sql} {
  1 { CREATE TEMP TABLE xx(a, b) }
  2 { DROP TABLE xx }
  3 { CREATE TEMP TABLE yy(a, b) }
  4 { CREATE VIEW temp.v1 AS SELECT * FROM t1 }
  5 { CREATE INDEX yyi1 ON yy(a); }
  6 { CREATE TABLE temp.zz(a, b) }
} {
  do_catchsql_test 1.7.1.$tn.1 "
    BEGIN CONCURRENT;
    $sql
  " {0 {}}

  do_execsql_test 1.7.1.$tn.2 COMMIT
}


do_execsql_test 1.7.1.x {
  SELECT sql FROM sqlite_master;
  SELECT sql FROM sqlite_temp_master;
} {
  {CREATE TABLE t1(a, b)}
  {CREATE TABLE yy(a, b)} 
  {CREATE VIEW v1 AS SELECT * FROM t1} 
  {CREATE INDEX yyi1 ON yy(a)} 
  {CREATE TABLE zz(a, b)}
}

#-------------------------------------------------------------------------
# If an auto-vacuum database is written within an CONCURRENT transaction, it
# is handled in the same way as for a non-CONCURRENT transaction.
#
reset_db