ZNZNCOOP

dbms.lua

Mar 17th, 2016
132
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. ----------------------------------------------------
  2. -- Система управления базами данных от Zer0Galaxy --
  3. ----------------------------------------------------
  4. local DBpath,port,password
  5. do
  6.   local cfgFileName="/etc/dbms.cfg"
  7.   local env = {}
  8.   local config = loadfile(cfgFileName, nil, env)
  9.   if config then
  10.     pcall(config)
  11.     DBpath=env.DBpath
  12.     port=env.port
  13.     password=env.password
  14.   else
  15.     print("Ошибка открытия файла конфигурации '"..cfgFileName.."'") return
  16.   end  
  17. end
  18.  
  19. if not DBpath then print("В файле конфигурации не задан путь к базам данных") return end
  20. local fs=require("filesystem")
  21. if not fs.isDirectory(DBpath) then
  22.   local ok,err=fs.makeDirectory(DBpath)
  23.   if not ok then print("Ошибка создания дирректории '"..DBpath.."' ",err) return end
  24. end
  25.  
  26. local event=require("event")
  27. local pushSignal = require("computer").pushSignal
  28. local ser=require("serialization").serialize
  29. local uns=require("serialization").unserialize
  30. local sig_request="mysql_request"
  31. local sig_ansver ="mysql_ansver"
  32.  
  33. local sessions={}
  34. local currentID
  35. -------------------------------------------------------------
  36. local errors={
  37. [0]="Query OK, ",
  38. [1]="Ошибка в синтаксисе SQL-запроса; ",
  39. }
  40. local types={ --Разрешенные типы данных
  41.   tinyint="number", smallint="number", mediumint="number", int="number", --числовые
  42.   char="string", varchar="string", text="string", --строковые
  43.   bool="boolean", boolean="boolean" --булевые
  44. }
  45.  
  46. local DBs={} --Открытые базы данных
  47. function saveDB(name, row_num)
  48.   local file,err=io.open(DBpath..name,"w")
  49.   if not file then return false, "Ошибка создания базы данных "..name.."; "..err end
  50.   file:write("db="..ser(DBs[name]))
  51.   file:close()
  52.   return true,errors[0]..(row_num and "строк затронуто "..row_num or "")
  53. end
  54.  
  55. function loadDB(name)
  56.   DBs[name]=nil
  57.   local env = {}
  58.   local db = loadfile(DBpath..name, nil, env)
  59.   if db then
  60.     pcall(db)
  61.     DBs[name]=env.db
  62.   else
  63.     return false, "База данных "..name.." не существует"
  64.   end  
  65.   if type(DBs[name])=="table" then return true end
  66.   return false, "Ошибка чтения базы данных "..name
  67. end
  68. -------------------------------------------------------------
  69. funcs={
  70. version=function() return "1.0 OpenSQL" end,
  71. }
  72. -------------------------------------------------------------
  73. --http://www.site-do.ru/db/db.php
  74. local query={}
  75. local function currentDB()
  76.   if not sessions[currentID].DBname then return false, "База данных не выбрана" end
  77.   local DB=DBs[sessions[currentID].DBname]
  78.   if not DB then
  79.     local ok,err=loadDB(sessions[currentID].DBname)
  80.     if not ok then return false,err end
  81.     DB=DBs[sessions[currentID].DBname]
  82.   end
  83.   return DB
  84. end
  85.  
  86. function query.create(data)
  87.   local item,name,filds=tostring(data):match("(%S+)%s*(%S+)%s*(.*)")
  88.   if item=="database" then
  89.     if fs.exists(DBpath..name) then return false, "База данных "..name.." уже существует;" end
  90.     DBs[name]={}
  91.     return saveDB(name)
  92.   elseif item=="table" then
  93.     if not sessions[currentID].DBname then return false, "База данных не выбрана" end
  94.     local DB=DBs[sessions[currentID].DBname]
  95.     if not DB then
  96.       local ok,err=loadDB(sessions[currentID].DBname)
  97.       if not ok then return false,err end
  98.       DB=DBs[sessions[currentID].DBname]
  99.     end
  100.     if DB[name] then return false, "Таблица '"..name.."' уже существует" end
  101.     filds=filds:match("%((.+)%)")
  102.     if not filds then return false, errors[1] end
  103.     filds=filds..","
  104. --  print(filds)
  105.     local tab={name={}, type={}, default={}, extra={}}
  106.     for f_name, f_type, f_params in filds:gmatch("([_%w]+)%s+([_%w]+)%s*(.-),") do
  107. --  print(f_name,f_type,f_params)
  108.     --[[
  109.       name - название колонки
  110. --      table - название таблицы, которой принадлежит колонка
  111. --      max_length - максимальная длинна содержания
  112.       not_null - 1, если колонка не может быть равна NULL
  113.       primary_key - 1, если колонка -- первичный индекс
  114.       unique_key - 1, если колона -- уникальный индекс
  115.       multiple_key - 1, если колонка -- не уникальный индекс
  116. --      numeric - 1, если колонка численная
  117. --      blob - 1, если колонка -- BLOB
  118.       type - тип колонки
  119. --      unsigned - 1, если колонка строго положительная (unsigned)
  120. --      zerofill - 1, если колонка заполняется нулями (zero-filled)]]
  121.       table.insert(tab.name,f_name)
  122.       if types[f_type] then table.insert(tab.type,types[f_type])
  123.       else return false, errors[1]..","..f_type.."'"
  124.       end
  125.       table.insert(tab.extra,f_params)
  126.     end
  127.     DB[name]=tab
  128.     return saveDB(sessions[currentID].DBname)
  129.   else
  130.     return false, errors[1]..(item or "")
  131.   end
  132. end
  133.  
  134. function query.select(data)
  135.   data=tostring(data) or ""
  136.   local result={}
  137.   local fields,tab,cond,order_by,desc
  138.   -- сортировка по убыванию ORDER BY field DESC
  139.   fields,order_by=data:match("^%s*(.+)%s+order%s+by%s+(.+)%s+desc%s*$")
  140.   if fields then
  141.     data=fields
  142.     desc=true
  143.   else -- сортировка по возрастанию ORDER BY field
  144.     fields,order_by=data:match("^%s*(.+)%s+order%s+by%s+(.+)%s*$")
  145.     if fields then data=fields end
  146.   end
  147.   -- выбор по условию WHERE condition
  148.   fields,cond=data:match("^%s*(.-)%s+where%s+(.-)%s*$")
  149.   if fields then data=fields end
  150.   -- выбор из таблицы FROM table
  151.   fields,tab=data:match("^%s*(.-)%s+from%s+(.-)%s*$")
  152.   -- SELECT fields
  153.   if not fields then fields=data end
  154.   fields=fields..","
  155.   local env=setmetatable({},{__index=funcs})
  156.   local col=""
  157.   result.name={}
  158.   for field in fields:gmatch("%s*(.-)%s*,") do
  159.     local expr,name=field:match("(.-)%s+as%s+([_%w]+)")
  160.     if expr then
  161.       table.insert(result.name,name)
  162.       col=col..expr..","
  163.     else
  164.       table.insert(result.name,field)
  165.       col=col..field..","
  166.     end
  167.   end
  168.  
  169.   if tab then
  170.     local DB,err=currentDB()
  171.     if not DB then return false,err end
  172.     if not DB[tab] then return false, "Таблица '"..sessions[currentID].DBname.."."..tab.."' не существует" end
  173.     tab=DB[tab]
  174.     if col=="*," then
  175.       result.name=tab.name
  176.       col=table.concat(tab.name,",")
  177.     end
  178.     local Fcol=load("return {"..col.."}",_,_,env)
  179.     if not Fcol then return false, errors[1]..col end
  180.     local Fcond
  181.     if cond then
  182.       Fcond=load("return "..cond,_,_,env)
  183.       if not Fcond then return false, errors[1]..cond end
  184.     end
  185.     for i=1,#tab do
  186.       for j=1,#tab.name do env[tab.name[j]]=tab[i][j] end
  187.       if Fcond then
  188.         local ok,output=pcall(Fcond)
  189.         if not ok or not output then goto continue end
  190.       end
  191.       local ok,output=pcall(Fcol)
  192.       if not ok then return false, errors[1]..col.." в строке "..i end
  193.       table.insert(result,output)
  194.       ::continue::
  195.     end
  196.     if order_by then
  197.       local Fnum
  198.       for i=1,#result.name do
  199.         if result.name[i]==order_by then Fnum=i break end
  200.       end
  201.       if Fnum then
  202.        table.sort(result,
  203.         function(row1,row2)
  204.           row1,row2=row1[Fnum],row2[Fnum]
  205.           if not row1 then return false end
  206.           if not row2 then return true end
  207.           if desc then return row1>row2 end
  208.           return row1<row2
  209.         end
  210.        )
  211.       else
  212.         return false, errors[1]..order_by
  213.       end
  214.     end
  215.   else
  216.     local Fcol=load("return {"..col.."}",_,_,env)
  217.     if not Fcol then return false, errors[1]..col end
  218.     local ok,output=pcall(Fcol)
  219.     if not ok then return false, errors[1]..col end
  220.     result[1]=output
  221.   end  
  222.   return ser(result)
  223. end
  224.  
  225. function query.use(data)
  226.   local name=tostring(data):match("(.*)%s*$")
  227.   if not name then   return false,"USE: укажите имя базы данных" end
  228.   if not DBs[name] then
  229.     local ok,err=loadDB(name)
  230.     if not ok then return false,err end
  231.   end
  232.   sessions[currentID].DBname=name
  233.   return true, "Произведена смена базы данных"
  234. end
  235.  
  236. function query.show(item)
  237.   item=tostring(item):match("(.*)%s*$")
  238.   local result={}
  239.   if item=="databases" then
  240.     result.name="Databases"
  241.     for db in fs.list(DBpath) do
  242.       table.insert(result,db)
  243.     end
  244.   elseif item=="tables" then
  245.     local DB,err=currentDB()
  246.     if not DB then return false,err end
  247.     result.name="Tables_in_"..sessions[currentID].DBname
  248.     for tab in pairs(DB) do
  249.       table.insert(result,tab)
  250.     end
  251.   else
  252.     return false, errors[1]..(item or "")
  253.   end
  254.   table.sort(result)
  255.   return ser(result)
  256. end
  257.  
  258. function query.describe(tab)
  259.   tab=tostring(tab):match("(.*)%s*$")
  260.   local DB,err=currentDB()
  261.   if not DB then return false,err end
  262.   if not DB[tab] then return false, "Таблица '"..sessions[currentID].DBname.."."..tab.."' не существует" end
  263.   tab=DB[tab]
  264.   local result={name={"Field","Type","Default","Extra"}}
  265.   for i=1,#tab.name do
  266.     result[i]={tab.name[i],tab.type[i],(tab.default or {})[i],(tab.extra or {})[i]}
  267.   end
  268.   return ser(result)
  269. end
  270.  
  271. function query.drop(data)
  272.   local item,name=tostring(data):match("(%S+)%s*(%S+)")
  273.   if item=="database" then
  274.     if not fs.exists(DBpath..name) then return false, "База данных "..name.." не существует;" end
  275.     DBs[name]=nil
  276.     local ok,err=fs.remove(DBpath..name)
  277.     if not ok then return false, "Ошибка удаления базы '"..name.."'; "..err end
  278.     return true, errors[0]
  279.   elseif item=="table" then
  280.     local DB,err=currentDB()
  281.     if not DB then return false,err end
  282.     if not DB[name] then return false, "Таблица '"..sessions[currentID].DBname.."."..name.."' не существует" end
  283.     DB[name]=nil
  284.     return saveDB(sessions[currentID].DBname)
  285.   else
  286.     return false, errors[1]..(item or "")
  287.   end
  288. end;
  289.  
  290. function query.insert(data)
  291.   local tab, fields,values = data:match("^%s*into%s+([_%w]+)%s*%((.*)%)%s*values%s*%((.*)%)%s*$")
  292.   if not tab then tab, values = data:match("^%s*into%s+([_%w]+)%s+values%s*%((.*)%)%s*$") end
  293.   if not tab then return false, errors[1] end
  294.   local DB,err=currentDB()
  295.   if not DB then return false,err end
  296.   if not DB[tab] then return false, "Таблица '"..sessions[currentID].DBname.."."..tab.."' не существует" end
  297.   tab=DB[tab]
  298.   local result = uns("{"..values.."}")
  299.   if not result then return false, errors[1]..values end
  300.   local row={}
  301.   if fields then
  302.     for i=1,#tab.name do
  303.       if tab.default then row[i]=tab.default[i] end
  304.       if tab.type[i]=="number" and tab.extra[i]:find("auto_increment") then
  305.         local Max=0
  306.         for j=1,#tab do
  307.           if type(tab[j][i])=="number" and tab[j][i]>Max then Max=tab[j][i] end
  308.         end
  309.         row[i]=math.floor(Max)+1
  310.       end
  311.     end
  312.     fields=fields..","
  313.     local field_num={}
  314.     for i=1,#tab.name do field_num[tab.name[i]]=i end
  315.     local n=1
  316.     for field in fields:gmatch("([_%w]+)%s*,") do
  317.       if not field_num[field] then return false, "Поле "..field.." отсутствует в таблице" end
  318.       row[field_num[field]]=result[n]
  319.       n=n+1
  320.     end
  321.   else
  322.     if #tab.name~=#result then return false, "Количество колонок таблицы не соответствует количеству данных" end
  323.     for i=1,#tab.type do
  324.       if type(result[i])==tab.type[i] then
  325.         table.insert(row,result[i])
  326.       else
  327.         return false, "Несоответствие типа данных "..result[i]
  328.       end
  329.     end
  330.   end
  331.   table.insert(tab,row)
  332.   return saveDB(sessions[currentID].DBname,1)
  333. end
  334. -------------------------------------------------------------
  335. local commands={}
  336. function commands.close()
  337.   sessions[currentID]=nil
  338.   return true
  339. end
  340.  
  341. function commands.connect()
  342.   local id=#sessions+1
  343.   sessions[id]={}
  344.   return id
  345. end
  346.  
  347. function commands.query(que)
  348.   local command,data=tostring(que):match("(%S+)%s*(.*)")
  349.   if not command then return false, "Ошибка в строке запроса" end
  350.   if query[command] then return query[command](data)
  351.   else return false, errors[1]..command end
  352. end
  353.  
  354. -------------------------------------------------------------
  355. function request(ev_name, id, command, ...)
  356.   if not command then pushSignal(sig_ansver, id, false, "Команда не определена") return end
  357.   currentID=id
  358.   if commands[command] then pushSignal(sig_ansver, id, commands[command](...))
  359.   else pushSignal(sig_ansver, id, false, errors[1]..command) end
  360. end
  361.  
  362. if not event.listen(sig_request,request) then
  363.   print("Невозможно запустить обработчик события "..sig_request) return
  364. end
  365.  
  366. print("MySQL-сервер успешно запущен")
RAW Paste Data