# ==== Purpose ==== # # Evaluate an expression, possibly containing arbitrary # sub-expressions from different connections. # # The expression is parsed before executed. The following constructs # are supported: # # [SQL_STATEMENT, COLUMN, ROW] # The square bracket is replaced by the result from SQL_STATEMENT, # in the given COLUMN and ROW. # # Optionally, SQL_STATEMENT may have the form: # connection:SQL_STATEMENT # In this case, SQL_STATEMENT is executed on the named connection. # All other queries executed by this script will be executed on # the connection that was in use when this script was started. # The current connection will also be restored at the end of this # script. # # It is also possible to nest sub-statements on this form, like: # [master:SHOW BINLOG EVENTS FROM # [slave:SHOW SLAVE STATUS, Master_Log_Pos, 1], # 1, Position] # # [SQL_STATEMENT] # Shortcut to the above form, usable when the result has only one # row and one column. # # <1> # This is a shorthand for the result of the first executed square # bracket. <2> is a shorthand for the second executed square # bracket, and so on. # # ==== Usage ==== # # --let $eval_expr= [SHOW SLAVE STATUS, Relay_Log_Pos, 1] + 47 # [--let $eval_no_result= 1] # [--let $rpl_debug= 1] # --source include/eval.inc # --echo Result was '$eval_result' # # Parameters: # # $eval_expr # Expression to evaluate. See above for details about the format. The # expression will be executed as `SELECT $eval_expr`. # # Both $eval_expr and the result from any substatement on the # form [SQL_STATEMENT, COLUMN, ROW] will be used in SQL statements, # inside single quotes (as in '$eval_expr'). So any single quotes # in these texts must be escaped or replaced by double quotes. # # $eval_no_result # By default, the expression is evaluated inside 'SELECT' and the # result is stored in $eval_result. If this variable is set, the # expression is instead evaluated as it is and the result is not # stored anywhere. # # $rpl_debug # Print extra debug info. # # Return value: # The result is stored in $eval_result. --let $include_filename= eval.inc --source include/begin_include_file.inc if ($rpl_debug) { --echo # debug: eval_expr='$eval_expr' eval_no_result='$eval_no_result' } --let $_eval_old_connection= $CURRENT_CONNECTION # Evaluate square brackets in expr. --let $_eval_substmt_number= 1 --let $_eval_expr_interp= '$eval_expr' --let $_eval_rbracket= `SELECT LOCATE(']', $_eval_expr_interp)` while ($_eval_rbracket) { # Get position of right bracket --let $_eval_lbracket= `SELECT $_eval_rbracket - LENGTH(SUBSTRING_INDEX(SUBSTR($_eval_expr_interp, 1, $_eval_rbracket), '[', -1))` if ($_eval_lbracket == 0) { --echo BUG IN TEST: Mismatching square brackets in eval_expr. --echo Original eval_expr='$eval_expr' --echo Interpolated eval_expr=$_eval_expr_interp --die BUG IN TEST: Mismatching square brackets in $eval_expr } # Get sub-statement from statement. Preserve escapes for single quotes. --let $_eval_full_substmt= `SELECT QUOTE(SUBSTRING($_eval_expr_interp, $_eval_lbracket + 1, $_eval_rbracket - $_eval_lbracket - 1))` # Get connection from sub-statement --let $_eval_colon= `SELECT IF($_eval_full_substmt REGEXP '^[a-zA-Z_][a-zA-Z_0-9]*:', LOCATE(':', $_eval_full_substmt), 0)` --let $_eval_connection= --let $_eval_substmt= $_eval_full_substmt if ($_eval_colon) { --let $_eval_connection= `SELECT SUBSTRING($_eval_substmt, 1, $_eval_colon - 1)` # Preserve escapes for single quotes. --let $_eval_substmt= `SELECT QUOTE(SUBSTRING($_eval_substmt, $_eval_colon + 1))` } # Interpolate escapes before using expression outside string context. --let $_eval_substmt_interp= `SELECT $_eval_substmt` # Change connection if ($_eval_connection) { if ($rpl_debug) { --echo # debug: connection='$_eval_connection' sub-statement=$_eval_substmt } --let $rpl_connection_name= $_eval_connection --source include/rpl_connection.inc } if (!$_eval_connection) { if ($rpl_debug) { --echo # debug: old connection, sub-statement=$_eval_substmt } } # Execute and get result from sub-statement. # Can't use dollar to denote end of string because mtr will try to # interpolate it. --let $selected_row_col= `SELECT CONCAT($_eval_substmt, 'ZZENDZZ') REGEXP '[a-zA-Z_][a-zA-Z0-9_]* *, *[0-9][0-9]* *ZZENDZZ'` if ($selected_row_col) { --let $_eval_substmt_result= query_get_value($_eval_substmt_interp) } if (!$selected_row_col) { --let $_eval_substmt_result= `$_eval_substmt_interp` } # Change back connection if ($_eval_connection) { --let $rpl_connection_name= $_eval_old_connection --source include/rpl_connection.inc } if ($rpl_debug) { --echo # debug: result of sub-statement='$_eval_substmt_result' } # Replace sub-statement by its result --let $_eval_expr_interp= `SELECT QUOTE(REPLACE($_eval_expr_interp, CONCAT('[', $_eval_full_substmt, ']'), '$_eval_substmt_result'))` # Replace result references by result --let $_eval_expr_interp= `SELECT QUOTE(REPLACE($_eval_expr_interp, '<$_eval_substmt_number>', '$_eval_substmt_result'))` --let $_eval_rbracket= `SELECT LOCATE(']', $_eval_expr_interp)` --inc $_eval_substmt_number } # Interpolate escapes before using expression outside string context. --let $_eval_expr_interp= `SELECT $_eval_expr_interp` if ($rpl_debug) { --echo # debug: interpolated_expr='$_eval_expr_interp' } # Execute. if ($eval_no_result) { --eval $_eval_expr_interp } if (!$eval_no_result) { --let $eval_result= `SELECT $_eval_expr_interp` } if ($rpl_debug) { --echo # debug: result='$eval_result' } --let $include_filename= eval.inc --source include/end_include_file.inc