Skip to content

Instantly share code, notes, and snippets.

@fmpwizard
Created January 31, 2015 03:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fmpwizard/61b9c4091c5b355be82a to your computer and use it in GitHub Desktop.
Save fmpwizard/61b9c4091c5b355be82a to your computer and use it in GitHub Desktop.
mysql proxy lua file database key value store with replication
--[[ $%BEGINLICENSE%$
Copyright (C) 2009 MySQL AB, 2009 Sun Microsystems, Inc
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
$%ENDLICENSE%$ --]]
-- Updated with emulation of mysql server
-- To make query parsing easier
local tokenizer = require("proxy.tokenizer")
-- We assign the value of the same table to itself
-- or initialize it if not existent
proxy.global.db = proxy.global.db or {}
--[[ ====================================================================== ]]--
function packet_auth(fields)
fields = fields or { }
return "\010" .. -- proto version
(fields.version or "5.0.45-proxy") .. -- version
"\000" .. -- term-null
"\001\000\000\000" .. -- thread-id
"\065\065\065\065" ..
"\065\065\065\065" .. -- challenge - part I
"\000" .. -- filler
"\001\130" .. -- server cap (long pass, 4.1 proto)
"\008" .. -- charset
"\002\000" .. -- status
("\000"):rep(13) .. -- filler
"\065\065\065\065"..
"\065\065\065\065"..
"\065\065\065\065"..
"\000" -- challenge - part II
end
--[[ ====================================================================== ]]--
function connect_server()
-- emulate a server
proxy.response = {
type = proxy.MYSQLD_PACKET_RAW,
packets = {
packet_auth()
}
}
return proxy.PROXY_SEND_RESULT
end
--[[ ====================================================================== ]]--
function read_query( packet )
if string.byte(packet) == proxy.COM_QUERY then
-- We tokenize the query
local tokens = tokenizer.tokenize(packet:sub(2))
-- We loop over the query
for i = 1, #tokens do
-- print the token and what we know about it
local token = tokens[i]
-- print(i .. ": " .. " { " .. token["token_name"] .. ", " .. token["text"] .. " }" )
-- Based on the tokens we find, do something
if token["token_name"] == 'TK_SQL_SELECT'
and tokens[i + 1]["token_name"] == 'TK_STAR' then
return show_all()
elseif token["token_name"] == 'TK_SQL_SELECT' then
-- we pass the text of the next token
return get(tokens[i + 1]["text"])
elseif token["token_name"] == 'TK_SQL_INSERT' then
-- we pass the text of the next token and we skip
-- the equal sign
return add(tokens[i + 1]["text"], tokens[i + 3]["text"])
elseif token["token_name"] == 'TK_SQL_DELETE' then
-- we pass the text of the next token
return delete(tokens[i + 1]["text"])
elseif token["token_name"] == 'TK_SQL_DROP' then
-- TK_SQL_TRUNCATE does not exist (need to file a bug on it)
-- We do not need any parameter for this one
return truncate()
else
-- Unkown query
return error_result (
"I haven't learnt how to handle that query"
, '101'
, '!101')
end
end
end
end -- End of read_query()
--[[ ====================================================================== ]]--
function error_result (msg, code, state)
proxy.response = {
type = proxy.MYSQLD_PACKET_ERR,
errmsg = msg,
errcode = code,
sqlstate = state,
}
return proxy.PROXY_SEND_RESULT
end
--[[ ====================================================================== ]]--
function get( key )
-- if the key is not found, return an error
if proxy.global.db[key] == nil then
return error_result(
'No value found for key "' .. key .. '"' , -- error message
100, -- error code
'!100' -- SQL state
)
end
proxy.response.type = proxy.MYSQLD_PACKET_OK
proxy.response.resultset = {
fields = {
{ type = proxy.MYSQL_TYPE_STRING, name = "key", },
{ type = proxy.MYSQL_TYPE_STRING, name = "value", }
},
rows = {}
}
-- Add the result to a nice mysql resulset
table.insert(
proxy.response.resultset.rows,
{ key , proxy.global.db[key] })
return proxy.PROXY_SEND_RESULT
end
--[[ ====================================================================== ]]--
function add( key, value )
-- We add the key value pair to the global table
proxy.global.db[key] = value
-- we return a nice "affected rows count"
proxy.response.type = proxy.MYSQLD_PACKET_OK
proxy.response.affected_rows = 1
proxy.response.insert_id = 0
return proxy.PROXY_SEND_RESULT
end
--[[ ====================================================================== ]]--
function show_all()
-- the more key => value pairs you have, the slower this
-- will be
-- * Values are not retrieved on the same order they were inserted
proxy.response.type = proxy.MYSQLD_PACKET_OK
proxy.response.resultset = {
fields = {
{ type = proxy.MYSQL_TYPE_STRING, name = "key", },
{ type = proxy.MYSQL_TYPE_STRING, name = "value", }
},
rows = {}
}
for k,v in pairs(proxy.global.db) do
table.insert(
proxy.response.resultset.rows,
{ k , v })
end
return proxy.PROXY_SEND_RESULT
end
--[[ ====================================================================== ]]--
function truncate()
-- simple way to truncate the table
proxy.global.db = {}
-- we return a nice "affected rows count"
proxy.response.type = proxy.MYSQLD_PACKET_OK
proxy.response.affected_rows = 0
proxy.response.insert_id = 0
return proxy.PROXY_SEND_RESULT
end
--[[ ====================================================================== ]]--
function delete( key )
-- using table.remove only works with numeric indexes :(
proxy.global.db[key] = nil
-- we return a nice "affected rows count"
proxy.response.type = proxy.MYSQLD_PACKET_OK
proxy.response.affected_rows = 1
proxy.response.insert_id = 0
return proxy.PROXY_SEND_RESULT
end
--[[ ====================================================================== ]]--
--[[
How to use:
It supports 3 types of queries
mysql> INSERT "key" = "value";
mysql> SELECT "key";
mysql> DELETE "key";
mysql> SELECT *;
mysql> DROP;
--]]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment