summaryrefslogtreecommitdiff
path: root/mysql-test/include/query_cache_sql_prepare.inc
blob: 1bc7c94a1725c46cf8589d009f5b2b90e8198fdb (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
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
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
############### include/query_cache_sql_prepare.inc ################
#
# This is to see how statements prepared via the PREPARE SQL command
# go into the query cache.
# Query cache is abbreviated as "QC"
#
# Last update:
# 2008-05-26 Kostja
#               - Add test coverage for automatic statement reprepare
#
# 2007-05-03 ML - Move t/query_cache_sql_prepare.test
#                 to   include/query_cache_sql_prepare.inc
#               - Create two toplevel tests sourcing this routine
#               - Add tests checking that
#                 - another connection gets the same amount of QC hits
#                 - statements running via ps-protocol do not hit QC results
#                   of preceding sql EXECUTEs
#

--source include/have_query_cache.inc
# embedded can't make more than one connection, which this test needs
-- source include/not_embedded.inc
set GLOBAL query_cache_type=ON;
set LOCAL query_cache_type=ON;

connect (con1,localhost,root,,test,$MASTER_MYPORT,);
connection default;

set @initial_query_cache_size = @@global.query_cache_size;
set @@global.query_cache_size=102400;
flush status;
--disable_warnings
drop table if exists t1;
--enable_warnings
create table t1(c1 int);
insert into t1 values(1),(10),(100);

# First, prepared statements with no parameters
prepare stmt1 from "select * from t1 where c1=10";
show status like 'Qcache_hits';
execute stmt1;
show status like 'Qcache_hits';
execute stmt1;
show status like 'Qcache_hits';
execute stmt1;
show status like 'Qcache_hits';
# Another prepared statement (same text, same connection), should hit the QC
prepare stmt2 from "select * from t1 where c1=10";
execute stmt2;
show status like 'Qcache_hits';
execute stmt2;
show status like 'Qcache_hits';
execute stmt2;
show status like 'Qcache_hits';
# Another prepared statement (same text, other connection), should hit the QC
connection con1;
prepare stmt3 from "select * from t1 where c1=10";
execute stmt3;
show status like 'Qcache_hits';
execute stmt3;
show status like 'Qcache_hits';
execute stmt3;
show status like 'Qcache_hits';
connection default;

# Mixup tests, where statements without PREPARE.../EXECUTE.... meet statements
# with PREPARE.../EXECUTE.... (text protocol). Both statements have the
# same text. QC hits occur only when both statements use the same protocol.
# The outcome of the test depends on the mysqltest startup options
# - with "--ps-protocol"
#   Statements without PREPARE.../EXECUTE.... run as prepared statements
#   with binary protocol. Expect to get no QC hits.
# - without any "--<whatever>-protocol"
#   Statements without PREPARE.../EXECUTE run as non prepared statements
#   with text protocol. Expect to get QC hits.
############################################################################
#
# Statement with PREPARE.../EXECUTE.... first
let $my_stmt= SELECT * FROM t1 WHERE c1 = 100;
eval prepare stmt10 from "$my_stmt";
show status like 'Qcache_hits';
execute stmt10;
show status like 'Qcache_hits';
execute stmt10;
show status like 'Qcache_hits';
eval $my_stmt;
show status like 'Qcache_hits';
connection con1;
eval $my_stmt;
show status like 'Qcache_hits';
connection default;
#
# Statement without PREPARE.../EXECUTE.... first
let $my_stmt= SELECT * FROM t1 WHERE c1 = 1;
eval prepare stmt11 from "$my_stmt";
connection con1;
eval prepare stmt12 from "$my_stmt";
connection default;
eval $my_stmt;
show status like 'Qcache_hits';
eval $my_stmt;
show status like 'Qcache_hits';
execute stmt11;
show status like 'Qcache_hits';
connection con1;
execute stmt12;
show status like 'Qcache_hits';
connection default;

# Query caching also works when statement has parameters
# (BUG#29318 Statements prepared with PREPARE and with one parameter don't use
# query cache)
prepare stmt1 from "select * from t1 where c1=?";
show status like 'Qcache_hits';
set @a=1;
execute stmt1 using @a;
show status like 'Qcache_hits';
execute stmt1 using @a;
show status like 'Qcache_hits';
connection con1;
set @a=1;
prepare stmt4 from "select * from t1 where c1=?";
execute stmt4 using @a;
show status like 'Qcache_hits';
# verify that presence of user variables forbids caching
prepare stmt4 from "select @a from t1 where c1=?";
execute stmt4 using @a;
show status like 'Qcache_hits';
execute stmt4 using @a;
show status like 'Qcache_hits';
connection default;

# See if enabling/disabling the query cache between PREPARE and
# EXECUTE is an issue; the expected result is that the query cache
# will not be used.
# Indeed, decision to read/write the query cache is taken at PREPARE
# time, so if the query cache was disabled at PREPARE time then no
# execution of the statement will read/write the query cache.
# If the query cache was enabled at PREPARE time, but disabled at
# EXECUTE time, at EXECUTE time the query cache internal functions do
# nothing so again the query cache is not read/written. But if the
# query cache is re-enabled before another execution then that
# execution will read/write the query cache.

# QC is enabled at PREPARE
prepare stmt1 from "select * from t1 where c1=10";
# then QC is disabled at EXECUTE
# Expect to see no additional Qcache_hits.
set global query_cache_size=0;
show status like 'Qcache_hits';
execute stmt1;
show status like 'Qcache_hits';
execute stmt1;
show status like 'Qcache_hits';
execute stmt1;
show status like 'Qcache_hits';
# The QC is global = affects also other connections.
# Expect to see no additional Qcache_hits.
connection con1;
execute stmt3;
show status like 'Qcache_hits';
execute stmt3;
show status like 'Qcache_hits';
execute stmt3;
show status like 'Qcache_hits';
#
# then QC is re-enabled for more EXECUTE.
connection default;
set global query_cache_size=102400;
# Expect to see additional Qcache_hits.
# The fact that the QC was temporary disabled should have no affect
# except that the first execute will not hit results from the
# beginning of the test (because QC has been emptied meanwhile by
# setting its size to 0).
execute stmt1;
show status like 'Qcache_hits';
execute stmt1;
show status like 'Qcache_hits';
execute stmt1;
show status like 'Qcache_hits';
# The QC is global = affects also other connections.
connection con1;
execute stmt3;
show status like 'Qcache_hits';
execute stmt3;
show status like 'Qcache_hits';
execute stmt3;
show status like 'Qcache_hits';
connection default;
#
# then QC is re-disabled for more EXECUTE.
# Expect to see no additional Qcache_hits.
# The fact that the QC was temporary enabled should have no affect.
set global query_cache_size=0;
show status like 'Qcache_hits';
execute stmt1;
show status like 'Qcache_hits';
execute stmt1;
show status like 'Qcache_hits';
execute stmt1;
show status like 'Qcache_hits';
# The QC is global = affects also other connections.
connection con1;
execute stmt3;
show status like 'Qcache_hits';
execute stmt3;
show status like 'Qcache_hits';
execute stmt3;
show status like 'Qcache_hits';
#

connection default;
# QC is disabled at PREPARE
set global query_cache_size=0;
prepare stmt1 from "select * from t1 where c1=10";
connection con1;
prepare stmt3 from "select * from t1 where c1=10";
connection default;
# then QC is enabled at EXECUTE
set global query_cache_size=102400;
show status like 'Qcache_hits';
execute stmt1;
show status like 'Qcache_hits';
execute stmt1;
show status like 'Qcache_hits';
execute stmt1;
show status like 'Qcache_hits';
# The QC is global = affects also other connections.
connection con1;
show status like 'Qcache_hits';
execute stmt3;
show status like 'Qcache_hits';
execute stmt3;
show status like 'Qcache_hits';
execute stmt3;
show status like 'Qcache_hits';
connection default;
#
# QC is disabled at PREPARE
set global query_cache_size=0;
prepare stmt1 from "select * from t1 where c1=?";
# then QC is enabled at EXECUTE
set global query_cache_size=102400;
show status like 'Qcache_hits';
set @a=1;
execute stmt1 using @a;
show status like 'Qcache_hits';
set @a=100;
execute stmt1 using @a;
show status like 'Qcache_hits';
set @a=10;
execute stmt1 using @a;
show status like 'Qcache_hits';


drop table t1;
disconnect con1;

#
# Bug #25843 Changing default database between PREPARE and EXECUTE of statement
# breaks binlog.
#
# There were actually two problems discovered by this bug:
#
#   1. Default (current) database is not fixed at the creation time.
#      That leads to wrong output of DATABASE() function.
#
#   2. Database attributes (@@collation_database) are not fixed at the creation
#      time. That leads to wrong resultset.
#
# Binlog breakage and Query Cache wrong output happened because of the first
# problem.
#

--echo ########################################################################
--echo #
--echo # BUG#25843: Changing default database between PREPARE and EXECUTE of
--echo # statement breaks binlog.
--echo #
--echo ########################################################################

###############################################################################

--echo
--echo #
--echo # Check that default database and its attributes are fixed at the
--echo # creation time.
--echo #

# Prepare data structures.

--echo
--disable_warnings
DROP DATABASE IF EXISTS mysqltest1;
DROP DATABASE IF EXISTS mysqltest2;
--enable_warnings

--echo
CREATE DATABASE mysqltest1 COLLATE utf8_unicode_ci;
CREATE DATABASE mysqltest2 COLLATE utf8_general_ci;

--echo
CREATE TABLE mysqltest1.t1(msg VARCHAR(255));
CREATE TABLE mysqltest2.t1(msg VARCHAR(255));

# - Create a prepared statement with mysqltest1 as default database;

--echo

use mysqltest1;

PREPARE stmt_a_1 FROM 'INSERT INTO t1 VALUES(DATABASE())';
PREPARE stmt_a_2 FROM 'INSERT INTO t1 VALUES(@@collation_database)';

# - Execute on mysqltest1.

--echo

EXECUTE stmt_a_1;
EXECUTE stmt_a_2;

# - Execute on mysqltest2.

--echo

use mysqltest2;

EXECUTE stmt_a_1;
EXECUTE stmt_a_2;

# - Check the results;

--echo
SELECT * FROM mysqltest1.t1;

--echo
SELECT * FROM mysqltest2.t1;

# - Drop prepared statements.

--echo
DROP PREPARE stmt_a_1;
DROP PREPARE stmt_a_2;

###############################################################################

--echo
--echo #
--echo # The Query Cache test case.
--echo #

--echo
DELETE FROM mysqltest1.t1;
DELETE FROM mysqltest2.t1;

--echo
INSERT INTO mysqltest1.t1 VALUES('mysqltest1.t1');
INSERT INTO mysqltest2.t1 VALUES('mysqltest2.t1');

--echo
use mysqltest1;
PREPARE stmt_b_1 FROM 'SELECT * FROM t1';

--echo
use mysqltest2;
PREPARE stmt_b_2 FROM 'SELECT * FROM t1';

--echo
EXECUTE stmt_b_1;

--echo
EXECUTE stmt_b_2;

--echo
use mysqltest1;

--echo
EXECUTE stmt_b_1;

--echo
EXECUTE stmt_b_2;

--echo
DROP PREPARE stmt_b_1;
DROP PREPARE stmt_b_2;

# Cleanup.

--echo
use test;

--echo
DROP DATABASE mysqltest1;
DROP DATABASE mysqltest2;

###############################################################################

--echo
--echo #
--echo # Check that prepared statements work properly when there is no current
--echo # database.
--echo #

--echo
CREATE DATABASE mysqltest1 COLLATE utf8_unicode_ci;
CREATE DATABASE mysqltest2 COLLATE utf8_general_ci;

--echo
use mysqltest1;

--echo
PREPARE stmt_c_1 FROM 'SELECT DATABASE(), @@collation_database';

--echo
use mysqltest2;

--echo
PREPARE stmt_c_2 FROM 'SELECT DATABASE(), @@collation_database';

--echo
DROP DATABASE mysqltest2;

--echo
SELECT DATABASE(), @@collation_database;

# -- Here we have: current db: NULL; stmt db: mysqltest1;
--echo
EXECUTE stmt_c_1;

--echo
SELECT DATABASE(), @@collation_database;

# -- Here we have: current db: NULL; stmt db: mysqltest2 (non-existent);
--echo
EXECUTE stmt_c_2;

--echo
SELECT DATABASE(), @@collation_database;

# -- Create prepared statement, which has no current database.

--echo
PREPARE stmt_c_3 FROM 'SELECT DATABASE(), @@collation_database';

# -- Here we have: current db: NULL; stmt db: NULL;
--echo
EXECUTE stmt_c_3;

--echo
use mysqltest1;

# -- Here we have: current db: mysqltest1; stmt db: mysqltest2 (non-existent);
--echo
EXECUTE stmt_c_2;

--echo
SELECT DATABASE(), @@collation_database;

# -- Here we have: current db: mysqltest1; stmt db: NULL;
--echo
EXECUTE stmt_c_3;

--echo
SELECT DATABASE(), @@collation_database;

--echo
DROP DATABASE mysqltest1;

--echo
use test;

--echo
--echo ########################################################################
--echo #
--echo # Bug#27430 Crash in subquery code when in PS and table DDL changed
--echo # after PREPARE
--echo # Check the effect of automatic reprepare on query cache
--echo #
--echo ########################################################################
--disable_warnings
drop table if exists t1;
--enable_warnings
create table t1 (a varchar(255));
insert into t1 (a) values ("Pack my box with five dozen liquor jugs.");
flush status;
prepare stmt from "select a from t1";
execute stmt;
set @@global.query_cache_size=0;
alter table t1 add column b int;
execute stmt;
set @@global.query_cache_size=102400;
execute stmt;
execute stmt;
--echo #
--echo # Sic: ALTER TABLE caused an automatic reprepare 
--echo # of the prepared statement. Since the query cache was disabled
--echo # at the time of reprepare, the new prepared statement doesn't
--echo # work with it.
--echo # 
show status like 'Qcache_hits';
show status like 'Qcache_queries_in_cache';
--echo # Cleanup
deallocate prepare stmt;
drop table t1;

###############################################################################

set @@global.query_cache_size=@initial_query_cache_size;
flush status; # reset Qcache status variables for next tests
set GLOBAL query_cache_type=default;