--[[ $%BEGINLICENSE%$
Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved.
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., 51 Franklin St, Fifth Floor, Boston, MA
02110-1301 USA
$%ENDLICENSE%$ --]]
--[[
--]]
--
-- Debug
--
---
-- read_query() gets the client query before it reaches the server
--
-- we want to inject the query be able to dump its content in the
-- read_query_result() call
--
-- @see read_query_result
function read_query( packet )
proxy.queries:append(1, packet, {resultset_is_needed = true } )
return proxy.PROXY_SEND_QUERY
end
--- dump the result-set to stdout
--
-- @param inj "packet.injection"
local function dump_query_result( inj )
local field_count = 0
local fields = inj.resultset.fields
while fields[field_count] do
local field = fields[field_count]
print("| | field[" .. field_count .. "] = { type = " ..
field.type .. ", name = " .. field.name .. " }" )
field_count = field_count + 1
end
local row_count = 0
for row in inj.resultset.rows do
local cols = {}
local o
for i = 1, field_count do
if not o then
o = ""
else
o = o .. ", "
end
if not row[i] then
o = o .. "(nul)"
else
o = o .. row[i]
end
end
print("| | row["..row_count.."] = { " .. o .. " }")
row_count = row_count + 1
end
end
--- dump the connection data at startup
--
local function dump_connection()
print(".== connection ")
cur_backend_ndx = assert(proxy.connection["backend_ndx"])
cur_backend = proxy.global.backends[cur_backend_ndx]
print("| backend[ndx] = " .. cur_backend_ndx)
print("| connected_clients = " .. cur_backend["connected_clients"])
print("| address = " .. cur_backend["address"])
print("| server-version = " .. proxy.connection.server["mysqld_version"])
print("| default-db = " .. proxy.connection.server["default_db"])
print("| thread-id = " .. proxy.connection.server["thread_id"])
print("'== ")
end
--
-- map the constants to strings
-- lua starts at 1
local command_names = {
"COM_SLEEP",
"COM_QUIT",
"COM_INIT_DB",
"COM_QUERY",
"COM_FIELD_LIST",
"COM_CREATE_DB",
"COM_DROP_DB",
"COM_REFRESH",
"COM_SHUTDOWN",
"COM_STATISTICS",
"COM_PROCESS_INFO",
"COM_CONNECT",
"COM_PROCESS_KILL",
"COM_DEBUG",
"COM_PING",
"COM_TIME",
"COM_DELAYED_INSERT",
"COM_CHANGE_USER",
"COM_BINLOG_DUMP",
"COM_TABLE_DUMP",
"COM_CONNECT_OUT",
"COM_REGISTER_SLAVE",
"COM_STMT_PREPARE",
"COM_STMT_EXECUTE",
"COM_STMT_SEND_LONG_DATA",
"COM_STMT_CLOSE",
"COM_STMT_RESET",
"COM_SET_OPTION",
"COM_STMT_FETCH",
"COM_DAEMON"
}
local prepared_queries = {}
local function str2hex(str)
local raw_len = string.len(str)
local i = 1
local o = ""
while i <= raw_len do
o = o .. string.format(" %02x", string.byte(str, i))
i = i + 1
end
return o
end
local function decode_query_packet( packet )
-- we don't have the packet header in the
packet_len = string.len(packet)
print("| query.len = " .. packet_len)
print("| query.packet =" .. str2hex(packet))
-- print("(decode_query) " .. "| packet-id = " .. "(unknown)")
print("| .--- query")
print("| | command = " .. command_names[string.byte(packet) + 1])
if string.byte(packet) == proxy.COM_QUERY then
-- after the COM_QUERY comes the query
print("| | query = " .. string.format("%q", string.sub(packet, 2)))
elseif string.byte(packet) == proxy.COM_INIT_DB then
print("| | db = " .. string.format("%q", string.sub(packet, 2)))
elseif string.byte(packet) == proxy.COM_STMT_PREPARE then
print("| | query = " .. string.format("%q", string.sub(packet, 2)))
elseif string.byte(packet) == proxy.COM_STMT_EXECUTE then
local stmt_handler_id = string.byte(packet, 2) + (string.byte(packet, 3) * 256) + (string.byte(packet, 4) * 256 * 256) + (string.byte(packet, 5) * 256 * 256 * 256)
local flags = string.byte(packet, 6)
local iteration_count = string.byte(packet, 7) + (string.byte(packet, 8) * 256) + (string.byte(packet, 9) * 256 * 256) + (string.byte(packet, 10) * 256 * 256 * 256)
print("| | stmt-id = " .. stmt_handler_id )
print("| | flags = " .. string.format("%02x", flags) )
print("| | iteration_count = " .. iteration_count )
if packet_len > 10 then
-- if we don't have any place-holders, no for NUL and friends
local nul_bitmap = string.byte(packet, 11)
local new_param = string.byte(packet, 12)
print("| | nul_bitmap = " .. string.format("%02x", nul_bitmap ))
print("| | new_param = " .. new_param )
else
print("| | (no params)")
end
print("| | prepared-query = " .. prepared_queries[stmt_handler_id] )
else
print("| | packet =" .. str2hex(packet))
end
print("| '---")
end
---
-- read_query_result() is called when we receive a query result
-- from the server
--
-- we try to dump everything we know about this query
-- * the query
-- * the exec-time
-- * the result-set
-- * the query-status
--
--
function read_query_result( inj )
-- the query
-- the result-set
local res = assert(inj.resultset)
local packet = assert(inj.query)
local raw_len = assert(res.raw):len()
local flags = res.flags
dump_connection()
print(".--- mysql query")
decode_query_packet(packet)
print("|")
print("| result.len = " .. raw_len)
print("| result.packet =" .. str2hex(res.raw))
print("| result.flags = { in_trans = " .. tostring(flags.in_trans) .. ", " ..
"auto_commit = " .. tostring(flags.auto_commit) .. ", " ..
"no_good_index_used = " ..tostring( flags.no_good_index_used ) .. ", " ..
"no_index_used = " .. tostring(flags.no_index_used) .. " }")
print("| result.warning_count = " .. res.warning_count)
if res.affected_rows then
print("| result.affected_rows = " .. res.affected_rows)
print("| result.insert_id = " .. res.insert_id)
end
if res.query_status then
print("| result.query_status = " .. res.query_status)
end
print("| query_time = " .. inj.query_time .. "us")
print("| response_time = " .. inj.response_time .. "us")
if res.query_status == proxy.MYSQLD_PACKET_ERR then
print("| result.err.code = " .. res.raw:byte(2) + (res.raw:byte(3) * 256))
print("| result.err.sql_state = " .. string.format("%q", res.raw:sub(5, 9)))
print("| result.err.msg = " .. string.format("%q", res.raw:sub(10)))
else
print("| .--- result-set")
print("| | command = " .. command_names[string.byte(packet) + 1])
if string.byte(packet) == proxy.COM_STMT_PREPARE then
assert(string.byte(res.raw, 1) == 0, string.format("packet[0] should be 0, is %02x", string.byte(res.raw, 1)))
local stmt_handler_id = string.byte(res.raw, 2) + (string.byte(res.raw, 3) * 256) + (string.byte(res.raw, 4) * 256 * 256) + (string.byte(res.raw, 5) * 256 * 256 * 256)
local num_cols = string.byte(res.raw, 6) + (string.byte(res.raw, 7) * 256)
local num_params = string.byte(res.raw, 8) + (string.byte(res.raw, 9) * 256)
print("| | stmt-id = " .. stmt_handler_id )
print("| | num-cols = " .. num_cols )
print("| | num-params = " .. num_params )
if raw_len >= 12 then
local num_params = string.byte(res.raw, 11) + (string.byte(res.raw, 12) * 256)
print("| | (5.0) warning-count = " .. num_params )
end
-- track the prepared query
prepared_queries[stmt_handler_id] = string.sub(packet, 2)
elseif string.byte(packet) == proxy.COM_STMT_EXECUTE or
string.byte(packet) == proxy.COM_QUERY then
local num_cols = string.byte(res.raw, 1)
print("| | num-cols = " .. num_cols)
if num_cols > 0 and num_cols < 255 then
dump_query_result(inj)
end
else
print("| | client-packet =" .. str2hex(res.raw))
end
print("| '---")
end
print("'---")
-- end
end