--[[ $%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


