File: check_repeatable_read_all_columns.inc

package info (click to toggle)
mysql-5.1 5.1.73-1%2Bdeb6u1
  • links: PTS, VCS
  • area: main
  • in suites: squeeze-lts
  • size: 197,132 kB
  • ctags: 93,377
  • sloc: cpp: 579,952; ansic: 429,462; perl: 49,053; sh: 21,692; pascal: 21,272; yacc: 12,801; makefile: 4,545; xml: 4,114; sql: 3,297; lex: 1,265; asm: 1,023
file content (225 lines) | stat: -rw-r--r-- 10,192 bytes parent folder | download | duplicates (8)
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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
################################################################################
#
# Verifies that queries in a REPEATABLE READ transaction is indeed repeatable.
# Wrong results are shown as a result set based on one or more specially crafted
# queries. Normally these result sets should be empty.
#
# We want to verify that reads (SELECTs) are indeed repeatable during a 
# REPEATABLE READ transaction.
#
# Generally, queries which should yield the same results at one moment in time 
# should also yield the same results later in the same transaction. In some 
# configurations, however, phantom reads are allowed (may e.g. depend on 
# settings such as falcon_consistent_read).
#
# The check will fail if rows are changed or missing when comparing later
# queries to earlier ones.
# TODO: Phantom reads.
#       Note: There is a separate test looking for `is_uncommitted` = 1.
#
# Assumptions:
#   - we are in a REPEATABLE READ transaction with autocommit OFF.
#   - queries include all columns of table (t1) (we SELECT columns by name)
#
# Requires/using the following variables:
#   $query_count - the number of queries to compare.
#                  Will also be used to deduce the name of the temp table in
#                  which the query results should be stored (see 
#                  record_query_all_columns.inc).
#
################################################################################

# Show results of next queries. Empty results is OK. Non-empty means failure.
--enable_result_log

# The mysqltest language is unfortunaltely not very flexible, but we try our
# best to compare query results this way:
#   - For each query, compare with previous query
#     - this requires that at least 2 queries have been stored
#   - Number of queries should be stored as $query_count
#   - Results should be stored in temp tables with names ending with the query
#     number, and with prefix "tmp". 
#   - E.g. compare "tmp2" with "tmp1", "tmp3" with "tmp2", "tmp4" with "tmp3" etc.
#   - Fail the test once we detect changed or missing or invalid extra rows in
#     latter query.
#   ?????
#   - Problem is that if one of the queries deadlocked or timed out, we may not
#     have enough result sets to compare, so output will vary depending on this.
#     Still we need the output from these checks to see which rows are missing or
#     changed.
#     So, if we don't have enough queries we fake "correct output" to make mysqltest
#     happy.
#
# Unfortunately, we need to utilize SQL and spend client-server roundtrips
# in order to do some computations that the mysqltest language does not handle.
# We try to use mysqltest variables instead where possible, as this should be 
# less expensive in terms of CPU usage and time spenditure.

#
# First, check that we have at least two query results stored.
# We need at least 2 to be able to compare.
# Some results may not have been stored due to locking errors (see record_query_all_columns.inc), so
# we cannot assume that we always have at least 2 query results stored.
# If less than 2 query results are stored, return to calling test/script.
#
if (`SELECT IF($query_count > 1, 1, 0)`)
{
    
    --echo ***************************************************************************
    --echo * Checking REPEATABLE READ by comparing result sets from same transaction
    --echo ***************************************************************************

    --echo *** Query log disabled. See include files used by test for query details.
    --disable_query_log

    let $queryA= 1;
    let $queryB= 2;
    let $more_queries= $query_count;

    # We start out by comparing the first 2 queries, so the while loop should run
    # $query_count - 1 times. (If we have 3 queries, compare 1 with 2, 2 and 3).
    --dec $more_queries

    while ($more_queries)
    {
        # We still have one or more queries that have not been compared to the
        # previous query.
        # Compare queryB ("current query") with queryA ("previous query")

        #--source suite/stress_tx_rr/include/compare_queries_with_pk.inc

        let $tableA= tmp$queryA;
        let $tableB= tmp$queryB;

        --echo *** Comparing query $queryA (A) with query $queryB (B):

        #
        # In the following queries, 'SELECT * ...' could have been used instead of
        # 'SELECT tmp1.pk AS ...' etc., but the latter makes it easier to compare the first
        # result set to the second in test/diff output.



        ###########################
        # Detect extra rows:
        # Allow phantoms in some configurations:
        #   - InnoDB default settings
        #   - Falcon's falcon_consistent_read=0 (non-default setting)
        #   (TODO: What about PBXT?)
        #
        ###########################
        # TODO: Execute a query against tmp1 and tmp2 which selects new rows (rows
        #       present in tmp2 that are not present in tmp1) that are of the uncommitted
        #       variety (field `is_uncommitted` = 1).
        # E.g. something like:
        #  SELECT ...
        #   FROM tmp2 LEFT JOIN tmp1
        #   ON tmp1.`pk` = tmp2.`pk`
        #   WHERE tmp1.`int1` IS NULL
        #   OR tmp1.`int1_key` IS NULL
        #   OR tmp1.`int1_unique` IS NULL
        #   OR tmp1.`int2` IS NULL
        #   OR tmp1.`int2_key` IS NULL
        #   OR tmp1.`int2_unique` IS NULL
        #   AND tmp2.`is_uncommitted` = 1;


        --echo ###########################
        --echo # Detect missing rows:
        --echo ###########################


        eval SELECT    $tableA.pk AS 'A.pk',
                      $tableB.pk AS 'B.pk',
                      $tableA.id AS 'A.id',
                      $tableB.id AS 'B.id',
                      $tableA.`int1` AS 'A.int1',
                      $tableB.`int1` AS 'B.int1',
                      $tableA.`int1_key` AS 'A.int1_key',
                      $tableB.`int1_key` AS 'B.int1_key',
                      $tableA.`int1_unique` AS 'A.int1_unique',
                      $tableB.`int1_unique` AS 'B.int1_unique',
                      $tableA.`int2` AS 'A.int2',
                      $tableB.`int2` AS 'B.int2',
                      $tableA.`int2_key` AS 'A.int2_key',
                      $tableB.`int2_key` AS 'B.int2_key',
                      $tableA.`int2_unique` AS 'A.int2_unique',
                      $tableB.`int2_unique` AS 'B.int2_unique',
                      $tableA.`for_update` AS 'A.for_update',
                      $tableB.`for_update` AS 'B.for_update',
                      $tableA.timestamp AS 'A.timestamp',
                      $tableB.timestamp AS 'B.timestamp',
                      $tableA.`connection_id` AS 'A.connection_id',
                      $tableB.`connection_id` AS 'B.connection_id',
                      $tableA.`thread_id` AS 'A.thread_id',
                      $tableB.`thread_id` AS 'B.thread_id',
                      $tableA.`is_uncommitted` AS 'A.is_uncommitted',
                      $tableB.`is_uncommitted` AS 'B.is_uncommitted',
                      $tableA.`is_consistent` AS 'A.is_consistent',
                      $tableB.`is_consistent` AS 'B.is_consistent'
                FROM $tableA LEFT JOIN $tableB
                  ON $tableA.`pk` = $tableB.`pk`
                WHERE $tableB.`pk` IS NULL;

    #
    #               OR $tableB.`int1_key` IS NULL
    #               OR $tableB.`int1_unique` IS NULL
    #               OR $tableB.`int2` IS NULL
    #               OR $tableB.`int2_key` IS NULL
    #               OR $tableB.`int2_unique` IS NULL;

        --echo
        --echo ###########################
        --echo # Detect changed rows:
        --echo ###########################

        eval SELECT  $tableA.pk AS 'A.pk',
                      $tableB.pk AS 'B.pk',
                      $tableA.id AS 'A.id',
                      $tableB.id AS 'B.id',
                      $tableA.`int1` AS 'A.int1',
                      $tableB.`int1` AS 'B.int1',
                      $tableA.`int1_key` AS 'A.int1_key',
                      $tableB.`int1_key` AS 'B.int1_key',
                      $tableA.`int1_unique` AS 'A.int1_unique',
                      $tableB.`int1_unique` AS 'B.int1_unique',
                      $tableA.`int2` AS 'A.int2',
                      $tableB.`int2` AS 'B.int2',
                      $tableA.`int2_key` AS 'A.int2_key',
                      $tableB.`int2_key` AS 'B.int2_key',
                      $tableA.`int2_unique` AS 'A.int2_unique',
                      $tableB.`int2_unique` AS 'B.int2_unique',
                      $tableA.`for_update` AS 'A.for_update',
                      $tableB.`for_update` AS 'B.for_update',
                      $tableA.timestamp AS 'A.timestamp',
                      $tableB.timestamp AS 'B.timestamp',
                      $tableA.`connection_id` AS 'A.connection_id',
                      $tableB.`connection_id` AS 'B.connection_id',
                      $tableA.`thread_id` AS 'A.thread_id',
                      $tableB.`thread_id` AS 'B.thread_id',
                      $tableA.`is_uncommitted` AS 'A.is_uncommitted',
                      $tableB.`is_uncommitted` AS 'B.is_uncommitted',
                      $tableA.`is_consistent` AS 'A.is_consistent',
                      $tableB.`is_consistent` AS 'B.is_consistent'
                FROM $tableB INNER JOIN $tableA
                  ON $tableB.`pk` = $tableA.`pk`
                WHERE $tableB.`int1` <> $tableA.`int1`
                  OR $tableB.`int1_key` <> $tableA.`int1_key`
                  OR $tableB.`int1_unique` <> $tableA.`int1_unique`
                  OR $tableB.`int2` <> $tableA.`int2`
                  OR $tableB.`int2_key` <> $tableA.`int2_key`
                  OR $tableB.`int2_unique` <> $tableA.`int2_unique`;

        --dec $more_queries
        --inc $queryA
        --inc $queryB

    }
    --enable_query_log
}


## Cleanup is skipped because temporary tables and prepared statements will
## be cleaned up automatically by the server when this session ends, and we
## want to have as few client-server roundtrips as possible (thus avoid 
## unnecessary SQL statement executions).