1# ==== Purpose ==== 2# 3# Evaluate an expression, possibly containing arbitrary 4# sub-expressions from different connections. 5# 6# The expression is parsed before executed. The following constructs 7# are supported: 8# 9# [SQL_STATEMENT, COLUMN, ROW] 10# The square bracket is replaced by the result from SQL_STATEMENT, 11# in the given COLUMN and ROW. 12# 13# Optionally, SQL_STATEMENT may have the form: 14# connection:SQL_STATEMENT 15# In this case, SQL_STATEMENT is executed on the named connection. 16# All other queries executed by this script will be executed on 17# the connection that was in use when this script was started. 18# The current connection will also be restored at the end of this 19# script. 20# 21# It is also possible to nest sub-statements on this form, like: 22# [master:SHOW BINLOG EVENTS FROM 23# [slave:SHOW SLAVE STATUS, Master_Log_Pos, 1], 24# 1, Position] 25# 26# [SQL_STATEMENT] 27# Shortcut to the above form, usable when the result has only one 28# row and one column. 29# 30# <1> 31# This is a shorthand for the result of the first executed square 32# bracket. <2> is a shorthand for the second executed square 33# bracket, and so on. 34# 35# ==== Usage ==== 36# 37# --let $eval_expr= [SHOW SLAVE STATUS, Relay_Log_Pos, 1] + 47 38# [--let $eval_no_result= 1] 39# [--let $rpl_debug= 1] 40# --source include/eval.inc 41# --echo Result was '$eval_result' 42# 43# Parameters: 44# 45# $eval_expr 46# Expression to evaluate. See above for details about the format. The 47# expression will be executed as `SELECT $eval_expr`. 48# 49# Both $eval_expr and the result from any substatement on the 50# form [SQL_STATEMENT, COLUMN, ROW] will be used in SQL statements, 51# inside single quotes (as in '$eval_expr'). So any single quotes 52# in these texts must be escaped or replaced by double quotes. 53# 54# $eval_no_result 55# By default, the expression is evaluated inside 'SELECT' and the 56# result is stored in $eval_result. If this variable is set, the 57# expression is instead evaluated as it is and the result is not 58# stored anywhere. 59# 60# $rpl_debug 61# Print extra debug info. 62# 63# Return value: 64# The result is stored in $eval_result. 65 66--let $include_filename= eval.inc 67--source include/begin_include_file.inc 68 69if ($rpl_debug) 70{ 71 --echo # debug: eval_expr='$eval_expr' eval_no_result='$eval_no_result' 72} 73 74--let $_eval_old_connection= $CURRENT_CONNECTION 75 76# Evaluate square brackets in expr. 77--let $_eval_substmt_number= 1 78--let $_eval_expr_interp= '$eval_expr' 79--let $_eval_rbracket= `SELECT LOCATE(']', $_eval_expr_interp)` 80while ($_eval_rbracket) 81{ 82 # Get position of right bracket 83 --let $_eval_lbracket= `SELECT $_eval_rbracket - LENGTH(SUBSTRING_INDEX(SUBSTR($_eval_expr_interp, 1, $_eval_rbracket), '[', -1))` 84 if ($_eval_lbracket == 0) 85 { 86 --echo BUG IN TEST: Mismatching square brackets in eval_expr. 87 --echo Original eval_expr='$eval_expr' 88 --echo Interpolated eval_expr=$_eval_expr_interp 89 --die BUG IN TEST: Mismatching square brackets in $eval_expr 90 } 91 92 # Get sub-statement from statement. Preserve escapes for single quotes. 93 --let $_eval_full_substmt= `SELECT QUOTE(SUBSTRING($_eval_expr_interp, $_eval_lbracket + 1, $_eval_rbracket - $_eval_lbracket - 1))` 94 95 # Get connection from sub-statement 96 --let $_eval_colon= `SELECT IF($_eval_full_substmt REGEXP '^[a-zA-Z_][a-zA-Z_0-9]*:', LOCATE(':', $_eval_full_substmt), 0)` 97 --let $_eval_connection= 98 --let $_eval_substmt= $_eval_full_substmt 99 if ($_eval_colon) 100 { 101 --let $_eval_connection= `SELECT SUBSTRING($_eval_substmt, 1, $_eval_colon - 1)` 102 # Preserve escapes for single quotes. 103 --let $_eval_substmt= `SELECT QUOTE(SUBSTRING($_eval_substmt, $_eval_colon + 1))` 104 } 105 106 # Interpolate escapes before using expression outside string context. 107 --let $_eval_substmt_interp= `SELECT $_eval_substmt` 108 109 # Change connection 110 if ($_eval_connection) 111 { 112 if ($rpl_debug) 113 { 114 --echo # debug: connection='$_eval_connection' sub-statement=$_eval_substmt 115 } 116 --let $rpl_connection_name= $_eval_connection 117 --source include/rpl_connection.inc 118 } 119 if (!$_eval_connection) 120 { 121 if ($rpl_debug) 122 { 123 --echo # debug: old connection, sub-statement=$_eval_substmt 124 } 125 } 126 127 # Execute and get result from sub-statement. 128 # Can't use dollar to denote end of string because mtr will try to 129 # interpolate it. 130 --let $selected_row_col= `SELECT CONCAT($_eval_substmt, 'ZZENDZZ') REGEXP '[a-zA-Z_][a-zA-Z0-9_]* *, *[0-9][0-9]* *ZZENDZZ'` 131 132 if ($selected_row_col) 133 { 134 --let $_eval_substmt_result= query_get_value($_eval_substmt_interp) 135 } 136 if (!$selected_row_col) 137 { 138 --let $_eval_substmt_result= `$_eval_substmt_interp` 139 } 140 141 # Change back connection 142 if ($_eval_connection) 143 { 144 --let $rpl_connection_name= $_eval_old_connection 145 --source include/rpl_connection.inc 146 } 147 148 if ($rpl_debug) 149 { 150 --echo # debug: result of sub-statement='$_eval_substmt_result' 151 } 152 153 # Replace sub-statement by its result 154 --let $_eval_expr_interp= `SELECT QUOTE(REPLACE($_eval_expr_interp, CONCAT('[', $_eval_full_substmt, ']'), '$_eval_substmt_result'))` 155 # Replace result references by result 156 --let $_eval_expr_interp= `SELECT QUOTE(REPLACE($_eval_expr_interp, '<$_eval_substmt_number>', '$_eval_substmt_result'))` 157 158 --let $_eval_rbracket= `SELECT LOCATE(']', $_eval_expr_interp)` 159 160 --inc $_eval_substmt_number 161} 162 163# Interpolate escapes before using expression outside string context. 164--let $_eval_expr_interp= `SELECT $_eval_expr_interp` 165 166if ($rpl_debug) 167{ 168 --echo # debug: interpolated_expr='$_eval_expr_interp' 169} 170 171# Execute. 172if ($eval_no_result) 173{ 174 --eval $_eval_expr_interp 175} 176if (!$eval_no_result) 177{ 178 --let $eval_result= `SELECT $_eval_expr_interp` 179} 180 181if ($rpl_debug) 182{ 183 --echo # debug: result='$eval_result' 184} 185 186--let $include_filename= eval.inc 187--source include/end_include_file.inc 188