os/persistentdata/persistentstorage/sqlite3api/TEST/TclScript/lock.test
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
# 2001 September 15
sl@0
     2
#
sl@0
     3
# The author disclaims copyright to this source code.  In place of
sl@0
     4
# a legal notice, here is a blessing:
sl@0
     5
#
sl@0
     6
#    May you do good and not evil.
sl@0
     7
#    May you find forgiveness for yourself and forgive others.
sl@0
     8
#    May you share freely, never taking more than you give.
sl@0
     9
#
sl@0
    10
#***********************************************************************
sl@0
    11
# This file implements regression tests for SQLite library.  The
sl@0
    12
# focus of this script is database locks.
sl@0
    13
#
sl@0
    14
# $Id: lock.test,v 1.33 2006/08/16 16:42:48 drh Exp $
sl@0
    15
sl@0
    16
sl@0
    17
set testdir [file dirname $argv0]
sl@0
    18
source $testdir/tester.tcl
sl@0
    19
sl@0
    20
# Create an alternative connection to the database
sl@0
    21
#
sl@0
    22
do_test lock-1.0 {
sl@0
    23
  sqlite3 db2 ./test.db
sl@0
    24
  set dummy {}
sl@0
    25
} {}
sl@0
    26
do_test lock-1.1 {
sl@0
    27
  execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name}
sl@0
    28
} {}
sl@0
    29
do_test lock-1.2 {
sl@0
    30
  execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name} db2
sl@0
    31
} {}
sl@0
    32
do_test lock-1.3 {
sl@0
    33
  execsql {CREATE TABLE t1(a int, b int)}
sl@0
    34
  execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name}
sl@0
    35
} {t1}
sl@0
    36
do_test lock-1.5 {
sl@0
    37
  catchsql {
sl@0
    38
     SELECT name FROM sqlite_master WHERE type='table' ORDER BY name
sl@0
    39
  } db2
sl@0
    40
} {0 t1}
sl@0
    41
sl@0
    42
do_test lock-1.6 {
sl@0
    43
  execsql {INSERT INTO t1 VALUES(1,2)}
sl@0
    44
  execsql {SELECT * FROM t1}
sl@0
    45
} {1 2}
sl@0
    46
# Update: The schema is now brought up to date by test lock-1.5.
sl@0
    47
# do_test lock-1.7.1 {
sl@0
    48
#   catchsql {SELECT * FROM t1} db2
sl@0
    49
# } {1 {no such table: t1}}
sl@0
    50
do_test lock-1.7.2 {
sl@0
    51
  catchsql {SELECT * FROM t1} db2
sl@0
    52
} {0 {1 2}}
sl@0
    53
do_test lock-1.8 {
sl@0
    54
  execsql {UPDATE t1 SET a=b, b=a} db2
sl@0
    55
  execsql {SELECT * FROM t1} db2
sl@0
    56
} {2 1}
sl@0
    57
do_test lock-1.9 {
sl@0
    58
  execsql {SELECT * FROM t1}
sl@0
    59
} {2 1}
sl@0
    60
do_test lock-1.10 {
sl@0
    61
  execsql {BEGIN TRANSACTION}
sl@0
    62
  execsql {UPDATE t1 SET a = 0 WHERE 0}
sl@0
    63
  execsql {SELECT * FROM t1}
sl@0
    64
} {2 1}
sl@0
    65
do_test lock-1.11 {
sl@0
    66
  catchsql {SELECT * FROM t1} db2
sl@0
    67
} {0 {2 1}}
sl@0
    68
do_test lock-1.12 {
sl@0
    69
  execsql {ROLLBACK}
sl@0
    70
  catchsql {SELECT * FROM t1}
sl@0
    71
} {0 {2 1}}
sl@0
    72
sl@0
    73
do_test lock-1.13 {
sl@0
    74
  execsql {CREATE TABLE t2(x int, y int)}
sl@0
    75
  execsql {INSERT INTO t2 VALUES(8,9)}
sl@0
    76
  execsql {SELECT * FROM t2}
sl@0
    77
} {8 9}
sl@0
    78
do_test lock-1.14.1 {
sl@0
    79
  catchsql {SELECT * FROM t2} db2
sl@0
    80
} {1 {no such table: t2}}
sl@0
    81
do_test lock-1.14.2 {
sl@0
    82
  catchsql {SELECT * FROM t1} db2
sl@0
    83
} {0 {2 1}}
sl@0
    84
do_test lock-1.15 {
sl@0
    85
  catchsql {SELECT * FROM t2} db2
sl@0
    86
} {0 {8 9}}
sl@0
    87
sl@0
    88
do_test lock-1.16 {
sl@0
    89
  db eval {SELECT * FROM t1} qv {
sl@0
    90
    set x [db eval {SELECT * FROM t1}]
sl@0
    91
  }
sl@0
    92
  set x
sl@0
    93
} {2 1}
sl@0
    94
do_test lock-1.17 {
sl@0
    95
  db eval {SELECT * FROM t1} qv {
sl@0
    96
    set x [db eval {SELECT * FROM t2}]
sl@0
    97
  }
sl@0
    98
  set x
sl@0
    99
} {8 9}
sl@0
   100
sl@0
   101
# You cannot UPDATE a table from within the callback of a SELECT
sl@0
   102
# on that same table because the SELECT has the table locked.
sl@0
   103
#
sl@0
   104
# 2006-08-16:  Reads no longer block writes within the same
sl@0
   105
# database connection.
sl@0
   106
#
sl@0
   107
#do_test lock-1.18 {
sl@0
   108
#  db eval {SELECT * FROM t1} qv {
sl@0
   109
#    set r [catch {db eval {UPDATE t1 SET a=b, b=a}} msg]
sl@0
   110
#    lappend r $msg
sl@0
   111
#  }
sl@0
   112
#  set r
sl@0
   113
#} {1 {database table is locked}}
sl@0
   114
sl@0
   115
# But you can UPDATE a different table from the one that is used in
sl@0
   116
# the SELECT.
sl@0
   117
#
sl@0
   118
do_test lock-1.19 {
sl@0
   119
  db eval {SELECT * FROM t1} qv {
sl@0
   120
    set r [catch {db eval {UPDATE t2 SET x=y, y=x}} msg]
sl@0
   121
    lappend r $msg
sl@0
   122
  }
sl@0
   123
  set r
sl@0
   124
} {0 {}}
sl@0
   125
do_test lock-1.20 {
sl@0
   126
  execsql {SELECT * FROM t2}
sl@0
   127
} {9 8}
sl@0
   128
sl@0
   129
# It is possible to do a SELECT of the same table within the
sl@0
   130
# callback of another SELECT on that same table because two
sl@0
   131
# or more read-only cursors can be open at once.
sl@0
   132
#
sl@0
   133
do_test lock-1.21 {
sl@0
   134
  db eval {SELECT * FROM t1} qv {
sl@0
   135
    set r [catch {db eval {SELECT a FROM t1}} msg]
sl@0
   136
    lappend r $msg
sl@0
   137
  }
sl@0
   138
  set r
sl@0
   139
} {0 2}
sl@0
   140
sl@0
   141
# Under UNIX you can do two SELECTs at once with different database
sl@0
   142
# connections, because UNIX supports reader/writer locks.  Under windows,
sl@0
   143
# this is not possible.
sl@0
   144
#
sl@0
   145
if {$::tcl_platform(platform)=="unix"} {
sl@0
   146
  do_test lock-1.22 {
sl@0
   147
    db eval {SELECT * FROM t1} qv {
sl@0
   148
      set r [catch {db2 eval {SELECT a FROM t1}} msg]
sl@0
   149
      lappend r $msg
sl@0
   150
    }
sl@0
   151
    set r
sl@0
   152
  } {0 2}
sl@0
   153
}
sl@0
   154
integrity_check lock-1.23
sl@0
   155
sl@0
   156
# If one thread has a transaction another thread cannot start
sl@0
   157
# a transaction.  -> Not true in version 3.0.  But if one thread
sl@0
   158
# as a RESERVED lock another thread cannot acquire one.
sl@0
   159
#
sl@0
   160
do_test lock-2.1 {
sl@0
   161
  execsql {BEGIN TRANSACTION}
sl@0
   162
  execsql {UPDATE t1 SET a = 0 WHERE 0}
sl@0
   163
  execsql {BEGIN TRANSACTION} db2
sl@0
   164
  set r [catch {execsql {UPDATE t1 SET a = 0 WHERE 0} db2} msg]
sl@0
   165
  execsql {ROLLBACK} db2
sl@0
   166
  lappend r $msg
sl@0
   167
} {1 {database is locked}}
sl@0
   168
sl@0
   169
# A thread can read when another has a RESERVED lock.
sl@0
   170
#
sl@0
   171
do_test lock-2.2 {
sl@0
   172
  catchsql {SELECT * FROM t2} db2
sl@0
   173
} {0 {9 8}}
sl@0
   174
sl@0
   175
# If the other thread (the one that does not hold the transaction with
sl@0
   176
# a RESERVED lock) tries to get a RESERVED lock, we do get a busy callback
sl@0
   177
# as long as we were not orginally holding a READ lock.
sl@0
   178
#
sl@0
   179
do_test lock-2.3.1 {
sl@0
   180
  proc callback {count} {
sl@0
   181
    set ::callback_value $count
sl@0
   182
    break
sl@0
   183
  }
sl@0
   184
  set ::callback_value {}
sl@0
   185
  db2 busy callback
sl@0
   186
  # db2 does not hold a lock so we should get a busy callback here
sl@0
   187
  set r [catch {execsql {UPDATE t1 SET a=b, b=a} db2} msg]
sl@0
   188
  lappend r $msg
sl@0
   189
  lappend r $::callback_value
sl@0
   190
} {1 {database is locked} 0}
sl@0
   191
do_test lock-2.3.2 {
sl@0
   192
  set ::callback_value {}
sl@0
   193
  execsql {BEGIN; SELECT rowid FROM sqlite_master LIMIT 1} db2
sl@0
   194
  # This time db2 does hold a read lock.  No busy callback this time.
sl@0
   195
  set r [catch {execsql {UPDATE t1 SET a=b, b=a} db2} msg]
sl@0
   196
  lappend r $msg
sl@0
   197
  lappend r $::callback_value
sl@0
   198
} {1 {database is locked} {}}
sl@0
   199
catch {execsql {ROLLBACK} db2}
sl@0
   200
do_test lock-2.4.1 {
sl@0
   201
  proc callback {count} {
sl@0
   202
    lappend ::callback_value $count
sl@0
   203
    if {$count>4} break
sl@0
   204
  }
sl@0
   205
  set ::callback_value {}
sl@0
   206
  db2 busy callback
sl@0
   207
  # We get a busy callback because db2 is not holding a lock
sl@0
   208
  set r [catch {execsql {UPDATE t1 SET a=b, b=a} db2} msg]
sl@0
   209
  lappend r $msg
sl@0
   210
  lappend r $::callback_value
sl@0
   211
} {1 {database is locked} {0 1 2 3 4 5}}
sl@0
   212
do_test lock-2.4.2 {
sl@0
   213
  proc callback {count} {
sl@0
   214
    lappend ::callback_value $count
sl@0
   215
    if {$count>4} break
sl@0
   216
  }
sl@0
   217
  set ::callback_value {}
sl@0
   218
  db2 busy callback
sl@0
   219
  execsql {BEGIN; SELECT rowid FROM sqlite_master LIMIT 1} db2
sl@0
   220
  # No busy callback this time because we are holding a lock
sl@0
   221
  set r [catch {execsql {UPDATE t1 SET a=b, b=a} db2} msg]
sl@0
   222
  lappend r $msg
sl@0
   223
  lappend r $::callback_value
sl@0
   224
} {1 {database is locked} {}}
sl@0
   225
catch {execsql {ROLLBACK} db2}
sl@0
   226
do_test lock-2.5 {
sl@0
   227
  proc callback {count} {
sl@0
   228
    lappend ::callback_value $count
sl@0
   229
    if {$count>4} break
sl@0
   230
  }
sl@0
   231
  set ::callback_value {}
sl@0
   232
  db2 busy callback
sl@0
   233
  set r [catch {execsql {SELECT * FROM t1} db2} msg]
sl@0
   234
  lappend r $msg
sl@0
   235
  lappend r $::callback_value
sl@0
   236
} {0 {2 1} {}}
sl@0
   237
execsql {ROLLBACK}
sl@0
   238
sl@0
   239
# Test the built-in busy timeout handler
sl@0
   240
#
sl@0
   241
do_test lock-2.8 {
sl@0
   242
  db2 timeout 400
sl@0
   243
  execsql BEGIN
sl@0
   244
  execsql {UPDATE t1 SET a = 0 WHERE 0}
sl@0
   245
  catchsql {BEGIN EXCLUSIVE;} db2
sl@0
   246
} {1 {database is locked}}
sl@0
   247
do_test lock-2.9 {
sl@0
   248
  db2 timeout 0
sl@0
   249
  execsql COMMIT
sl@0
   250
} {}
sl@0
   251
integrity_check lock-2.10
sl@0
   252
sl@0
   253
# Try to start two transactions in a row
sl@0
   254
#
sl@0
   255
do_test lock-3.1 {
sl@0
   256
  execsql {BEGIN TRANSACTION}
sl@0
   257
  set r [catch {execsql {BEGIN TRANSACTION}} msg]
sl@0
   258
  execsql {ROLLBACK}
sl@0
   259
  lappend r $msg
sl@0
   260
} {1 {cannot start a transaction within a transaction}}
sl@0
   261
integrity_check lock-3.2
sl@0
   262
sl@0
   263
# Make sure the busy handler and error messages work when
sl@0
   264
# opening a new pointer to the database while another pointer
sl@0
   265
# has the database locked.
sl@0
   266
#
sl@0
   267
do_test lock-4.1 {
sl@0
   268
  db2 close
sl@0
   269
  catch {db eval ROLLBACK}
sl@0
   270
  db eval BEGIN
sl@0
   271
  db eval {UPDATE t1 SET a=0 WHERE 0}
sl@0
   272
  sqlite3 db2 ./test.db
sl@0
   273
  catchsql {UPDATE t1 SET a=0} db2
sl@0
   274
} {1 {database is locked}}
sl@0
   275
do_test lock-4.2 {
sl@0
   276
  set ::callback_value {}
sl@0
   277
  set rc [catch {db2 eval {UPDATE t1 SET a=0}} msg]
sl@0
   278
  lappend rc $msg $::callback_value
sl@0
   279
} {1 {database is locked} {}}
sl@0
   280
do_test lock-4.3 {
sl@0
   281
  proc callback {count} {
sl@0
   282
    lappend ::callback_value $count
sl@0
   283
    if {$count>4} break
sl@0
   284
  }
sl@0
   285
  db2 busy callback
sl@0
   286
  set rc [catch {db2 eval {UPDATE t1 SET a=0}} msg]
sl@0
   287
  lappend rc $msg $::callback_value
sl@0
   288
} {1 {database is locked} {0 1 2 3 4 5}}
sl@0
   289
execsql {ROLLBACK}
sl@0
   290
sl@0
   291
# When one thread is writing, other threads cannot read.  Except if the
sl@0
   292
# writing thread is writing to its temporary tables, the other threads
sl@0
   293
# can still read.  -> Not so in 3.0.  One thread can read while another
sl@0
   294
# holds a RESERVED lock.
sl@0
   295
#
sl@0
   296
proc tx_exec {sql} {
sl@0
   297
  db2 eval $sql
sl@0
   298
}
sl@0
   299
do_test lock-5.1 {
sl@0
   300
  execsql {
sl@0
   301
    SELECT * FROM t1
sl@0
   302
  }
sl@0
   303
} {2 1}
sl@0
   304
do_test lock-5.2 {
sl@0
   305
  db function tx_exec tx_exec
sl@0
   306
  catchsql {
sl@0
   307
    INSERT INTO t1(a,b) SELECT 3, tx_exec('SELECT y FROM t2 LIMIT 1');
sl@0
   308
  }
sl@0
   309
} {0 {}}
sl@0
   310
sl@0
   311
ifcapable tempdb {
sl@0
   312
  do_test lock-5.3 {
sl@0
   313
    execsql {
sl@0
   314
      CREATE TEMP TABLE t3(x);
sl@0
   315
      SELECT * FROM t3;
sl@0
   316
    }
sl@0
   317
  } {}
sl@0
   318
  do_test lock-5.4 {
sl@0
   319
    catchsql {
sl@0
   320
      INSERT INTO t3 SELECT tx_exec('SELECT y FROM t2 LIMIT 1');
sl@0
   321
    }
sl@0
   322
  } {0 {}}
sl@0
   323
  do_test lock-5.5 {
sl@0
   324
    execsql {
sl@0
   325
      SELECT * FROM t3;
sl@0
   326
    }
sl@0
   327
  } {8}
sl@0
   328
  do_test lock-5.6 {
sl@0
   329
    catchsql {
sl@0
   330
      UPDATE t1 SET a=tx_exec('SELECT x FROM t2');
sl@0
   331
    }
sl@0
   332
  } {0 {}}
sl@0
   333
  do_test lock-5.7 {
sl@0
   334
    execsql {
sl@0
   335
      SELECT * FROM t1;
sl@0
   336
    }
sl@0
   337
  } {9 1 9 8}
sl@0
   338
  do_test lock-5.8 {
sl@0
   339
    catchsql {
sl@0
   340
      UPDATE t3 SET x=tx_exec('SELECT x FROM t2');
sl@0
   341
    }
sl@0
   342
  } {0 {}}
sl@0
   343
  do_test lock-5.9 {
sl@0
   344
    execsql {
sl@0
   345
      SELECT * FROM t3;
sl@0
   346
    }
sl@0
   347
  } {9}
sl@0
   348
}
sl@0
   349
sl@0
   350
do_test lock-999.1 {
sl@0
   351
  rename db2 {}
sl@0
   352
} {}
sl@0
   353
sl@0
   354
finish_test