From 5da583412b15f0d4992081cf9af461fe70976a9a Mon Sep 17 00:00:00 2001 From: Sergey Bogdanov Date: Wed, 2 Feb 2022 14:21:36 +0000 Subject: [PATCH] Changed SQL queries for mysql2 ruby driver Signed-off-by: Sergey Bogdanov --- diary.rb | 88 +++++++++++++++++++++++--------------------- diary_datamapper.rb | 30 +++++++-------- diary_env.example.rb | 10 +++-- diary_policy.rb | 4 +- project.rb | 46 ++++++++++++----------- sql_cache.rb | 43 ++++++++++++++-------- 6 files changed, 120 insertions(+), 101 deletions(-) diff --git a/diary.rb b/diary.rb index 80bcde4..b1766ca 100644 --- a/diary.rb +++ b/diary.rb @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# Copyright (C) 2021 OKTET Labs Ltd. All rights reserved. +# Copyright (C) 2021-2022 OKTET Labs Ltd. All rights reserved. # # Class Diary for Diary Management Application. @@ -220,16 +220,18 @@ class Diary not policy.can_approve?(project, who)) or DiaryState.valid(@attributes["state"].to_i) - @approval_note = DataMapper.database.select_all( - "select * from approval_note where id = ?", @id - ).collect { |row| row.to_h } + @approval_note = DataMapper.database.query("select * from approval_note where id = '%s'" % @id).collect { |row| row.to_h } return @approval_note end def self.approve_all(prj, who) - DataMapper.database.do("update diary set state = ? where prj_id = ? " + - "AND who = ? AND state IN (?,?)", DiaryState::APPROVED, - prj.id, who, DiaryState::REQ_APPROVAL, DiaryState::REJECTED) + DataMapper.database.query("update diary set state = '%s' where prj_id = '%s' AND who = '%s' AND state IN ('%s','%s')" % + [ + DiaryState::APPROVED, + DataMapper.database.escape(prj.id.to_s), + DataMapper.database.escape(who.to_s), + DiaryState::REQ_APPROVAL, DiaryState::REJECTED + ]) end def destroy @@ -245,11 +247,8 @@ class Diary def self.predict_project(who) # TODO: select the most used of N last entries - last_diary = DataMapper.database.select_one( - "SELECT prj_id FROM diary " + - "WHERE who=? ORDER BY ddate DESC " + - "LIMIT 1", who.uid) - return last_diary ? last_diary[0].to_i : nil + last_diary = DataMapper.database.query("SELECT prj_id FROM diary WHERE who='%s' ORDER BY ddate DESC LIMIT 1" % who.uid ).first + return last_diary ? last_diary["prj_id"].to_i : nil end def self.find(args) @@ -260,7 +259,7 @@ class Diary dates = args[:ddate] raise ArgumentError unless dates.is_a? Range - query_clause = " where ddate >= ? and ddate <= ?" + query_clause = " where ddate >= '%s' and ddate <= '%s'" query_args = [dates.first, dates.last] if policy.restriction.include?(:project) @@ -268,10 +267,10 @@ class Diary prj_list = prj_list & [prj_id] if prj_id return [] if prj_list.empty? query_clause += " AND prj_id IN (" + - prj_list.collect { "?" }.join(",") + ")" + prj_list.collect { "'%s'" }.join(",") + ")" query_args += prj_list elsif prj_id - query_clause += " AND prj_id = ?" + query_clause += " AND prj_id = '%s'" query_args = query_args << prj_id end @@ -280,45 +279,48 @@ class Diary eng_list = eng_list & [who] if who return [] if eng_list.empty? query_clause += " AND who IN (" + - eng_list.collect { "?" }.join(",") + ")" + eng_list.collect { "'%s'" }.join(",") + ")" query_args += eng_list elsif who - query_clause += " AND who = ?" + query_clause += " AND who = '%s'" query_args = query_args << who end if customer - query_clause += " AND customer = ?" + query_clause += " AND customer = '%s'" query_args = query_args << customer end - DataMapper.database.select_all("select diary.*, project.customer, " + + DataMapper.database.query("select diary.*, project.customer, " + " project.leader, project.manager, diary.id as id" + ", diary.state as state" + " from diary left join project on diary.prj_id = project.id" + - query_clause + " order by ddate, prj_id, who", - *query_args).collect do |row| + query_clause % (query_args) + " order by ddate, prj_id, who" + ).collect do |row| self.new(row["id"], row.to_h) end end def self.for_approve(who) - DataMapper.database.select_all("select *, diary.id as id from" + + DataMapper.database.query("select *, diary.id as id from" + " diary inner join approval on approval.who = diary.who and" + " approval.prj_id = diary.prj_id left join project on" + - " diary.prj_id = project.id where approval.approver = ?" + - " and diary.state = ? order by diary.ddate", - who.uid, DiaryState::REQ_APPROVAL).collect do |row| + " diary.prj_id = project.id where approval.approver = '%s'" % who.uid + + " and diary.state = '%s' order by diary.ddate" % DiaryState::REQ_APPROVAL + ).collect do |row| self.new(row["id"], row.to_h) end end def self.add_approval_note(id, message) if message.is_a?(String) and message.length > 0 - DataMapper.database.do( - "insert into approval_note(id,created,author,note) " + - "values (?,?,?,?)", id, DbTime.now, - DiaryEnv.instance.user.uid, message) + DataMapper.database.query("insert into approval_note(id,created,author,note) values ('%s',%s,'%s','%s')" % + [ + DataMapper.database.escape(id.to_s), + "STR_TO_DATE('%s'," % DbTime.now + " '%Y-%m-%dT%h:%i:%s+00:00')", + DataMapper.database.escape(DiaryEnv.instance.user.uid), + DataMapper.database.escape(message) + ]) end end end @@ -697,12 +699,12 @@ class DiaryUI data["descr"].length < 10 # Check total hours - total = DataMapper.database.select_one( - "SELECT SUM(hours) FROM diary " + - "WHERE who=? AND ddate=?" + - (data.include?("id") ? - " AND id<>#{data["id"]}" : ""), - *([data["who"], data["ddate"]]))[0].to_i + + total = DataMapper.database.query("SELECT SUM(hours) as sum FROM diary WHERE who='%s' AND ddate='%s'" % + [ + data["who"], + data["ddate"] + ] + (data.include?("id") ? " AND id<>#{data["id"]}" : "") + ).first["sum"].to_i + data["hours"] raise "You have more than 24 hours " + "for #{data["ddate"]}" if total > 24 @@ -753,12 +755,16 @@ class DiaryUI else raise "You should specify at least 1 hour" if data["hours"] < 1 raise "You are inserting a duplicate diary record!" if - DataMapper.database.select_one( - "SELECT COUNT(*) FROM diary WHERE " + - "who = ? and descr = ? and hours = ? " + - "and ddate =?", - *([data["who"], data["descr"], - data["hours"], data["ddate"]]))[0].to_i > 0 + DataMapper.database.query( + "SELECT COUNT(*) as count FROM diary WHERE " + + "who = '%s' and descr = '%s' and hours = '%s' and ddate = '%s'" % + [ + DataMapper.database.escape(data["who"].to_s), + DataMapper.database.escape(data["descr"].to_s), + DataMapper.database.escape(data["hours"].to_s), + DataMapper.database.escape(data["ddate"].to_s) + ] + ).first["count"].to_i > 0 data["created"] = data["modified"] @diary_table.create(data) end diff --git a/diary_datamapper.rb b/diary_datamapper.rb index 29e3bc8..7f4091a 100644 --- a/diary_datamapper.rb +++ b/diary_datamapper.rb @@ -1,11 +1,11 @@ # SPDX-License-Identifier: Apache-2.0 -# Copyright (C) 2021 OKTET Labs Ltd. All rights reserved. +# Copyright (C) 2021-2022 OKTET Labs Ltd. All rights reserved. # # Class DataMapper for Diary Management Application. # -require 'dbi' +require 'mysql2' class DataMapper @@mapper = Hash.new @@ -16,13 +16,11 @@ class DataMapper @table = table @@mapper[@table] = self @cache = Hash.new - @columns = @@database.columns(@table).collect { |col| col["name"] } - [@key] + @columns = @@database.query("select column_name from information_schema.columns where table_name='%s'" % @table).collect{ |col| col["column_name"] } - [@key] end def self.setup(args) raise "Database parameters is not a hash" unless args.is_a? Hash - @@database = DBI.connect("dbi:#{args[:adapter]}:#{args[:database]}:" + - "#{args[:host]}", - args[:username], args[:password]) + @@database = Mysql2::Client.new(:host => args[:host], :username => args[:username], :password => args[:password], :database => args[:database]) end def self.database @@database @@ -37,14 +35,14 @@ class DataMapper def find(id) return @cache[id] if @cache.has_key?(id) - row = @@database.select_one("select * from #{@table} where #{@key} = ?", id) + row = @@database.query("select * from #{@table} where #{@key} = '%s' LIMIT 1" % id).first return nil unless row pick(row) end def where(clause, *args) - @@database.select_all("select * from #{@table} where " + clause, - *args).collect { |row| pick(row) } + cmd = "select * from #{@table} where " + clause % args + @@database.query(cmd).collect { |row| pick(row) } end def all(args) @@ -57,22 +55,20 @@ class DataMapper if value.is_a?(Array) if value.length > 0 query_clause << "#{tag.to_s} " + - "IN (#{value.collect {"?"}.join(",")})" + "IN (#{value.collect {"'%s'"}.join(",")})" query_args = query_args + value end elsif value.is_a?(Range) - query_clause << "#{tag.to_s} >= ? AND #{tag.to_s} <= ?" + query_clause << "#{tag.to_s} >= '%s' AND #{tag.to_s} <= '%s'" query_args << value.first << value.last else - query_clause << "#{tag.to_s} = ?" + query_clause << "#{tag.to_s} = '%s'" query_args << value end end # raise "#{MyCGI.dump(query_clause)} : #{MyCGI.dump(query_args)}" - @@database.select_all("select * from #{@table}" + - (query_clause.empty? ? "" : - " where " + query_clause.join(" and ")), - *query_args).collect { |row| pick(row) } + cmd = "select * from #{@table}" + (query_clause.empty? ? "" : " where " + query_clause.join(" and ")) % query_args + @@database.query(cmd).collect { |row| pick(row) } end def insert(obj) @@ -81,7 +77,7 @@ class DataMapper @@database.do("insert into #{@table} (" + fields.join(",") + ") values (" + fields.collect {"?"}.join(",") + ")", *(fields.collect {|field| obj[field]})) - obj.id = @@database.select_one("select last_insert_id()")[0] + obj.id = @@database.query("select last_insert_id() as id").first["id"] @@cache[obj.id] = obj end diff --git a/diary_env.example.rb b/diary_env.example.rb index 96af3fb..ad6b27f 100644 --- a/diary_env.example.rb +++ b/diary_env.example.rb @@ -42,15 +42,17 @@ class DiaryEnv :bindpw => LDAP_BIND_PW, :key => "uid") Person.set_local(HOME_ORGANIZATION, HOME_OU) - DataMapper.setup(:adapter => "Mysql", + DataMapper.setup(:adapter => "Mysql2", :database => DB_DATABASE, :host => DB_HOST, :username => DB_USERNAME, :password => DB_PASSWORD) - DataMapper.database.execute("SELECT nick FROM director") do |q| + cmd = "SELECT nick FROM director" + @director = [] + DataMapper.database.query(cmd, as: :hash, symbolize_keys: false).each do |q| raise "'Director' table is not filled" unless - q and name = q.fetch[0] - @director = [ Person.new('director') ] + q and name = q.fetch['nick'] + @director.push(Person.new(name)) end end diff --git a/diary_policy.rb b/diary_policy.rb index 11a064e..36008e7 100644 --- a/diary_policy.rb +++ b/diary_policy.rb @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# Copyright (C) 2021 OKTET Labs Ltd. All rights reserved. +# Copyright (C) 2021-2022 OKTET Labs Ltd. All rights reserved. # # Class Policy for Diary Management Application. @@ -95,7 +95,7 @@ class CustomerPolicy end def project_list - (Project.where("customer=? AND extra_rights IS NULL", + (Project.where("customer='%s' AND extra_rights IS NULL", @user.organization.uid) + extra_project_list).uniq.sort end diff --git a/project.rb b/project.rb index 9b08ddc..fab64bb 100644 --- a/project.rb +++ b/project.rb @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# Copyright (C) 2021 OKTET Labs Ltd. All rights reserved. +# Copyright (C) 2021-2022 OKTET Labs Ltd. All rights reserved. # # Class Project for Diary Management Application. @@ -100,16 +100,17 @@ class ProjectMapper < DataMapper def find_approvals(id) app = Hash.new - @@database.select_all("select * from approval where prj_id = ?", - id) { |row| app[row["who"]] = row["approver"] } + @@database.query("select * from approval where prj_id = '%s'" % id).collect { |row| app[row["who"]] = row["approver"] } app end def save_approvals(id, app) - @@database.do("delete from approval where prj_id = ?", id) + cmd = "delete from approval where prj_id = '%s'" % id.to_s + @@database.query(cmd) app.each do |who, approver| - @@database.do("insert into approval (prj_id, who, approver) " + - "values (?, ?, ?)", id, who, approver) + cmd = "insert into approval (prj_id, who, approver) values ('%s', '%s', '%s')" % + [@@database.escape(id.to_s), @@database.escape(who.to_s), @@database.escape(approver.to_s)] + @@database.query(cmd) end end end @@ -131,7 +132,7 @@ class ProjectUI < Hash @id = id self.clear if @id - DataMapper.database.execute("select * from project where id = #{@id}") do |q| + DataMapper.database.query("select * from project where id = #{@id}") do |q| ### For some reason MySQL driver always returns 0 in q.rows # if q.rows != 1 # raise "Project #{@id} has #{q.rows} instances" @@ -142,8 +143,8 @@ class ProjectUI < Hash self.delete("id") end self["cc"] = Array.new - DataMapper.database.select_all("select person from cc_list where " + - "prj_id = #{@id}") do |row| + DataMapper.database.query("select person from cc_list where " + + "prj_id = #{@id}").collect do |row| self["cc"].push(row["person"]) end end @@ -162,11 +163,10 @@ class ProjectUI < Hash #raise "Create project #{data["name"]}" inst = data.keys inst -= ["cc"] - DataMapper.database.do("insert into project (" + inst.join(", ") + - ") values (" + (inst.collect do "?" end).join(", ") + - ")", - *(inst.collect do |field| data[field] end)) - @id = DataMapper.database.select_one("select last_insert_id()")[0] + cmd = ("insert into project (" + inst.join(", ") + ") values (" + (inst.collect do "'%s'" end).join(", ") + ")") % + (inst.collect do |field| DataMapper.database.escape(data[field]) end) + DataMapper.database.query(cmd) + @id = DataMapper.database.query("select last_insert_id() as id").first["id"] if data["cc"].length > 0 DataMapper.database.do("insert into cc_list (prj_id, person) values " + (["(#{@id}, ?)"] * data["cc"].length).join(", "), @@ -184,12 +184,16 @@ class ProjectUI < Hash end end if (changes - ["cc"]).length > 0 - DataMapper.database.do("update project set " + - (changes.collect do - |field| field + " = ?" if field != "cc" - end).join(", ") + - " where id = #{@id}", - *(changes.collect do |field| data[field] end)); + cmd = ("update project set " + (changes.collect do |field| field + " = %s" if field != "cc" end).join(", ") + " where id = #{@id}") % + (changes.collect do |field| + if data[field].class == DateTime + t = "STR_TO_DATE('%s'" % data[field] + ", '%Y-%m-%dT%H:%i:%s+00:00')" + else + t = "'%s'" % DataMapper.database.escape(data[field].to_s) + end + t + end) + DataMapper.database.query(cmd); end if (current["cc"] - data["cc"]).length > 0 DataMapper.database.do("delete from cc_list where " + @@ -422,7 +426,7 @@ class ProjectUI < Hash if @cgi.tree_params["prj"].include?("edit") attrs = @cgi.tree_params["prj"]["edit"] - attrs["hide_hrs"] = [attrs.include?("hide_hrs") ? 1 : 0] + attrs["hide_hrs"] = attrs.include?("hide_hrs") ? "1" : "0" if attrs.include?("id") update(attrs["id"]) attrs.delete("id") diff --git a/sql_cache.rb b/sql_cache.rb index 490c7e9..7f7a2ea 100644 --- a/sql_cache.rb +++ b/sql_cache.rb @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# Copyright (C) 2021 OKTET Labs Ltd. All rights reserved. +# Copyright (C) 2021-2022 OKTET Labs Ltd. All rights reserved. # # SQL class for Diary Management Application @@ -11,7 +11,8 @@ class SQL_Cache < Hash @name = table @string_expr = string_expr @lists = Hash.new - @fields = @sql.columns(@name).collect { |col| col["name"] } + @fields = @sql.query("select column_name from information_schema.columns where table_name='%s'" % + @sql.escape(@name)).collect { |col| col["column_name"] } super(0) end @@ -20,7 +21,8 @@ class SQL_Cache < Hash def search(where) list = Array.new - @sql.select_all("select * from #{@name} where #{where} order by id") do |row| + cmd = "select * from #{@name} where #{where} order by id" + @sql.query(cmd).collect do |row| self[row["id"]] = row.to_h list.push(self[row["id"]]) end @@ -53,12 +55,17 @@ class SQL_Cache < Hash def create(data) fields = data.keys & @fields - @sql.do("insert into #{@name} (" + - fields.join(", ") + - ") values (" + fields.collect do "?" end.join(", ") + - ")", - *(fields.collect do |field| data[field] end)) - @sql.select_one("select last_insert_id()")[0] + cmd = ("insert into #{@name} (" + fields.join(", ") + ") values (" + fields.collect do "%s" end.join(", ") + ")") % + (fields.collect do |field| + if data[field].class == DateTime + t = "STR_TO_DATE('%s'" % data[field] + ", '%Y-%m-%dT%H:%i:%s+00:00')" + else + t = "'%s'" % @sql.escape(data[field].to_s) + end + t + end) + @sql.query(cmd) + @sql.query("select last_insert_id() as id").first["id"] end def modify(id, data) @@ -70,16 +77,20 @@ class SQL_Cache < Hash ch end end - @sql.do("update #{@name} set " + - changes.collect do |field| - field + " = ?" - end.join(", ") + " where id = #{id}", - *(changes.collect do |field| data[field] end) - ) if changes.length > 0 + cmd = ("update #{@name} set " + changes.collect do |field| field + " = %s" end.join(", ") + " where id = #{id}") % + (changes.collect do |field| + if data[field].class == DateTime + t = "STR_TO_DATE('%s'" % data[field] + ", '%Y-%m-%dT%H:%i:%s+00:00')" + else + t = "'%s'" % @sql.escape(data[field].to_s) + end + t + end) + @sql.query(cmd) if changes.length > 0 end def delete(id) - @sql.do("delete from #{@name} where id = #{id}") + @sql.query("delete from #{@name} where id = #{id}") super(id) end end