--[[ Copyright (C) 2009 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA --]] -- TODO: implement the master.info files -- you will need to know where to place the file proxy.global.vars = proxy.global.vars or {} proxy.global.ismaster = proxy.global.ismaster or false proxy.global.max_value = 2147483048 local query_counter = 0 function round(num, idp) return tonumber(string.format("%." .. (idp or 0) .. "f", num)) end --[[ We set some starting values for some variables and then increase their values after every query that comes through the proxy --]] function force_alerts() -- Set the starting point for values and increment if proxy.global.vars["mocked"] == nil then -- if this index is not setup ( nil ), this is the first query proxy.global.vars["mocked"] = 1 proxy.global.vars["aborted_connects"] = 1 proxy.global.vars["connections"] = 100 proxy.global.vars["max_connections"] = 50 proxy.global.vars["threads_connected"] = 80 proxy.global.vars["created_tmp_disk_tables"] = 95 proxy.global.vars["created_tmp_tables"] = 100 proxy.global.vars["innodb_buffer_pool_read_requests"] = 200 proxy.global.vars["innodb_buffer_pool_reads"] = 100 proxy.global.vars["key_read_requests"] = 10000 proxy.global.vars["key_reads"] = 5000 proxy.global.vars["query_cache_size"] = 1000000 proxy.global.vars["Qcache_lowmem_prunes"] = 100 proxy.global.vars["open_files_limit"] = 100 proxy.global.vars["table_cache"] = 10 proxy.global.vars["Open_tables"] = 90 proxy.global.vars["Opened_tables"] = 900 proxy.global.vars["threads_created"] = 2 proxy.global.vars["Binlog_cache_disk_use"] = 50 proxy.global.vars["Binlog_cache_use"] = 60 proxy.global.vars["flush"] = "ON" proxy.global.vars["flush_time"] = 10 proxy.global.vars["handler_read_first"] = 100 proxy.global.vars["handler_read_key"] = 500 proxy.global.vars["handler_read_next"] = 1000 proxy.global.vars["handler_read_prev"] = 1000 proxy.global.vars["handler_read_rnd"] = 3000 proxy.global.vars["handler_read_rnd_next"] = 5000 proxy.global.vars["uptime"] = 442107 proxy.global.vars["uptime_since_flush_status"] = 442107 proxy.global.vars["innodb_buffer_pool_wait_free"] = 100 proxy.global.vars["innodb_buffer_pool_write_requests"] = 2000 -- We get the mysqld port here local serveradddress = proxy.connection.server["address"] local port_pos, port_length = string.find(serveradddress,":") local serverport = string.sub(serveradddress,port_pos + 1) proxy.global.vars["port"] = serverport + 2000 proxy.global.vars["threads_running"] = 20 proxy.global.vars["master_binlog_id"] = 710 proxy.global.vars["com_select"] = 29 proxy.global.vars["com_insert"] = 65 proxy.global.vars["com_insert_select"] = 20 proxy.global.vars["com_update"] = 15 proxy.global.vars["com_update_multi"] = 13 proxy.global.vars["com_replace"] = 20 proxy.global.vars["com_replace_select"] = 5 proxy.global.vars["com_delete"] = 10 proxy.global.vars["com_delete_multi"] = 55 proxy.global.vars["com_call_procedure"] = 31 else -- we have been running, so increase these values proxy.global.vars["aborted_connects"] = proxy.global.vars["aborted_connects"] + 5 proxy.global.vars["connections"] = proxy.global.vars["connections"] + 10 proxy.global.vars["created_tmp_disk_tables"] = proxy.global.vars["created_tmp_disk_tables"] + 100 proxy.global.vars["created_tmp_tables"] = proxy.global.vars["created_tmp_tables"] + 100 proxy.global.vars["innodb_buffer_pool_read_requests"] = proxy.global.vars["innodb_buffer_pool_read_requests"] + 100 proxy.global.vars["innodb_buffer_pool_reads"] = proxy.global.vars["innodb_buffer_pool_reads"] + 100 proxy.global.vars["key_read_requests"] = proxy.global.vars["key_read_requests"] + 100 proxy.global.vars["key_reads"] = proxy.global.vars["key_reads"] + 100 proxy.global.vars["threads_created"] = proxy.global.vars["threads_created"] + 100 proxy.global.vars["Binlog_cache_disk_use"] = proxy.global.vars["Binlog_cache_disk_use"] + 100 proxy.global.vars["Binlog_cache_use"] = proxy.global.vars["Binlog_cache_use"] + 100 proxy.global.vars["handler_read_first"] = proxy.global.vars["handler_read_first"] + 100 proxy.global.vars["handler_read_key"] = proxy.global.vars["handler_read_key"] + 100 proxy.global.vars["handler_read_next"] = proxy.global.vars["handler_read_next"] + 100 proxy.global.vars["handler_read_prev"] = proxy.global.vars["handler_read_prev"] + 100 proxy.global.vars["handler_read_rnd"] = proxy.global.vars["handler_read_rnd"] + 200 proxy.global.vars["handler_read_rnd_next"] = proxy.global.vars["handler_read_rnd_next"] + 250 proxy.global.vars["uptime"] = proxy.global.vars["uptime"] + 1 proxy.global.vars["uptime_since_flush_status"] = proxy.global.vars["uptime_since_flush_status"] + 1 proxy.global.vars["innodb_buffer_pool_wait_free"] = proxy.global.vars["innodb_buffer_pool_wait_free"] + 100 proxy.global.vars["innodb_buffer_pool_write_requests"] = proxy.global.vars["innodb_buffer_pool_write_requests"] + 100 proxy.global.vars["threads_connected"] = proxy.global.vars["threads_connected"] + 10 proxy.global.vars["threads_running"] = proxy.global.vars["threads_running"] + 5 proxy.global.vars["master_binlog_id"] = proxy.global.vars["master_binlog_id"] + 1 proxy.global.vars["com_select"] = round( proxy.global.vars["com_select"] * 1.1 , 0) proxy.global.vars["com_insert"] = round( proxy.global.vars["com_insert"] * 1.1 , 0) proxy.global.vars["com_insert_select"] = round( proxy.global.vars["com_insert_select"] * 1.1 , 0) proxy.global.vars["com_update"] = round( proxy.global.vars["com_update"] * 1.1 , 0) proxy.global.vars["com_update_multi"] = round( proxy.global.vars["com_update_multi"] * 1.1 , 0) proxy.global.vars["com_replace"] = round( proxy.global.vars["com_replace"] * 1.1 , 0) proxy.global.vars["com_replace_select"] = round( proxy.global.vars["com_replace_select"] * 1.1 , 0) proxy.global.vars["com_delete"] = round( proxy.global.vars["com_delete"] * 1.1 , 0) proxy.global.vars["com_delete_multi"] = round( proxy.global.vars["com_delete_multi"] * 1.1 , 0) proxy.global.vars["com_call_procedure"] = round( proxy.global.vars["com_call_procedure"] * 1.1 , 0) end -- End of if variables are already set --[[ TODO: revisit this We reset the values here if we reach proxy.global.max_value on any variable (higher values break the app --]] local num = tonumber(proxy.global.max_value) for var, value in pairs(proxy.global.vars) do if (tonumber(value) ~= nil and num ~= nil) then if tonumber(value) > num then proxy.global.vars["mocked"] = nil end end end end -- End of force_alerts() function read_query( packet ) -- a new query cames in in this connection query_counter = query_counter + 1 if string.byte(packet) == proxy.COM_QUERY then -- TODO: find a good place to call this force_alerts() print (string.sub(packet, 2)) --[[ we use a simple string-match to split commands are word-boundaries mysql> show querycounter is split into command = "show" option = "querycounter" spaces are ignored, the case has to be as is. mysql> show myerror returns a error-packet --]] -- try to match the string up to the first non-alphanum local f_s, f_e, command = string.find(packet, "^%s*(%w+)", 2) command = string.lower(command) local option -- print ( "f_e=> " .. tostring(f_e) .. " Command => " .. command ) if f_e then -- Remove the comments from the statement local stmt = packet stmt = string.gsub(stmt, "%/%*%!50000 GLOBAL %*%/", " ") -- print ("stmt ==> " .. stmt) -- if that match, take the next sub-string as option f_s, f_e, option = string.find(stmt, "^%s+(%w+%s*%w*)", f_e + 1) if option then option = string.lower(option) -- print ("Command => " .. command .. " Option ==> " .. option) end end -- print ( "f_e=> " .. tostring(f_e) .. " Command => " .. command .. " Option ==> " .. tostring(option)) -- we got our commands, execute it if command == "show" and option == "querycounter" then proxy.response.type = proxy.MYSQLD_PACKET_OK proxy.response.resultset = { fields = { { type = proxy.MYSQL_TYPE_LONG, name = "query_counter", }, }, rows = { { query_counter } } } -- we have our result, send it back return proxy.PROXY_SEND_RESULT elseif command == "show" and option == "myerror" then proxy.response.type = proxy.MYSQLD_PACKET_ERR proxy.response.errmsg = "my first error" return proxy.PROXY_SEND_RESULT elseif command == "show" and option == "master status" then -- We will mock SHOW MASTER STATUS proxy.queries:append(1, packet, { resultset_is_needed = true } ) proxy.queries:append(2, string.char(proxy.COM_QUERY) .. "show slave status", { resultset_is_needed = true } ) return proxy.PROXY_SEND_QUERY elseif command == "show" and option == "slave status" then -- we mock SHOW SLAVE STATUS -- We send the query to the server proxy.queries:append(1, packet, { resultset_is_needed = true } ) return proxy.PROXY_SEND_QUERY elseif command == "show" and option == "variables" then -- Mocking SHOW VARIABLES statements proxy.response.type = proxy.MYSQLD_PACKET_OK proxy.response.resultset = { fields = { { type = proxy.MYSQL_TYPE_STRING, name = "Variable_name", }, { type = proxy.MYSQL_TYPE_STRING, name = "Value", } }, rows = { { "auto_increment_increment" , "1" } , { "auto_increment_offset" , "1" } , { "automatic_sp_privileges" , "ON" } , { "back_log" , "50" } , { "basedir" , "/Users/wizard/Downloads/server/mysql/5.0.67/" } , { "binlog_cache_size" , "32768" } , { "bulk_insert_buffer_size" , "8388608" } , { "character_set_client" , "latin1" } , { "character_set_connection" , "latin1" } , { "character_set_database" , "latin1" } , { "character_set_filesystem" , "binary" } , { "character_set_results" , "latin1" } , { "character_set_server" , "latin1" } , { "character_set_system" , "utf8" } , { "character_sets_dir" , "/Users/wizard/Downloads/server/mysql/5.0.67/share/mysql/charsets/" } , { "collation_connection" , "latin1_swedish_ci" } , { "collation_database" , "latin1_swedish_ci" } , { "collation_server" , "latin1_swedish_ci" } , { "completion_type" , "0" } , { "concurrent_insert" , "1" } , { "connect_timeout" , "10" } , { "datadir" , "/Users/wizard/build/Selenium/" } , { "date_format" , "%Y-%m-%d" } , { "datetime_format" , "%Y-%m-%d %H:%i:%s" } , { "default_week_format" , "0" } , { "delay_key_write" , "ON" } , { "delayed_insert_limit" , "100" } , { "delayed_insert_timeout" , "300" } , { "delayed_queue_size" , "1000" } , { "div_precision_increment" , "4" } , { "keep_files_on_create" , "OFF" } , { "engine_condition_pushdown" , "OFF" } , { "expire_logs_days" , "0" } , { "flush" , proxy.global.vars["flush"] } , { "flush_time" , proxy.global.vars["flush_time"] } , -- { "ft_boolean_syntax" , "+ -><()~*:\"\"&|" } , { "ft_max_word_len" , "84" } , { "ft_min_word_len" , "4" } , { "ft_query_expansion_limit" , "20" } , { "ft_stopword_file" , "(built-in)" } , { "group_concat_max_len" , "1024" } , { "have_archive" , "YES" } , { "have_bdb" , "NO" } , { "have_blackhole_engine" , "YES" } , { "have_compress" , "YES" } , { "have_crypt" , "YES" } , { "have_csv" , "YES" } , { "have_dynamic_loading" , "YES" } , { "have_example_engine" , "NO" } , { "have_federated_engine" , "YES" } , { "have_geometry" , "YES" } , { "have_innodb" , "YES" } , { "have_isam" , "NO" } , { "have_merge_engine" , "YES" } , { "have_ndbcluster" , "DISABLED" } , { "have_openssl" , "DISABLED" } , { "have_ssl" , "DISABLED" } , { "have_query_cache" , "YES" } , { "have_raid" , "NO" } , { "have_rtree_keys" , "YES" } , { "have_symlink" , "YES" } , { "hostname" , "diego-medinas-macbook-pro.local" } , { "init_connect" , "" } , { "init_file" , "" } , { "init_slave" , "" } , { "innodb_additional_mem_pool_size" , "1048576" } , { "innodb_autoextend_increment" , "8" } , { "innodb_buffer_pool_awe_mem_mb" , "0" } , { "innodb_buffer_pool_size" , "8388608" } , { "innodb_checksums" , "ON" } , { "innodb_commit_concurrency" , "0" } , { "innodb_concurrency_tickets" , "500" } , { "innodb_data_file_path" , "ibdata1:10M:autoextend" } , { "innodb_data_home_dir" , "" } , { "innodb_adaptive_hash_index" , "ON" } , { "innodb_doublewrite" , "ON" } , { "innodb_fast_shutdown" , "1" } , { "innodb_file_io_threads" , "4" } , { "innodb_file_per_table" , "OFF" } , { "innodb_flush_log_at_trx_commit" , "1" } , { "innodb_flush_method" , "" } , { "innodb_force_recovery" , "0" } , { "innodb_lock_wait_timeout" , "50" } , { "innodb_locks_unsafe_for_binlog" , "OFF" } , { "innodb_log_arch_dir" , "" } , { "innodb_log_archive" , "OFF" } , { "innodb_log_buffer_size" , "1048576" } , { "innodb_log_file_size" , "5242880" } , { "innodb_log_files_in_group" , "2" } , { "innodb_log_group_home_dir" , "./" } , { "innodb_max_dirty_pages_pct" , "90" } , { "innodb_max_purge_lag" , "0" } , { "innodb_mirrored_log_groups" , "1" } , { "innodb_open_files" , "300" } , { "innodb_rollback_on_timeout" , "OFF" } , { "innodb_support_xa" , "ON" } , { "innodb_sync_spin_loops" , "20" } , { "innodb_table_locks" , "ON" } , { "innodb_thread_concurrency" , "8" } , { "innodb_thread_sleep_delay" , "10000" } , { "interactive_timeout" , "28800" } , { "join_buffer_size" , "131072" } , { "key_buffer_size" , "8384512" } , { "key_cache_age_threshold" , "300" } , { "key_cache_block_size" , "1024" } , { "key_cache_division_limit" , "100" } , { "language" , "/Users/wizard/Downloads/server/mysql/5.0.67/share/mysql/english/" } , { "large_files_support" , "ON" } , { "large_page_size" , "0" } , { "large_pages" , "OFF" } , { "lc_time_names" , "en_US" } , { "license" , "GPL" } , { "local_infile" , "ON" } , { "locked_in_memory" , "OFF" } , { "log" , "OFF" } , { "log_bin" , "OFF" } , { "log_bin_trust_function_creators" , "OFF" } , { "log_error" , "./msandbox.err" } , { "log_queries_not_using_indexes" , "OFF" } , { "log_slave_updates" , "OFF" } , { "log_slow_queries" , "OFF" } , { "log_warnings" , "1" } , { "long_query_time" , "10" } , { "low_priority_updates" , "OFF" } , { "lower_case_file_system" , "ON" } , { "lower_case_table_names" , "2" } , { "max_allowed_packet" , "1048576" } , { "max_binlog_cache_size" , "4294963200" } , { "max_binlog_size" , "1073741824" } , { "max_connect_errors" , "10" } , { "max_connections" , proxy.global.vars["max_connections"] } , { "max_delayed_threads" , "20" } , { "max_error_count" , "64" } , { "max_heap_table_size" , "16777216" } , { "max_insert_delayed_threads" , "20" } , { "max_join_size" , "18446744073709551615" } , { "max_length_for_sort_data" , "1024" } , { "max_prepared_stmt_count" , "16382" } , { "max_relay_log_size" , "0" } , { "max_seeks_for_key" , "4294967295" } , { "max_sort_length" , "1024" } , { "max_sp_recursion_depth" , "0" } , { "max_tmp_tables" , "32" } , { "max_user_connections" , "0" } , { "max_write_lock_count" , "4294967295" } , { "multi_range_count" , "256" } , { "myisam_data_pointer_size" , "6" } , { "myisam_max_sort_file_size" , "2146435072" } , { "myisam_recover_options" , "OFF" } , { "myisam_repair_threads" , "1" } , { "myisam_sort_buffer_size" , "8388608" } , { "myisam_stats_method" , "nulls_unequal" } , { "ndb_autoincrement_prefetch_sz" , "1" } , { "ndb_force_send" , "ON" } , { "ndb_use_exact_count" , "ON" } , { "ndb_use_transactions" , "ON" } , { "ndb_cache_check_time" , "0" } , { "ndb_connectstring" , "" } , { "net_buffer_length" , "16384" } , { "net_read_timeout" , "30" } , { "net_retry_count" , "10" } , { "net_write_timeout" , "60" } , { "new" , "OFF" } , { "old_passwords" , "OFF" } , { "open_files_limit" , proxy.global.vars["open_files_limit"] } , { "optimizer_prune_level" , "1" } , { "optimizer_search_depth" , "62" } , { "pid_file" , "/Users/wizard/sandboxes/msb_5_0_67/data/mysql_sandbox5067.pid" } , { "plugin_dir" , "" } , { "port" , proxy.global.vars["port"] } , { "preload_buffer_size" , "32768" } , { "profiling" , "OFF" } , { "profiling_history_size" , "15" } , { "protocol_version" , "10" } , { "query_alloc_block_size" , "8192" } , { "query_cache_limit" , "1048576" } , { "query_cache_min_res_unit" , "4096" } , { "query_cache_size" , proxy.global.vars["query_cache_size"] } , { "query_cache_type" , "ON" } , { "query_cache_wlock_invalidate" , "OFF" } , { "query_prealloc_size" , "8192" } , { "range_alloc_block_size" , "4096" } , { "read_buffer_size" , "131072" } , { "read_only" , "OFF" } , { "read_rnd_buffer_size" , "262144" } , { "relay_log" , "" } , { "relay_log_index" , "" } , { "relay_log_info_file" , "relay-log.info" } , { "relay_log_purge" , "ON" } , { "relay_log_space_limit" , "0" } , { "rpl_recovery_rank" , "0" } , { "secure_auth" , "OFF" } , { "secure_file_priv" , "" } , { "server_id" , "0" } , { "skip_external_locking" , "ON" } , { "skip_networking" , "OFF" } , { "skip_show_database" , "OFF" } , { "slave_compressed_protocol" , "OFF" } , { "slave_load_tmpdir" , "/var/folders/5Y/5Y2-TlifGUSkEWBfmEs4kk+++TI/-Tmp-/" } , { "slave_net_timeout" , "3600" } , { "slave_skip_errors" , "OFF" } , { "slave_transaction_retries" , "10" } , { "slow_launch_time" , "2" } , { "socket" , "/tmp/mysql_sandbox5067.sock" } , { "sort_buffer_size" , "2097144" } , { "sql_big_selects" , "ON" } , { "sql_mode" , "" } , { "sql_notes" , "ON" } , { "sql_warnings" , "OFF" } , { "ssl_ca" , "" } , { "ssl_capath" , "" } , { "ssl_cert" , "" } , { "ssl_cipher" , "" } , { "ssl_key" , "" } , { "storage_engine" , "MyISAM" } , { "sync_binlog" , "0" } , { "sync_frm" , "ON" } , { "system_time_zone" , "EST" } , { "table_cache" , proxy.global.vars["table_cache"] } , { "table_lock_wait_timeout" , "50" } , { "table_type" , "MyISAM" } , { "thread_cache_size" , "0" } , { "thread_stack" , "196608" } , { "time_format" , "%H:%i:%s" } , { "time_zone" , "SYSTEM" } , { "timed_mutexes" , "OFF" } , { "tmp_table_size" , "33554432" } , { "tmpdir" , "/var/folders/5Y/5Y2-TlifGUSkEWBfmEs4kk+++TI/-Tmp-/" } , { "transaction_alloc_block_size" , "8192" } , { "transaction_prealloc_size" , "4096" } , { "tx_isolation" , "REPEATABLE-READ" } , { "updatable_views_with_limit" , "YES" } , { "version" , "5.0.67" } , { "version_comment" , "MySQL Community Server (GPL) mocked" } , { "version_compile_machine" , "i686" } , { "version_compile_os" , "apple-darwin9.0.0b5" } , { "wait_timeout" , "28800" } } } -- we have our result, send it back return proxy.PROXY_SEND_RESULT elseif command == "show" and option == "status" then -- We mock the SHOW STATUS statement proxy.response.type = proxy.MYSQLD_PACKET_OK proxy.response.resultset = { fields = { { type = proxy.MYSQL_TYPE_STRING, name = "Variable_name", }, { type = proxy.MYSQL_TYPE_STRING, name = "Value", } }, rows = { { "Aborted_clients" , "4" }, { "Aborted_connects" , proxy.global.vars["aborted_connects"] }, { "Binlog_cache_disk_use" , proxy.global.vars["Binlog_cache_disk_use"] }, { "Binlog_cache_use" , proxy.global.vars["Binlog_cache_use"] }, { "Bytes_received" , "122" }, { "Bytes_sent" , "166" }, { "Com_admin_commands" , "0" }, { "Com_alter_db" , "0" }, { "Com_alter_table" , "0" }, { "Com_analyze" , "0" }, { "Com_backup_table" , "0" }, { "Com_begin" , "0" }, { "Com_call_procedure" , proxy.global.vars["com_call_procedure"] }, { "Com_change_db" , "0" }, { "Com_change_master" , "0" }, { "Com_check" , "0" }, { "Com_checksum" , "0" }, { "Com_commit" , "0" }, { "Com_create_db" , "0" }, { "Com_create_function" , "0" }, { "Com_create_index" , "0" }, { "Com_create_table" , "0" }, { "Com_create_user" , "0" }, { "Com_dealloc_sql" , "0" }, { "Com_delete" , proxy.global.vars["com_delete"] }, { "Com_delete_multi" , proxy.global.vars["com_delete_multi"] }, { "Com_do" , "0" }, { "Com_drop_db" , "0" }, { "Com_drop_function" , "0" }, { "Com_drop_index" , "0" }, { "Com_drop_table" , "0" }, { "Com_drop_user" , "0" }, { "Com_execute_sql" , "0" }, { "Com_flush" , "0" }, { "Com_grant" , "0" }, { "Com_ha_close" , "0" }, { "Com_ha_open" , "0" }, { "Com_ha_read" , "0" }, { "Com_help" , "0" }, { "Com_insert" , proxy.global.vars["com_insert"] }, { "Com_insert_select" , proxy.global.vars["com_insert_select"] }, { "Com_kill" , "0" }, { "Com_load" , "0" }, { "Com_load_master_data" , "0" }, { "Com_load_master_table" , "0" }, { "Com_lock_tables" , "0" }, { "Com_optimize" , "0" }, { "Com_preload_keys" , "0" }, { "Com_prepare_sql" , "0" }, { "Com_purge" , "0" }, { "Com_purge_before_date" , "0" }, { "Com_rename_table" , "0" }, { "Com_repair" , "0" }, { "Com_replace" , proxy.global.vars["com_replace"] }, { "Com_replace_select" , proxy.global.vars["com_replace_select"] }, { "Com_reset" , "0" }, { "Com_restore_table" , "0" }, { "Com_revoke" , "0" }, { "Com_revoke_all" , "0" }, { "Com_rollback" , "0" }, { "Com_savepoint" , "0" }, { "Com_select" , proxy.global.vars["com_select"] }, { "Com_set_option" , "0" }, { "Com_show_binlog_events" , "0" }, { "Com_show_binlogs" , "0" }, { "Com_show_charsets" , "0" }, { "Com_show_collations" , "0" }, { "Com_show_column_types" , "0" }, { "Com_show_create_db" , "0" }, { "Com_show_create_table" , "0" }, { "Com_show_databases" , "0" }, { "Com_show_errors" , "0" }, { "Com_show_fields" , "0" }, { "Com_show_grants" , "0" }, { "Com_show_innodb_status" , "0" }, { "Com_show_keys" , "0" }, { "Com_show_logs" , "0" }, { "Com_show_master_status" , "0" }, { "Com_show_ndb_status" , "0" }, { "Com_show_new_master" , "0" }, { "Com_show_open_tables" , "0" }, { "Com_show_privileges" , "0" }, { "Com_show_processlist" , "0" }, { "Com_show_slave_hosts" , "0" }, { "Com_show_slave_status" , "0" }, { "Com_show_status" , "1" }, { "Com_show_storage_engines" , "0" }, { "Com_show_tables" , "0" }, { "Com_show_triggers" , "0" }, { "Com_show_variables" , "0" }, { "Com_show_warnings" , "0" }, { "Com_slave_start" , "0" }, { "Com_slave_stop" , "0" }, { "Com_stmt_close" , "0" }, { "Com_stmt_execute" , "0" }, { "Com_stmt_fetch" , "0" }, { "Com_stmt_prepare" , "0" }, { "Com_stmt_reset" , "0" }, { "Com_stmt_send_long_data" , "0" }, { "Com_truncate" , "0" }, { "Com_unlock_tables" , "0" }, { "Com_update" , proxy.global.vars["com_update"] }, { "Com_update_multi" , proxy.global.vars["com_update_multi"] }, { "Com_xa_commit" , "0" }, { "Com_xa_end" , "0" }, { "Com_xa_prepare" , "0" }, { "Com_xa_recover" , "0" }, { "Com_xa_rollback" , "0" }, { "Com_xa_start" , "0" }, { "Compression" , "OFF" }, { "Connections" , proxy.global.vars["connections"] }, { "Created_tmp_disk_tables" , proxy.global.vars["created_tmp_disk_tables"] }, { "Created_tmp_files" , "5" }, { "Created_tmp_tables" , proxy.global.vars["created_tmp_tables"] }, { "Delayed_errors" , "0" }, { "Delayed_insert_threads" , "0" }, { "Delayed_writes" , "0" }, { "Flush_commands" , "1" }, { "Handler_commit" , "0" }, { "Handler_delete" , "0" }, { "Handler_discover" , "0" }, { "Handler_prepare" , "0" }, { "Handler_read_first" , proxy.global.vars["handler_read_first"] }, { "Handler_read_key" , proxy.global.vars["handler_read_key"] }, { "Handler_read_next" , proxy.global.vars["handler_read_next"] }, { "Handler_read_prev" , proxy.global.vars["handler_read_prev"] }, { "Handler_read_rnd" , proxy.global.vars["handler_read_rnd"] }, { "Handler_read_rnd_next" , proxy.global.vars["handler_read_rnd_next"] }, { "Handler_rollback" , "0" }, { "Handler_savepoint" , "0" }, { "Handler_savepoint_rollback" , "0" }, { "Handler_update" , "0" }, { "Handler_write" , "132" }, { "Innodb_buffer_pool_pages_data" , "319" }, { "Innodb_buffer_pool_pages_dirty" , "0" }, { "Innodb_buffer_pool_pages_flushed" , "0" }, { "Innodb_buffer_pool_pages_free" , "193" }, { "Innodb_buffer_pool_pages_latched" , "0" }, { "Innodb_buffer_pool_pages_misc" , "0" }, { "Innodb_buffer_pool_pages_total" , "512" }, { "Innodb_buffer_pool_read_ahead_rnd" , "6" }, { "Innodb_buffer_pool_read_ahead_seq" , "0" }, { "Innodb_buffer_pool_read_requests" , proxy.global.vars["innodb_buffer_pool_read_requests"]}, { "Innodb_buffer_pool_reads" , proxy.global.vars["innodb_buffer_pool_reads"]}, { "Innodb_buffer_pool_wait_free" , proxy.global.vars["innodb_buffer_pool_wait_free"]}, { "Innodb_buffer_pool_write_requests" , proxy.global.vars["innodb_buffer_pool_write_requests"]}, { "Innodb_data_fsyncs" , "3" }, { "Innodb_data_pending_fsyncs" , "0" }, { "Innodb_data_pending_reads" , "0" }, { "Innodb_data_pending_writes" , "0" }, { "Innodb_data_read" , "7409664" }, { "Innodb_data_reads" , "312" }, { "Innodb_data_writes" , "3" }, { "Innodb_data_written" , "1536" }, { "Innodb_dblwr_pages_written" , "0" }, { "Innodb_dblwr_writes" , "0" }, { "Innodb_log_waits" , "0" }, { "Innodb_log_write_requests" , "0" }, { "Innodb_log_writes" , "1" }, { "Innodb_os_log_fsyncs" , "3" }, { "Innodb_os_log_pending_fsyncs" , "0" }, { "Innodb_os_log_pending_writes" , "0" }, { "Innodb_os_log_written" , "512" }, { "Innodb_page_size" , "16384" }, { "Innodb_pages_created" , "0" }, { "Innodb_pages_read" , "319" }, { "Innodb_pages_written" , "0" }, { "Innodb_row_lock_current_waits" , "0" }, { "Innodb_row_lock_time" , "0" }, { "Innodb_row_lock_time_avg" , "0" }, { "Innodb_row_lock_time_max" , "0" }, { "Innodb_row_lock_waits" , "0" }, { "Innodb_rows_deleted" , "0" }, { "Innodb_rows_inserted" , "0" }, { "Innodb_rows_read" , "0" }, { "Innodb_rows_updated" , "0" }, { "Key_blocks_not_flushed" , "0" }, { "Key_blocks_unused" , "7244" }, { "Key_blocks_used" , "7245" }, { "Key_read_requests" , proxy.global.vars["key_read_requests"] }, { "Key_reads" , proxy.global.vars["key_reads"] }, { "Key_write_requests" , "2253421" }, { "Key_writes" , "31047" }, { "Last_query_cost" , "0.000000" }, { "Max_used_connections" , "4" }, { "Ndb_cluster_node_id" , "0" }, { "Ndb_config_from_host" , " " }, { "Ndb_config_from_port" , "0" }, { "Ndb_number_of_data_nodes" , "0" }, { "Not_flushed_delayed_rows" , "0" }, { "Open_files" , "52" }, { "Open_streams" , "0" }, { "Open_tables" , proxy.global.vars["Open_tables"] }, { "Opened_tables" , proxy.global.vars["Opened_tables"] }, { "Prepared_stmt_count" , "0" }, { "Qcache_free_blocks" , "0" }, { "Qcache_free_memory" , "0" }, { "Qcache_hits" , "0" }, { "Qcache_inserts" , "0" }, { "Qcache_lowmem_prunes" , proxy.global.vars["Qcache_lowmem_prunes"] }, { "Qcache_not_cached" , "0" }, { "Qcache_queries_in_cache" , "0" }, { "Qcache_total_blocks" , "0" }, { "Questions" , "16170" }, { "Rpl_status" , "NULL" }, { "Select_full_join" , "0" }, { "Select_full_range_join" , "0" }, { "Select_range" , "0" }, { "Select_range_check" , "0" }, { "Select_scan" , "1" }, { "Slave_open_temp_tables" , "0" }, { "Slave_retried_transactions" , "0" }, { "Slave_running" , "OFF" }, { "Slow_launch_threads" , "0" }, { "Slow_queries" , "0" }, { "Sort_merge_passes" , "0" }, { "Sort_range" , "0" }, { "Sort_rows" , "0" }, { "Sort_scan" , "0" }, { "Ssl_accept_renegotiates" , "0" }, { "Ssl_accepts" , "0" }, { "Ssl_callback_cache_hits" , "0" }, { "Ssl_cipher" , " " }, { "Ssl_cipher_list" , " " }, { "Ssl_client_connects" , "0" }, { "Ssl_connect_renegotiates" , "0" }, { "Ssl_ctx_verify_depth" , "0" }, { "Ssl_ctx_verify_mode" , "0" }, { "Ssl_default_timeout" , "0" }, { "Ssl_finished_accepts" , "0" }, { "Ssl_finished_connects" , "0" }, { "Ssl_session_cache_hits" , "0" }, { "Ssl_session_cache_misses" , "0" }, { "Ssl_session_cache_mode" , "NONE" }, { "Ssl_session_cache_overflows" , "0" }, { "Ssl_session_cache_size" , "0" }, { "Ssl_session_cache_timeouts" , "0" }, { "Ssl_sessions_reused" , "0" }, { "Ssl_used_session_cache_entries" , "0" }, { "Ssl_verify_depth" , "0" }, { "Ssl_verify_mode" , "0" }, { "Ssl_version" , " " }, { "Table_locks_immediate" , "4040" }, { "Table_locks_waited" , "0" }, { "Tc_log_max_pages_used" , "0" }, { "Tc_log_page_size" , "0" }, { "Tc_log_page_waits" , "0" }, { "Threads_cached" , "0" }, { "Threads_connected" , proxy.global.vars["threads_connected"] }, { "Threads_created" , proxy.global.vars["threads_created"] }, { "Threads_running" , proxy.global.vars["threads_running"] }, { "Uptime" , proxy.global.vars["uptime"] }, { "Uptime_since_flush_status" , proxy.global.vars["uptime_since_flush_status"] } } } -- you can see all the variables we are modifying --[[ for var, value in pairs(proxy.global.vars) do print(var .. "=" .. value) end --]] print("Current value for Com_select " .. proxy.global.vars["com_select"]) return proxy.PROXY_SEND_RESULT elseif string.sub(packet, 2) == [[SELECT GROUP_CONCAT('\\\\\n* ', '\'',user,'\'@\'',host,'\'' ]] .. [[ORDER BY user, host) as user FROM mysql.user WHERE password='']] then proxy.response.type = proxy.MYSQLD_PACKET_OK proxy.response.resultset = { fields = { { type = proxy.MYSQL_TYPE_STRING, name = "users", }, }, rows = {} } -- we mock 700 users with no password local user user = [[\\]] .. "\n" .. [[* 'user_]] .. 1 .. [['@'%',]] for i = 2, 700 do user = user .. [[,\\]] .. "\n" .. [[* 'user_]] .. i .. [['@'%']] end -- incluse this 1 row in the result (this is a group_concat result) table.insert( proxy.response.resultset.rows, {user}) return proxy.PROXY_SEND_RESULT elseif string.sub(packet, 2) == [[SELECT GROUP_CONCAT('\\\\\n* ', '\'',user,'\'@\'',host,'\'' ORDER BY user,]] .. [[ host) AS user_spec FROM mysql.user WHERE user != 'root' AND (Select_priv =]] .. [[ 'Y' OR Insert_priv = 'Y' OR Update_priv = 'Y' OR Delete_priv = 'Y' OR]] .. [[ Create_priv = 'Y' OR Drop_priv = 'Y' OR Index_priv = 'Y' OR Alter_priv = 'Y')]] then proxy.response.type = proxy.MYSQLD_PACKET_OK proxy.response.resultset = { fields = { { type = proxy.MYSQL_TYPE_STRING, name = "user_spec", }, }, rows = {} } -- we mock 700 users with excessive privileges local user user = [[\\]] .. "\n" .. [[* 'user_]] .. 1 .. [['@'%',]] for i = 2, 700 do user = user .. [[,\\]] .. "\n" .. [[* 'user_]] .. i .. [['@'%']] end -- incluse this 1 row in the result (this is a group_concat result) table.insert( proxy.response.resultset.rows, {user}) return proxy.PROXY_SEND_RESULT elseif string.sub(packet, 2) == [[SELECT GROUP_CONCAT('\\\\\n* ', '\'',user,'\'@\'',host,'\'' ORDER BY]] .. [[ user, host) as user FROM mysql.user WHERE user !='root' AND (File_priv='Y']] .. [[ OR Process_priv='Y' OR Shutdown_priv='Y' OR Grant_priv='Y')]] then proxy.response.type = proxy.MYSQLD_PACKET_OK proxy.response.resultset = { fields = { { type = proxy.MYSQL_TYPE_STRING, name = "user", }, }, rows = {} } -- we mock 700 users with excessive privileges (2) local user user = [[\\]] .. "\n" .. [[* 'user_]] .. 1 .. [['@'%',]] for i = 2, 700 do user = user .. [[,\\]] .. "\n" .. [[* 'user_]] .. i .. [['@'%']] end -- incluse this 1 row in the result (this is a group_concat result) table.insert( proxy.response.resultset.rows, {user}) return proxy.PROXY_SEND_RESULT elseif string.sub(packet, 2) == [[SELECT GROUP_CONCAT('\\\\\n* ', '\'',d.user,'\'@\'',d.host,'\']] .. [[ on DB ', d.db ORDER BY d.user, d.host, d.db) AS user,]] .. [[ GROUP_CONCAT('\\\\\n* ', d.db ORDER BY d.db) AS db_name FROM]] .. [[ mysql.db d LEFT JOIN information_schema.schemata s ON]] .. [[ d.db=s.schema_name WHERE s.schema_name IS NULL ORDER BY d.user, d.db]] then proxy.response.type = proxy.MYSQLD_PACKET_OK proxy.response.resultset = { fields = { { type = proxy.MYSQL_TYPE_STRING, name = "user", }, { type = proxy.MYSQL_TYPE_STRING, name = "db_name", }, }, rows = {} } -- we mock 700 users access to databases that do not exist local user user = [[\\]] .. "\n" .. [[* 'user_]] .. 1 .. [['@'%']] for i = 2, 700 do user = user .. [[,\\]] .. "\n" .. [[* 'user_]] .. i .. [['@'%']] end local db db = [[\\]] .. "\n" .. [[* 'db_]] .. 1 ..[[']] for i = 2, 700 do db = db .. [[,\\]] .. "\n" .. [[* 'db_]] .. i .. [[']] end -- incluse this 1 row in the result (this is a group_concat result) table.insert( proxy.response.resultset.rows, {user,db}) return proxy.PROXY_SEND_RESULT elseif command == "show" and option == "master logs" then -- we mock SHOW MASTER LOGS proxy.response.type = proxy.MYSQLD_PACKET_OK proxy.response.resultset = { fields = { { type = proxy.MYSQL_TYPE_STRING, name = "Log_name", }, { type = proxy.MYSQL_TYPE_LONG, name = "File_size", } }, rows = {} } -- we mock proxy.global.vars["master_binlog_id"] -- (starting at 710) binlog files for i = 1, proxy.global.vars["master_binlog_id"] do table.insert( proxy.response.resultset.rows, {"binlog." .. i , i }) end -- we have our result, send it back return proxy.PROXY_SEND_RESULT --[[ ====================================================================== ]]-- end -- End of elseif trying to match up queries end end -- End of read_query() --[[ ====================================================================== ]]-- function read_query_result(inj) -- print(proxy.global.ismaster) -- print(inj.id .. " " .. inj.query) if (inj.id == 2 and inj.resultset.row_count == 0 and string.find(inj.query, "show slave status")) then proxy.global.ismaster = true return proxy.PROXY_IGNORE_RESULT elseif (inj.id == 1 and proxy.global.ismaster == true -- We are a master and string.find(inj.query, "SHOW MASTER STATUS") ) then -- we mock SHOW MASTER STATUS print("==> mocked master status") proxy.response.type = proxy.MYSQLD_PACKET_OK proxy.response.resultset = { fields = { { type = proxy.MYSQL_TYPE_STRING, name = "File", }, { type = proxy.MYSQL_TYPE_LONG, name = "Position", }, { type = proxy.MYSQL_TYPE_STRING, name = "Binlog_Do_DB", }, { type = proxy.MYSQL_TYPE_STRING, name = "Binlog_Ignore_DB", } }, rows = { {"binlog." .. proxy.global.vars["master_binlog_id"] , proxy.global.vars["master_binlog_id"], "", "" } } } return proxy.PROXY_SEND_RESULT elseif (inj.id == 1 and proxy.global.ismaster == false -- We are a slave and string.find(inj.query, "SHOW MASTER STATUS") ) then -- we mock SHOW MASTER STATUS print("==> mocked master status for a slave") proxy.response.type = proxy.MYSQLD_PACKET_OK proxy.response.resultset = { fields = { { type = proxy.MYSQL_TYPE_STRING, name = "File", }, { type = proxy.MYSQL_TYPE_LONG, name = "Position", }, { type = proxy.MYSQL_TYPE_STRING, name = "Binlog_Do_DB", }, { type = proxy.MYSQL_TYPE_STRING, name = "Binlog_Ignore_DB", } }, rows = { {"binlog." .. proxy.global.vars["master_binlog_id"] - 1 , proxy.global.vars["master_binlog_id"] - 100, "", "" } } } return proxy.PROXY_SEND_RESULT elseif (inj.id == 1 and proxy.global.ismaster == false and inj.resultset.row_count > 0 and string.find(inj.query, "SHOW SLAVE STATUS")) then local master_port = 0 for row in inj.resultset.rows do master_port = row[4] end -- We send a custom result for show slave status proxy.response.type = proxy.MYSQLD_PACKET_OK proxy.response.resultset = { fields = { { type = proxy.MYSQL_TYPE_STRING, name = "Slave_IO_State", }, { type = proxy.MYSQL_TYPE_STRING, name = "Master_Host", }, { type = proxy.MYSQL_TYPE_STRING, name = "Master_User", }, { type = proxy.MYSQL_TYPE_STRING, name = "Master_Port", }, { type = proxy.MYSQL_TYPE_STRING, name = "Connect_Retry", }, { type = proxy.MYSQL_TYPE_STRING, name = "Master_Log_File", }, { type = proxy.MYSQL_TYPE_STRING, name = "Read_Master_Log_Pos", }, { type = proxy.MYSQL_TYPE_STRING, name = "Relay_Log_File", }, { type = proxy.MYSQL_TYPE_STRING, name = "Relay_Log_Pos", }, { type = proxy.MYSQL_TYPE_STRING, name = "Relay_Master_Log_File", }, { type = proxy.MYSQL_TYPE_STRING, name = "Slave_IO_Running", }, { type = proxy.MYSQL_TYPE_STRING, name = "Slave_SQL_Running", }, { type = proxy.MYSQL_TYPE_STRING, name = "Replicate_Do_DB", }, { type = proxy.MYSQL_TYPE_STRING, name = "Replicate_Ignore_DB", }, { type = proxy.MYSQL_TYPE_STRING, name = "Replicate_Do_Table", }, { type = proxy.MYSQL_TYPE_STRING, name = "Replicate_Ignore_Table", }, { type = proxy.MYSQL_TYPE_STRING, name = "Replicate_Wild_Do_Table", }, { type = proxy.MYSQL_TYPE_STRING, name = "Replicate_Wild_Ignore_Table", }, { type = proxy.MYSQL_TYPE_STRING, name = "Last_Errno", }, { type = proxy.MYSQL_TYPE_STRING, name = "Last_Error", }, { type = proxy.MYSQL_TYPE_STRING, name = "Skip_Counter", }, { type = proxy.MYSQL_TYPE_STRING, name = "Exec_Master_Log_Pos", }, { type = proxy.MYSQL_TYPE_STRING, name = "Relay_Log_Space", }, { type = proxy.MYSQL_TYPE_STRING, name = "Until_Condition", }, { type = proxy.MYSQL_TYPE_STRING, name = "Until_Log_File", }, { type = proxy.MYSQL_TYPE_STRING, name = "Until_Log_Pos", }, { type = proxy.MYSQL_TYPE_STRING, name = "Master_SSL_Allowed", }, { type = proxy.MYSQL_TYPE_STRING, name = "Master_SSL_CA_File", }, { type = proxy.MYSQL_TYPE_STRING, name = "Master_SSL_CA_Path", }, { type = proxy.MYSQL_TYPE_STRING, name = "Master_SSL_Cert", }, { type = proxy.MYSQL_TYPE_STRING, name = "Master_SSL_Cipher", }, { type = proxy.MYSQL_TYPE_STRING, name = "Master_SSL_Key", }, { type = proxy.MYSQL_TYPE_STRING, name = "Seconds_Behind_Master", } }, rows = { { "Waiting for master to send event", "127", "slave", master_port + 2000, "60", "binlog." .. proxy.global.vars["master_binlog_id"] - 1, proxy.global.vars["master_binlog_id"] - 10, "binlog." .. proxy.global.vars["master_binlog_id"] - 2, proxy.global.vars["master_binlog_id"] - 100, "binlog." .. proxy.global.vars["master_binlog_id"] - 2, "Yes", "Yes", "", "", "", "", "", "", "0", "", "0", proxy.global.vars["master_binlog_id"] - 10, proxy.global.vars["master_binlog_id"] - 100, "None", "", "0", "No", "", "", "", "", "", "10" } } } return proxy.PROXY_SEND_RESULT end end