--[[ $%BEGINLICENSE%$
 Copyright (c) 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%$ --]]
---
-- map SQL commands to the hidden MySQL Protocol commands
--
-- some protocol commands are only available through the mysqladmin tool like
-- * ping
-- * shutdown
-- * debug
-- * statistics
--
-- ... while others are avaible
-- * process info (SHOW PROCESS LIST)
-- * process kill (KILL <id>)
-- 
-- ... and others are ignored
-- * time
-- 
-- that way we can test MySQL Servers more easily with "mysqltest"
--


--- 
-- recognize special SQL commands and turn them into COM_* sequences
--
function read_query(packet)
    if packet:byte() ~= proxy.COM_QUERY then return end

    if packet:sub(2) == "COMMIT SUICIDE" then
        proxy.queries:append(proxy.COM_SHUTDOWN, string.char(proxy.COM_SHUTDOWN), { resultset_is_needed = true })
        return proxy.PROXY_SEND_QUERY
    elseif packet:sub(2) == "PING" then
        proxy.queries:append(proxy.COM_PING, string.char(proxy.COM_PING), { resultset_is_needed = true })
        return proxy.PROXY_SEND_QUERY
    elseif packet:sub(2) == "STATISTICS" then
        proxy.queries:append(proxy.COM_STATISTICS, string.char(proxy.COM_STATISTICS), { resultset_is_needed = true })
        return proxy.PROXY_SEND_QUERY
    elseif packet:sub(2) == "PROCINFO" then
        proxy.queries:append(proxy.COM_PROCESS_INFO, string.char(proxy.COM_PROCESS_INFO), { resultset_is_needed = true })
        return proxy.PROXY_SEND_QUERY
    elseif packet:sub(2) == "TIME" then
        proxy.queries:append(proxy.COM_TIME, string.char(proxy.COM_TIME), { resultset_is_needed = true })
        return proxy.PROXY_SEND_QUERY
    elseif packet:sub(2) == "DEBUG" then
        proxy.queries:append(proxy.COM_DEBUG, string.char(proxy.COM_DEBUG), { resultset_is_needed = true })
        return proxy.PROXY_SEND_QUERY
    elseif packet:sub(2) == "PROCKILL" then
        proxy.queries:append(proxy.COM_PROCESS_KILL, string.char(proxy.COM_PROCESS_KILL), { resultset_is_needed = true })
        return proxy.PROXY_SEND_QUERY
    elseif packet:sub(2) == "SETOPT" then
        proxy.queries:append(proxy.COM_SET_OPTION, string.char(proxy.COM_SET_OPTION), { resultset_is_needed = true })
        return proxy.PROXY_SEND_QUERY
    elseif packet:sub(2) == "BINLOGDUMP" then
        proxy.queries:append(proxy.COM_BINLOG_DUMP, string.char(proxy.COM_BINLOG_DUMP), { resultset_is_needed = true })
        return proxy.PROXY_SEND_QUERY
    elseif packet:sub(2) == "BINLOGDUMP1" then
        proxy.queries:append(proxy.COM_BINLOG_DUMP, 
            string.char(proxy.COM_BINLOG_DUMP) ..
            "\004\000\000\000" ..
            "\000\000" ..
            "\002\000\000\000" ..
            "\000" .. 
            ""
            , { resultset_is_needed = true })
        return proxy.PROXY_SEND_QUERY
    elseif packet:sub(2) == "REGSLAVE" then
        proxy.queries:append(proxy.COM_REGISTER_SLAVE, string.char(proxy.COM_REGISTER_SLAVE), { resultset_is_needed = true })
        return proxy.PROXY_SEND_QUERY
    elseif packet:sub(2) == "REGSLAVE1" then
        proxy.queries:append(proxy.COM_REGISTER_SLAVE, 
            string.char(proxy.COM_REGISTER_SLAVE) .. 
            "\001\000\000\000" .. -- server-id
            "\000" .. -- report-host
            "\000" .. -- report-user
            "\000" .. -- report-password ?
            "\001\000" .. -- our port
            "\000\000\000\000" .. -- recovery rank
            "\001\000\000\000" .. -- master id ... what ever that is
            ""
            , { resultset_is_needed = true }) 
        return proxy.PROXY_SEND_QUERY
    elseif packet:sub(2) == "PREP" then
        proxy.queries:append(proxy.COM_STMT_PREPARE, string.char(proxy.COM_STMT_PREPARE), { resultset_is_needed = true })
        return proxy.PROXY_SEND_QUERY
    elseif packet:sub(2) == "PREP1" then
        proxy.queries:append(proxy.COM_STMT_PREPARE, string.char(proxy.COM_STMT_PREPARE) .. "SELECT ?", { resultset_is_needed = true })
        return proxy.PROXY_SEND_QUERY
    elseif packet:sub(2) == "EXEC" then
        proxy.queries:append(proxy.COM_STMT_EXECUTE, string.char(proxy.COM_STMT_EXECUTE), { resultset_is_needed = true })
        return proxy.PROXY_SEND_QUERY
    elseif packet:sub(2) == "EXEC1" then
        proxy.queries:append(proxy.COM_STMT_EXECUTE, 
            string.char(proxy.COM_STMT_EXECUTE) .. 
            "\001\000\000\000" .. -- stmt-id
            "\000" .. -- flags
            "\001\000\000\000" .. -- iteration count
            "\000"             .. -- null-bits
            "\001"             .. -- new-parameters
            "\000\254" ..
            "\004" .. "1234" ..
            "", { resultset_is_needed = true })
        return proxy.PROXY_SEND_QUERY
    elseif packet:sub(2) == "DEAL" then
        proxy.queries:append(proxy.COM_STMT_CLOSE, string.char(proxy.COM_STMT_CLOSE), { resultset_is_needed = true })
        return proxy.PROXY_SEND_QUERY
    elseif packet:sub(2) == "DEAL1" then
        proxy.queries:append(proxy.COM_STMT_CLOSE, string.char(proxy.COM_STMT_CLOSE) .. "\001\000\000\000", { resultset_is_needed = true })
        return proxy.PROXY_SEND_QUERY
    elseif packet:sub(2) == "RESET" then
        proxy.queries:append(proxy.COM_STMT_RESET, string.char(proxy.COM_STMT_RESET), { resultset_is_needed = true })
        return proxy.PROXY_SEND_QUERY
    elseif packet:sub(2) == "RESET1" then
        proxy.queries:append(proxy.COM_STMT_RESET, string.char(proxy.COM_STMT_RESET) .. "\001\000\000\000", { resultset_is_needed = true })
        return proxy.PROXY_SEND_QUERY
    elseif packet:sub(2) == "FETCH" then
        proxy.queries:append(proxy.COM_STMT_FETCH, string.char(proxy.COM_STMT_FETCH), { resultset_is_needed = true })
        return proxy.PROXY_SEND_QUERY
    elseif packet:sub(2) == "FETCH1" then
        proxy.queries:append(proxy.COM_STMT_FETCH, string.char(proxy.COM_STMT_FETCH) .. "\001\000\000\000" .. "\128\000\000\000", { resultset_is_needed = true })
        return proxy.PROXY_SEND_QUERY
    elseif packet:sub(2) == "FLIST" then
        proxy.queries:append(proxy.COM_FIELD_LIST, string.char(proxy.COM_FIELD_LIST), { resultset_is_needed = true })
        return proxy.PROXY_SEND_QUERY
    elseif packet:sub(2) == "FLIST1" then
        proxy.queries:append(proxy.COM_FIELD_LIST, string.char(proxy.COM_FIELD_LIST) .. "t1\000id\000\000\000", { resultset_is_needed = true })
        return proxy.PROXY_SEND_QUERY
    elseif packet:sub(2) == "TDUMP" then
        proxy.queries:append(proxy.COM_TABLE_DUMP, string.char(proxy.COM_TABLE_DUMP), { resultset_is_needed = true })
        return proxy.PROXY_SEND_QUERY
    elseif packet:sub(2) == "TDUMP1" then
        proxy.queries:append(proxy.COM_TABLE_DUMP, string.char(proxy.COM_TABLE_DUMP) .. "\004test\002t1", { resultset_is_needed = true })
        return proxy.PROXY_SEND_QUERY
    elseif packet:sub(2) == "TDUMP2" then
        proxy.queries:append(proxy.COM_TABLE_DUMP, string.char(proxy.COM_TABLE_DUMP) .. "\004test\002t2", { resultset_is_needed = true })
        return proxy.PROXY_SEND_QUERY
    end
end


---
-- adjust the response to match the needs of COM_QUERY 
-- where neccesary
--
-- * some commands return EOF (COM_SHUTDOWN), 
-- * some are plain-text (COM_STATISTICS)
--
-- in the end the client sent us a COM_QUERY and we have to hide
-- all those specifics
function read_query_result(inj)

    if inj.id == proxy.COM_SHUTDOWN or
       inj.id == proxy.COM_SET_OPTION or
       inj.id == proxy.COM_BINLOG_DUMP or
       inj.id == proxy.COM_STMT_PREPARE or
       inj.id == proxy.COM_STMT_FETCH or
       inj.id == proxy.COM_FIELD_LIST or
       inj.id == proxy.COM_TABLE_DUMP or
       inj.id == proxy.COM_DEBUG then
        -- translate the EOF packet from the COM_SHUTDOWN into a OK packet
        -- to match the needs of the COM_QUERY we got
        if inj.resultset.raw:byte() ~= 255 then
            proxy.response = {
                type = proxy.MYSQLD_PACKET_OK,
            }
            return proxy.PROXY_SEND_RESULT
        end
    elseif inj.id == proxy.COM_PING or
           inj.id == proxy.COM_TIME or
           inj.id == proxy.COM_PROCESS_KILL or
           inj.id == proxy.COM_REGISTER_SLAVE or
           inj.id == proxy.COM_STMT_EXECUTE or
           inj.id == proxy.COM_STMT_RESET or
           inj.id == proxy.COM_PROCESS_INFO then
        -- no change needed
    elseif inj.id == proxy.COM_STATISTICS then
        -- the response a human readable plain-text
        --
        -- just turn it into a proper result-set
        proxy.response = {
            type = proxy.MYSQLD_PACKET_OK,
            resultset = {
                fields = {
                    { name = "statisitics" }
                },
                rows = {
                    { inj.resultset.raw }
                }
            }
        }
        return proxy.PROXY_SEND_RESULT

    else
        -- we don't know them yet, just return ERR to the client to
        -- match the needs of COM_QUERY
        print(("got: %q"):format(inj.resultset.raw))
        proxy.response = {
            type = proxy.MYSQLD_PACKET_ERR,
        }
        return proxy.PROXY_SEND_RESULT
    end
end

