webmcp
view libraries/mondelefant/mondelefant_atom_connector.lua @ 142:a686ed2ce967
Protect json.import(...) against Lua stack overflows (or integer overflows) due to too many nested levels
| author | jbe | 
|---|---|
| date | Wed Jul 30 02:01:24 2014 +0200 (2014-07-30) | 
| parents | 6b435d3c0b14 | 
| children | 8d7665e0d490 | 
 line source
     1 #!/usr/bin/env lua
     3 local _G             = _G
     4 local _VERSION       = _VERSION
     5 local assert         = assert
     6 local error          = error
     7 local getmetatable   = getmetatable
     8 local ipairs         = ipairs
     9 local next           = next
    10 local pairs          = pairs
    11 local print          = print
    12 local rawequal       = rawequal
    13 local rawget         = rawget
    14 local rawlen         = rawlen
    15 local rawset         = rawset
    16 local select         = select
    17 local setmetatable   = setmetatable
    18 local tonumber       = tonumber
    19 local tostring       = tostring
    20 local type           = type
    22 local math      = math
    23 local string    = string
    24 local table     = table
    26 local mondelefant = require("mondelefant")
    27 local atom        = require("atom")
    29 local _M = {}
    30 if _ENV then
    31   _ENV = _M
    32 else
    33   _G[...] = _M
    34   setfenv(1, _M)
    35 end
    38 input_converters = setmetatable({}, { __mode = "k" })
    40 input_converters["boolean"] = function(conn, value)
    41   if value then return "TRUE" else return "FALSE" end
    42 end
    44 input_converters["number"] = function(conn, value)
    45   local str = tostring(value)
    46   if string.find(str, "^[0-9%.e%-]+$") then
    47     return str
    48   else
    49     return "'NaN'"
    50   end
    51 end
    53 input_converters[atom.fraction] = function(conn, value)
    54   if value.invalid then
    55     return "'NaN'"
    56   else
    57     local n, d = tostring(value.numerator), tostring(value.denominator)
    58     if string.find(n, "^%-?[0-9]+$") and string.find(d, "^%-?[0-9]+$") then
    59       return "(" .. n .. "::numeric / " .. d .. "::numeric)"
    60     else
    61       return "'NaN'"
    62     end
    63   end
    64 end
    66 input_converters[atom.date] = function(conn, value)
    67   return conn:quote_string(tostring(value)) .. "::date"
    68 end
    70 input_converters[atom.timestamp] = function(conn, value)
    71   return conn:quote_string(tostring(value))  -- don't define type
    72 end
    74 input_converters[atom.time] = function(conn, value)
    75   return conn:quote_string(tostring(value)) .. "::time"
    76 end
    79 output_converters = setmetatable({}, { __mode = "k" })
    81 output_converters.int8 = function(str) return atom.integer:load(str) end
    82 output_converters.int4 = function(str) return atom.integer:load(str) end
    83 output_converters.int2 = function(str) return atom.integer:load(str) end
    85 output_converters.numeric = function(str) return atom.number:load(str) end
    86 output_converters.float4  = function(str) return atom.number:load(str) end
    87 output_converters.float8  = function(str) return atom.number:load(str) end
    89 output_converters.bool = function(str) return atom.boolean:load(str) end
    91 output_converters.date = function(str) return atom.date:load(str) end
    93 local timestamp_loader_func = function(str)
    94   local year, month, day, hour, minute, second = string.match(
    95     str,
    96     "^([0-9][0-9][0-9][0-9])%-([0-9][0-9])%-([0-9][0-9]) ([0-9]?[0-9]):([0-9][0-9]):([0-9][0-9])"
    97   )
    98   if year then
    99     return atom.timestamp{
   100       year   = tonumber(year),
   101       month  = tonumber(month),
   102       day    = tonumber(day),
   103       hour   = tonumber(hour),
   104       minute = tonumber(minute),
   105       second = tonumber(second)
   106     }
   107   else
   108     return atom.timestamp.invalid
   109   end
   110 end
   111 output_converters.timestamp = timestamp_loader_func
   112 output_converters.timestamptz = timestamp_loader_func
   114 local time_loader_func = function(str)
   115   local hour, minute, second = string.match(
   116     str,
   117     "^([0-9]?[0-9]):([0-9][0-9]):([0-9][0-9])"
   118   )
   119   if hour then
   120     return atom.time{
   121       hour   = tonumber(hour),
   122       minute = tonumber(minute),
   123       second = tonumber(second)
   124     }
   125   else
   126     return atom.time.invalid
   127   end
   128 end
   129 output_converters.time = time_loader_func
   130 output_converters.timetz = time_loader_func
   132 mondelefant.postgresql_connection_prototype.type_mappings = {
   133   int8 = atom.integer,
   134   int4 = atom.integer,
   135   int2 = atom.integer,
   136   bool = atom.boolean,
   137   date = atom.date,
   138   timestamp = atom.timestamp,
   139   time = atom.time,
   140   text = atom.string,
   141   varchar = atom.string,
   142 }
   145 function mondelefant.postgresql_connection_prototype.input_converter(conn, value, info)
   146   if value == nil then
   147     return "NULL"
   148   else
   149     local converter =
   150       input_converters[getmetatable(value)] or
   151       input_converters[type(value)]
   152     if converter then
   153       return converter(conn, value)
   154     else
   155       return conn:quote_string(tostring(value))
   156     end
   157   end
   158 end
   160 function mondelefant.postgresql_connection_prototype.output_converter(conn, value, info)
   161   if value == nil then
   162     return nil
   163   else
   164     local converter = output_converters[info.type]
   165     if converter then
   166       return converter(value)
   167     else
   168       return value
   169     end
   170   end
   171 end
   173 return _M
   176 --[[
   178 db = assert(mondelefant.connect{engine='postgresql', dbname='test'})
   179 result = db:query{'SELECT ? + 1', atom.date{ year=1999, month=12, day=31}}
   180 print(result[1][1].year)
   182 --]]
