Skip to content

Commit 5fea964

Browse files
committed
Bug28429993: Merge branch 'mysql-5.6' into mysql-5.7
2 parents 00df405 + 8a04361 commit 5fea964

5 files changed

+3380
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,399 @@
1+
# ==== Purpose ====
2+
#
3+
# Creates a stored routine, stored function, trigger, view, or
4+
# prepared statement (commonly referred to as "recursive construct")
5+
# that invokes a given unsafe statement.
6+
#
7+
# Then, it invokes the created recursive construct several times:
8+
#
9+
# - With SQL_LOG_BIN = 1 and binlog_format = STATEMENT, to verify
10+
# that it gives a warning.
11+
#
12+
# - With SQL_LOG_BIN = 0 and binlog_format = STATEMENT, to verify that
13+
# there is no warning and nothing is logged.
14+
#
15+
# - With SQL_LOG_BIN = 1 and binlog_format = MIXED, to verify that it
16+
# errors out when the engine is a only statement capable.
17+
#
18+
# - In some cases, the recursive construct can be invoked so that it
19+
# has no side-effects but returns a value that may be
20+
# nondeterministic. An example is a function that returns UUID().
21+
# The function does not have side effects but its a return value
22+
# that may differ on slave. Such statements are invoked so that
23+
# the return value is discarded (e.g., SELECT func()), with
24+
# SQL_LOG_BIN = 1 and binlog_format = STATEMENT. In this case, no
25+
# warning should be given and nothing should be written to the
26+
# binlog.
27+
#
28+
# This is an auxiliary file particularly targeted to being used by the
29+
# test binlog_unsafe_stmt_capable_engine. In this context, the purpose is to
30+
# check how warnings for unsafe statements are propagated in recursive
31+
# constructs.
32+
#
33+
# The statement to invoke ("input") is described using mtr variables,
34+
# and the resulting recursive construct ("output") is stored in mtr
35+
# variables in a similar fashion. To create several levels of nested
36+
# recursive constructs, source this file once, then copy the values of
37+
# appropriate output variables to the input variables, and then source
38+
# this file again.
39+
#
40+
#
41+
# ==== Usage ====
42+
#
43+
# See the test binlog_unsafe_stmt_capable_engine for an example of how to use this file.
44+
#
45+
# let $CRC_ARG_level= <level>;
46+
# let $CRC_ARG_type= <type>;
47+
# let $CRC_ARG_stmt_sidef= <stmt>;
48+
# let $CRC_ARG_value= <stmt>;
49+
# let $CRC_ARG_sel_retval= <stmt>;
50+
# let $CRC_ARG_sel_sidef= <stmt>;
51+
# let $CRC_ARG_desc= <desc>;
52+
# source extra/rpl_tests/create_recursive_construct.inc;
53+
# let $my_stmt_sidef= $CRC_RET_stmt_sidef;
54+
# let $my_value= $CRC_RET_value;
55+
# let $my_sel_sidef= $CRC_RET_sel_sidef;
56+
# let $my_sel_retval= $CRC_RET_sel_retval;
57+
# let $my_drop= $CRC_RET_drop;
58+
# let $my_is_toplevel= $CRC_RET_top_is_toplevel;
59+
# let $my_desc= $CRC_RET_desc;
60+
#
61+
# $CRC_ARG_* are used as input parameters (arguments) to this file:
62+
#
63+
# $CRC_ARG_level is the recursion depth: 1 for the innermost
64+
# statement created, 2 for a statement that invokes a statement on
65+
# level 1, etc.
66+
#
67+
# $CRC_ARG_type is an integer from 0 to 6, indicating what type of
68+
# statement shall be created:
69+
# 0 - Create a stored function where the return value depends on
70+
# the value of the given statement.
71+
# 1 - Create a stored function that invokes the given statement as
72+
# a side-effect but may not return a value that depends on it.
73+
# 2 - Create a stored routine that invokes the given statement.
74+
# 3 - Create a trigger (on table trigger_table_$CRC_ARG_level) that
75+
# invokes the given statement.
76+
# 4 - Create a view that returns a value that depends on the value
77+
# of the given statement.
78+
# 5 - Create a view that invokes the given statement but may return
79+
# a value that does not depend on it.
80+
# 6 - Create a prepared statement that invokes the given statement.
81+
#
82+
# $CRC_ARG_stmt_sidef is the statement to invoke. It should be a
83+
# statement that can be invoked on its own (not sub-statement),
84+
# which causes something unsafe to be written to the binlog.
85+
#
86+
# $CRC_ARG_value is a sub-statement holding the value of the given
87+
# statement. Can be empty if the given statement does not have a
88+
# value. Typically, this is non-empty if the given statement is a
89+
# function call or user variable, but not if it is a stored routine
90+
# call, INSERT, SELECT, etc (because none of them has a value).
91+
# $CRC_ARG_value is used only when $CRC_ARG_type=6.
92+
#
93+
# $CRC_ARG_sel_sidef is a SELECT sub-statement that invokes the
94+
# statement as a side-effect, but returns a result set that may not
95+
# depend on the statement. Can be empty if the statement cannot
96+
# produce a result set from a SELECT. $CRC_ARG_sel_sidef is used
97+
# only if $CRC_ARG_type=2
98+
#
99+
# $CRC_ARG_sel_retval is a SELECT sub-statement that does not have
100+
# side-effects, but returns a result set that depends on the unsafe
101+
# statement. Can be empty if the statement cannot be invoked from a
102+
# SELECT. $CRC_ARG_sel_retval is used only if $CRC_ARG_type=3.
103+
#
104+
# $CRC_ARG_desc is a human-readable description of the statement to
105+
# invoke.
106+
#
107+
# $CRC_RET_* are used as output parameters (return values) of this
108+
# file:
109+
#
110+
# $CRC_RET_stmt_sidef is a statement invoking the resulting recursive
111+
# construct.
112+
#
113+
# $CRC_RET_value is a sub-statement invoking the resulting recursive
114+
# construct and returning the value of the recursive construct.
115+
# This is the empty string if the resulting recursive construct does
116+
# not have a value. In particular, this is non-empty only if
117+
# $CRC_ARG_value=7.
118+
#
119+
# $CRC_RET_sel_sidef is a SELECT sub-statement that invokes the
120+
# resulting recursive construct as a side-effect but where the
121+
# result set may not depend on the recursive construct. This is the
122+
# empty string if the recursive construct cannot be invoked from a
123+
# SELECT. In particular, this is non-empty only if $CRC_ARG_value=6
124+
# or $CRC_ARG_value=2.
125+
#
126+
# $CRC_RET_sel_retval is a SELECT sub-statement that does not have
127+
# side-effects, but returns a result set depending on the unsafe
128+
# statement. This is the empty string if the recursive construct
129+
# cannot produce a result set from a SELECT. In particular, this is
130+
# non-empty only if $CRC_ARG_value=7 or $CRC_ARG_value=3.
131+
#
132+
# $CRC_RET_drop is a statement that drops the created object. I.e.,
133+
# it is one of 'DROP FUNCTION <func>', 'DROP PROCEDURE <proc>', etc.
134+
#
135+
# $CRC_RET_top_is_toplevel is 0 normally, or 1 if the resulting
136+
# recursive construct can only be called from a top-level statement.
137+
# In particular, this is 1 only when $CRC_ARG_value=1, because
138+
# prepared statements cannot be invoked from other recursive
139+
# constructs.
140+
#
141+
# $CRC_RET_desc is a text string that describes the invokation of
142+
# the recursive construct in a human-readable fashion.
143+
#
144+
# Assumptions
145+
#
146+
# Before sourcing this file with $CRC_ARG_level=X, you need to
147+
# create three tables: tX, taX and trigger_table_X. These are used
148+
# as auxiliary tables.
149+
150+
151+
#--echo debug: >>>>ENTER create_recursive_construct
152+
#--echo debug: level=$CRC_ARG_level
153+
#--echo debug: type=$CRC_ARG_type
154+
#--echo debug: stmt_sidef=$CRC_ARG_stmt_sidef
155+
#--echo debug: value=$CRC_ARG_value
156+
#--echo debug: sel_retval=$CRC_ARG_sel_retval
157+
#--echo debug: sel_sidef=$CRC_ARG_sel_sidef
158+
159+
--let $CRC_RET_stmt_sidef=
160+
--let $CRC_RET_value=
161+
--let $CRC_RET_sel_retval=
162+
--let $CRC_RET_sel_sidef=
163+
--let $CRC_RET_drop=
164+
--let $CRC_RET_is_toplevel= 1
165+
--let $CRC_RET_desc=
166+
--let $CRC_name=
167+
--let $CRC_create=
168+
--let $CRC_expected_number_of_warnings= $CRC_ARG_expected_number_of_warnings
169+
--let $CRC_expected_number_of_warnings_normal_protocol= $CRC_ARG_expected_number_of_warnings
170+
--let $CRC_expected_number_of_warnings_ps_protocol= $CRC_ARG_expected_number_of_warnings
171+
--let $CRC_expected_number_of_warnings_after_reset= 0
172+
173+
######## func_retval ########
174+
# if inside if in lieu of AND operand
175+
if ($CRC_ARG_type == 0) {
176+
if ($CRC_ARG_value) {
177+
# It will be safe to call this function and discard the return
178+
# value, but it will be unsafe to use return value (e.g., in
179+
# INSERT...SELECT).
180+
--let $CRC_name= func_retval_$CRC_ARG_level
181+
--let $CRC_create= CREATE FUNCTION $CRC_name() RETURNS VARCHAR(100) BEGIN INSERT INTO ta$CRC_ARG_level VALUES (47); RETURN $CRC_ARG_value; END
182+
--let $CRC_RET_stmt_sidef= INSERT INTO t$CRC_ARG_level VALUES ($CRC_name())
183+
--let $CRC_RET_value= $CRC_name()
184+
--let $CRC_RET_sel_sidef=
185+
--let $CRC_RET_sel_retval= SELECT $CRC_name()
186+
--let $CRC_RET_drop= DROP FUNCTION $CRC_name
187+
--let $CRC_RET_is_toplevel= 0
188+
--let $CRC_RET_desc= function $CRC_name returning value from $CRC_ARG_desc
189+
}
190+
}
191+
192+
######## func_sidef ########
193+
if ($CRC_ARG_type == 1) {
194+
# It will be unsafe to call func even if you discard return value.
195+
--let $CRC_name= func_sidef_$CRC_ARG_level
196+
--let $CRC_create= CREATE FUNCTION $CRC_name() RETURNS VARCHAR(100) BEGIN INSERT INTO ta$CRC_ARG_level VALUES (47); $CRC_ARG_stmt_sidef; RETURN 0; END
197+
--let $CRC_RET_stmt_sidef= INSERT INTO t$CRC_ARG_level SELECT $CRC_name()
198+
--let $CRC_RET_value=
199+
--let $CRC_RET_sel_retval=
200+
--let $CRC_RET_sel_sidef= SELECT $CRC_name()
201+
--let $CRC_RET_drop= DROP FUNCTION $CRC_name
202+
--let $CRC_RET_is_toplevel= 0
203+
--let $CRC_RET_desc= function $CRC_name invoking $CRC_ARG_desc
204+
}
205+
206+
######## proc ########
207+
if ($CRC_ARG_type == 2) {
208+
# It will be unsafe to call this procedure.
209+
--let $CRC_name= proc_$CRC_ARG_level
210+
--let $CRC_create= CREATE PROCEDURE $CRC_name() BEGIN $CRC_ARG_stmt_sidef; INSERT INTO ta$CRC_ARG_level VALUES (47); END
211+
--let $CRC_RET_stmt_sidef= CALL $CRC_name()
212+
--let $CRC_RET_value=
213+
--let $CRC_RET_sel_retval=
214+
--let $CRC_RET_sel_sidef=
215+
--let $CRC_RET_drop= DROP PROCEDURE $CRC_name
216+
--let $CRC_RET_is_toplevel= 0
217+
--let $CRC_RET_desc= procedure $CRC_name invoking $CRC_ARG_desc
218+
}
219+
220+
######## trig ########
221+
if ($CRC_ARG_type == 3) {
222+
# It will be unsafe to invoke this trigger.
223+
--let $CRC_name= trig_$CRC_ARG_level
224+
--let $CRC_create= CREATE TRIGGER $CRC_name BEFORE INSERT ON trigger_table_$CRC_ARG_level FOR EACH ROW BEGIN INSERT INTO ta$CRC_ARG_level VALUES (47); $CRC_ARG_stmt_sidef; END
225+
--let $CRC_RET_stmt_sidef= INSERT INTO trigger_table_$CRC_ARG_level VALUES (1)
226+
--let $CRC_RET_value=
227+
--let $CRC_RET_sel_retval=
228+
--let $CRC_RET_sel_sidef=
229+
--let $CRC_RET_drop= DROP TRIGGER $CRC_name
230+
--let $CRC_RET_is_toplevel= 0
231+
--let $CRC_RET_desc= trigger $CRC_name invoking $CRC_ARG_desc
232+
}
233+
234+
######## view_retval ########
235+
if ($CRC_ARG_type == 4) {
236+
if ($CRC_ARG_sel_retval) {
237+
# It will be safe to select from this view if you discard the result
238+
# set, but unsafe to use result set (e.g., in INSERT..SELECT).
239+
--let $CRC_name= view_retval_$CRC_ARG_level
240+
--let $CRC_create= CREATE VIEW $CRC_name AS $CRC_ARG_sel_retval
241+
--let $CRC_RET_stmt_sidef= INSERT INTO t$CRC_ARG_LEVEL SELECT * FROM $CRC_name
242+
--let $CRC_RET_value=
243+
--let $CRC_RET_sel_retval= SELECT * FROM $CRC_name
244+
--let $CRC_RET_sel_sidef=
245+
--let $CRC_RET_drop= DROP VIEW $CRC_name
246+
--let $CRC_RET_is_toplevel= 0
247+
--let $CRC_RET_desc= view $CRC_name returning value from $CRC_ARG_desc
248+
}
249+
}
250+
251+
######## view_sidef ########
252+
if ($CRC_ARG_type == 5) {
253+
if ($CRC_ARG_sel_sidef) {
254+
# It will be unsafe to select from this view, even if you discard
255+
# the return value.
256+
--let $CRC_name= view_sidef_$CRC_ARG_level
257+
--let $CRC_create= CREATE VIEW $CRC_name AS $CRC_ARG_sel_sidef
258+
--let $CRC_RET_stmt_sidef= INSERT INTO t$CRC_ARG_level SELECT * FROM $CRC_name
259+
--let $CRC_RET_value=
260+
--let $CRC_RET_sel_retval=
261+
--let $CRC_RET_sel_sidef= SELECT * FROM $CRC_name
262+
--let $CRC_RET_drop= DROP VIEW $CRC_name
263+
--let $CRC_RET_is_toplevel= 0
264+
--let $CRC_RET_desc= view $CRC_name invoking $CRC_ARG_desc
265+
}
266+
}
267+
268+
######## prep ########
269+
if ($CRC_ARG_type == 6) {
270+
# It will be unsafe to execute this prepared statement
271+
--let $CRC_name= prep_$CRC_ARG_level
272+
--let $CRC_create= PREPARE $CRC_name FROM "$CRC_ARG_stmt_sidef"
273+
--let $CRC_RET_stmt_sidef= EXECUTE $CRC_name
274+
--let $CRC_RET_value=
275+
--let $CRC_RET_sel_retval=
276+
--let $CRC_RET_sel_sidef=
277+
--let $CRC_RET_drop= DROP PREPARE $CRC_name
278+
--let $CRC_RET_is_toplevel= 1
279+
--let $CRC_RET_desc= prepared statement $CRC_name invoking $CRC_ARG_desc
280+
}
281+
282+
######## no recursive construct: just return the given statement ########
283+
if ($CRC_ARG_type == 7) {
284+
# CRC_ARG_type=7 is a special case. We just set $CRC_RET_x =
285+
# $CRC_ARG_x. This way, the $CRC_ARG_stmt gets executed directly
286+
# (below). In binlog_unsafe.test, it is used to invoke the unsafe
287+
# statement created in the outermost loop directly, without
288+
# enclosing it in a recursive construct.
289+
--let $CRC_RET_stmt_sidef= $CRC_ARG_stmt_sidef
290+
--let $CRC_RET_value= $CRC_ARG_value
291+
--let $CRC_RET_sel_retval= $CRC_ARG_sel_retval
292+
--let $CRC_RET_sel_sidef= $CRC_ARG_sel_sidef
293+
--let $CRC_RET_drop=
294+
--let $CRC_RET_is_toplevel= 1
295+
--let $CRC_RET_desc= $CRC_ARG_desc
296+
--let $CRC_expected_number_of_warnings_normal_protocol= `select $CRC_ARG_expected_number_of_deprecation_warnings + $CRC_ARG_expected_number_of_warnings`
297+
--let $CRC_expected_number_of_warnings_ps_protocol= $CRC_ARG_expected_number_of_warnings
298+
--let $CRC_expected_number_of_warnings_after_reset_normal_protocol= `select $CRC_ARG_expected_number_of_deprecation_warnings + $CRC_expected_number_of_warnings_after_reset`
299+
--let $CRC_expected_number_of_warnings_after_reset_ps_protocol= $CRC_expected_number_of_warnings_after_reset
300+
301+
--let $CRC_expected_number_of_warnings= $CRC_expected_number_of_warnings_normal_protocol
302+
--let $CRC_expected_number_of_warnings_after_reset= $CRC_expected_number_of_warnings_after_reset_normal_protocol
303+
if ($PS_PROTOCOL)
304+
{
305+
--let $CRC_expected_number_of_warnings= $CRC_expected_number_of_warnings_ps_protocol
306+
--let $CRC_expected_number_of_warnings_after_reset= $CRC_expected_number_of_warnings_after_reset_ps_protocol
307+
}
308+
}
309+
310+
######## execute! ########
311+
if ($CRC_RET_stmt_sidef) {
312+
--echo
313+
--echo Invoking $CRC_RET_desc.
314+
if ($CRC_create) {
315+
--eval $CRC_create
316+
}
317+
318+
if ($CRC_expected_number_of_warnings_normal_protocol == $CRC_expected_number_of_warnings_ps_protocol)
319+
{
320+
--echo * binlog_format = STATEMENT: expect $CRC_expected_number_of_warnings warnings.
321+
}
322+
if ($CRC_expected_number_of_warnings_normal_protocol != $CRC_expected_number_of_warnings_ps_protocol)
323+
{
324+
--echo * binlog_format = STATEMENT: expect $CRC_expected_number_of_warnings_normal_protocol warnings. $CRC_expected_number_of_warnings_ps_protocol with ps-protocol.
325+
}
326+
--eval $CRC_RET_stmt_sidef
327+
--let $n_warnings= `SHOW COUNT(*) WARNINGS`
328+
329+
--let $assert_cond= $n_warnings = $CRC_expected_number_of_warnings
330+
--let $assert_text= There should be $CRC_expected_number_of_warnings warning(s)
331+
--source include/assert.inc
332+
333+
334+
# These queries are run without query log, to make result file more
335+
# readable. Debug info is only printed if something abnormal
336+
# happens.
337+
--disable_query_log
338+
339+
--echo * SQL_LOG_BIN = 0: expect nothing logged and only deprecation warnings.
340+
SET SQL_LOG_BIN = 0;
341+
RESET MASTER;
342+
--eval $CRC_RET_stmt_sidef
343+
344+
--let $n_warnings= `SHOW COUNT(*) WARNINGS`
345+
--let $assert_cond= $n_warnings = $CRC_expected_number_of_warnings_after_reset
346+
--let $assert_text= There should be $CRC_expected_number_of_warnings_after_reset warning(s)
347+
--source include/assert.inc
348+
349+
--let $assert_text= Only two events should exist in the binary log
350+
--let $assert_cond= "[SHOW BINLOG EVENTS, Event_type, 3]" = "No such row"
351+
--source include/assert.inc
352+
SET SQL_LOG_BIN = 1;
353+
354+
--echo * binlog_format = MIXED: expect error since the engine is only statement capable and doesn't have row logging capability.
355+
SET binlog_format = MIXED;
356+
RESET MASTER;
357+
--let $CRC_expected_number_of_warnings_after_reset = $CRC_expected_number_of_warnings
358+
--error ER_BINLOG_UNSAFE_AND_STMT_ENGINE
359+
--eval $CRC_RET_stmt_sidef
360+
--let $n_warnings= `SHOW COUNT(*) WARNINGS`
361+
if ($n_warnings != $CRC_expected_number_of_warnings_after_reset) {
362+
--echo ******** Failure! Expected $CRC_expected_number_of_warnings_after_reset warnings, got $n_warnings warnings. ********
363+
--source include/show_rpl_debug_info.inc
364+
--die Wrong number of warnings
365+
}
366+
SET binlog_format = STATEMENT;
367+
368+
--enable_query_log
369+
}
370+
371+
# Invoke created object, discarding the return value. This should not
372+
# give any warning.
373+
if ($CRC_RET_sel_retval) {
374+
--echo * Invoke statement so that return value is discarded: expect no warning.
375+
--disable_result_log
376+
--eval $CRC_RET_sel_retval
377+
--enable_result_log
378+
379+
# Currently, due to a bug, we do get warnings here, so we don't
380+
# fail. When the bug is fixed, we should execute the following.
381+
382+
#--let $n_warnings= `SHOW COUNT(*) WARNINGS`
383+
#if ($n_warnings) {
384+
# --enable_query_log
385+
# --echo Failure! Expected 0 warnings, got $n_warnings warnings.
386+
# SHOW WARNINGS;
387+
# SHOW BINLOG EVENTS;
388+
# --die Wrong number of warnings.
389+
#}
390+
}
391+
392+
#--echo debug: <<<<EXIT create_recursive_construct
393+
#--echo debug: stmt_sidef=$CRC_RET_stmt_sidef
394+
#--echo debug: value=$CRC_RET_value
395+
#--echo debug: sel_retval=$CRC_RET_sel_retval
396+
#--echo debug: sel_sidef=$CRC_RET_sel_sidef
397+
#--echo debug: drop=$CRC_RET_drop
398+
#--echo debug: is_toplevel=$CRC_RET_is_toplevel
399+
#--echo debug: desc=$CRC_RET_desc

0 commit comments

Comments
 (0)