summaryrefslogtreecommitdiffstats
path: root/test/fts3shared.test
blob: 0943c0510fcb6300b2be9bcbfd56c64c8c40c143 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
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
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
#
# 2010 September 17
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is the interactions between the FTS3/4 module 
# and shared-cache mode.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl

ifcapable !fts3||!shared_cache {
  finish_test
  return
}
set ::testprefix fts3shared

db close
set ::enable_shared_cache [sqlite3_enable_shared_cache 1]

# Open two connections to the database in shared-cache mode.
#
sqlite3 db test.db
sqlite3 db2 test.db

# Create a virtual FTS3 table. Populate it with some initial data.
#
do_execsql_test fts3shared-1.1 {
  CREATE VIRTUAL TABLE t1 USING fts3(x);
  BEGIN;
  INSERT INTO t1 VALUES('We listened and looked sideways up!');
  INSERT INTO t1 VALUES('Fear at my heart, as at a cup,');
  INSERT INTO t1 VALUES('My life-blood seemed to sip!');
  INSERT INTO t1 VALUES('The stars were dim, and thick the night');
  COMMIT;
} {}

# Open a write transaction and insert rows into the FTS3 table. This takes
# a write-lock on the underlying t1_content table.
#
do_execsql_test fts3shared-1.2 {
  BEGIN;
    INSERT INTO t1 VALUES('The steersman''s face by his lamp gleamed white;');
} {}

# Now try a SELECT on the full-text table. This particular SELECT does not
# read data from the %_content table. But it still attempts to obtain a lock
# on that table and so the SELECT fails.
#
do_test fts3shared-1.3 {
  catchsql {  
    BEGIN;
      SELECT rowid FROM t1 WHERE t1 MATCH 'stars' 
  } db2
} {1 {database table is locked}}

# Verify that the first connection can commit its transaction.
#
do_test fts3shared-1.4 { sqlite3_get_autocommit db } 0
do_execsql_test fts3shared-1.5 { COMMIT } {}
do_test fts3shared-1.6 { sqlite3_get_autocommit db } 1

# Verify that the second connection still has an open transaction.
#
do_test fts3shared-1.6 { sqlite3_get_autocommit db2 } 0

db close
db2 close

#-------------------------------------------------------------------------
# The following tests - fts3shared-2.* - test that unless FTS is bypassed
# and the underlying tables accessed directly, it is not possible for an
# SQLITE_LOCKED error to be enountered when committing an FTS transaction.
#
# Any SQLITE_LOCKED error should be returned when the fts4 (or fts4aux)
# table is first read/written within a transaction, not later on.
#
set LOCKED {1 {database table is locked}}
forcedelete test.db
sqlite3 dbR test.db
sqlite3 dbW test.db
do_test 2.1 {
  execsql {
    CREATE VIRTUAL TABLE t1 USING fts4;
    CREATE TABLE t2ext(a, b);
    CREATE VIRTUAL TABLE t2 USING fts4(content=t2ext);
    CREATE VIRTUAL TABLE t1aux USING fts4aux(t1);
    CREATE VIRTUAL TABLE t2aux USING fts4aux(t2);

    INSERT INTO t1   VALUES('a b c');
    INSERT INTO t2(rowid, a, b) VALUES(1, 'd e f', 'g h i');
  } dbW
} {}

# Test that once [dbW] has written to the FTS table, no client may read
# from the FTS or fts4aux table.
do_test 2.2.1 {
  execsql {
    BEGIN;
      INSERT INTO t1 VALUES('j k l');
  } dbW
  execsql BEGIN dbR
} {}
do_test 2.2.2 { catchsql "SELECT * FROM t1 WHERE rowid=1"          dbR } $LOCKED
do_test 2.2.3 { catchsql "SELECT * FROM t1 WHERE t1 MATCH 'a'"     dbR } $LOCKED
do_test 2.2.4 { catchsql "SELECT rowid FROM t1 WHERE t1 MATCH 'a'" dbR } $LOCKED
do_test 2.2.5 { catchsql "SELECT * FROM t1"                        dbR } $LOCKED
do_test 2.2.6 { catchsql "SELECT * FROM t1aux"                     dbR } $LOCKED
do_test 2.2.7 { execsql COMMIT dbW } {}
do_test 2.2.8 { execsql COMMIT dbR } {}

# Same test as 2.2.*, except with a content= table.
#
do_test 2.3.1 {
  execsql {
    BEGIN;
      INSERT INTO t2(rowid, a, b) VALUES(2, 'j k l', 'm n o');
  } dbW
  execsql BEGIN dbR
} {}
do_test 2.3.3 { catchsql "SELECT * FROM t2 WHERE t2 MATCH 'a'"     dbR } $LOCKED
do_test 2.3.4 { catchsql "SELECT rowid FROM t2 WHERE t2 MATCH 'a'" dbR } $LOCKED
do_test 2.3.6 { catchsql "SELECT * FROM t2aux"                     dbR } $LOCKED
do_test 2.3.7 { execsql COMMIT dbW } {}
do_test 2.3.8 { execsql COMMIT dbR } {}

# Test that once a connection has read from the FTS or fts4aux table, 
# another connection may not write to the FTS table.
#
foreach {tn sql} {
  1 "SELECT * FROM t1 WHERE rowid=1"
  2 "SELECT * FROM t1 WHERE t1 MATCH 'a'" 
  3 "SELECT rowid FROM t1 WHERE t1 MATCH 'a'"
  4 "SELECT * FROM t1"
  5 "SELECT * FROM t1aux"
} {

  do_test 2.4.$tn {
    execsql BEGIN dbR
    execsql $::sql dbR
    execsql BEGIN dbW
    catchsql "INSERT INTO t1 VALUES('p q r')" dbW
  } $LOCKED

  execsql ROLLBACK dbR 
  execsql ROLLBACK dbW 
}

# Same test as 2.4.*, except with a content= table.
#
foreach {tn sql} {
  2 "SELECT * FROM t2 WHERE t2 MATCH 'a'" 
  3 "SELECT rowid FROM t2 WHERE t2 MATCH 'a'"
  5 "SELECT * FROM t2aux"
} {

  do_test 2.5.$tn {
    execsql BEGIN dbR
    execsql $::sql dbR
    execsql BEGIN dbW
    catchsql "INSERT INTO t2(rowid, a, b) VALUES(3, 's t u', 'v w x')" dbW
  } $LOCKED

  execsql ROLLBACK dbR 
  execsql ROLLBACK dbW 
}

dbW close
dbR close
sqlite3_enable_shared_cache $::enable_shared_cache
finish_test