Changed SQL queries for mysql2 ruby driver

Signed-off-by: Sergey Bogdanov <sergey.bogdanov@oktetlabs.ru>
master
Sergey Bogdanov 2022-02-02 14:21:36 +00:00
parent 3a172adb84
commit 5da583412b
6 changed files with 120 additions and 101 deletions

View File

@ -1,5 +1,5 @@
# SPDX-License-Identifier: Apache-2.0 # 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. # Class Diary for Diary Management Application.
@ -220,16 +220,18 @@ class Diary
not policy.can_approve?(project, who)) or not policy.can_approve?(project, who)) or
DiaryState.valid(@attributes["state"].to_i) DiaryState.valid(@attributes["state"].to_i)
@approval_note = DataMapper.database.select_all( @approval_note = DataMapper.database.query("select * from approval_note where id = '%s'" % @id).collect { |row| row.to_h }
"select * from approval_note where id = ?", @id
).collect { |row| row.to_h }
return @approval_note return @approval_note
end end
def self.approve_all(prj, who) def self.approve_all(prj, who)
DataMapper.database.do("update diary set state = ? where prj_id = ? " + DataMapper.database.query("update diary set state = '%s' where prj_id = '%s' AND who = '%s' AND state IN ('%s','%s')" %
"AND who = ? AND state IN (?,?)", DiaryState::APPROVED, [
prj.id, who, DiaryState::REQ_APPROVAL, DiaryState::REJECTED) DiaryState::APPROVED,
DataMapper.database.escape(prj.id.to_s),
DataMapper.database.escape(who.to_s),
DiaryState::REQ_APPROVAL, DiaryState::REJECTED
])
end end
def destroy def destroy
@ -245,11 +247,8 @@ class Diary
def self.predict_project(who) def self.predict_project(who)
# TODO: select the most used of N last entries # TODO: select the most used of N last entries
last_diary = DataMapper.database.select_one( last_diary = DataMapper.database.query("SELECT prj_id FROM diary WHERE who='%s' ORDER BY ddate DESC LIMIT 1" % who.uid ).first
"SELECT prj_id FROM diary " + return last_diary ? last_diary["prj_id"].to_i : nil
"WHERE who=? ORDER BY ddate DESC " +
"LIMIT 1", who.uid)
return last_diary ? last_diary[0].to_i : nil
end end
def self.find(args) def self.find(args)
@ -260,7 +259,7 @@ class Diary
dates = args[:ddate] dates = args[:ddate]
raise ArgumentError unless dates.is_a? Range 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] query_args = [dates.first, dates.last]
if policy.restriction.include?(:project) if policy.restriction.include?(:project)
@ -268,10 +267,10 @@ class Diary
prj_list = prj_list & [prj_id] if prj_id prj_list = prj_list & [prj_id] if prj_id
return [] if prj_list.empty? return [] if prj_list.empty?
query_clause += " AND prj_id IN (" + query_clause += " AND prj_id IN (" +
prj_list.collect { "?" }.join(",") + ")" prj_list.collect { "'%s'" }.join(",") + ")"
query_args += prj_list query_args += prj_list
elsif prj_id elsif prj_id
query_clause += " AND prj_id = ?" query_clause += " AND prj_id = '%s'"
query_args = query_args << prj_id query_args = query_args << prj_id
end end
@ -280,45 +279,48 @@ class Diary
eng_list = eng_list & [who] if who eng_list = eng_list & [who] if who
return [] if eng_list.empty? return [] if eng_list.empty?
query_clause += " AND who IN (" + query_clause += " AND who IN (" +
eng_list.collect { "?" }.join(",") + ")" eng_list.collect { "'%s'" }.join(",") + ")"
query_args += eng_list query_args += eng_list
elsif who elsif who
query_clause += " AND who = ?" query_clause += " AND who = '%s'"
query_args = query_args << who query_args = query_args << who
end end
if customer if customer
query_clause += " AND customer = ?" query_clause += " AND customer = '%s'"
query_args = query_args << customer query_args = query_args << customer
end end
DataMapper.database.select_all("select diary.*, project.customer, " + DataMapper.database.query("select diary.*, project.customer, " +
" project.leader, project.manager, diary.id as id" + " project.leader, project.manager, diary.id as id" +
", diary.state as state" + ", diary.state as state" +
" from diary left join project on diary.prj_id = project.id" + " from diary left join project on diary.prj_id = project.id" +
query_clause + " order by ddate, prj_id, who", query_clause % (query_args) + " order by ddate, prj_id, who"
*query_args).collect do |row| ).collect do |row|
self.new(row["id"], row.to_h) self.new(row["id"], row.to_h)
end end
end end
def self.for_approve(who) 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" + " diary inner join approval on approval.who = diary.who and" +
" approval.prj_id = diary.prj_id left join project on" + " approval.prj_id = diary.prj_id left join project on" +
" diary.prj_id = project.id where approval.approver = ?" + " diary.prj_id = project.id where approval.approver = '%s'" % who.uid +
" and diary.state = ? order by diary.ddate", " and diary.state = '%s' order by diary.ddate" % DiaryState::REQ_APPROVAL
who.uid, DiaryState::REQ_APPROVAL).collect do |row| ).collect do |row|
self.new(row["id"], row.to_h) self.new(row["id"], row.to_h)
end end
end end
def self.add_approval_note(id, message) def self.add_approval_note(id, message)
if message.is_a?(String) and message.length > 0 if message.is_a?(String) and message.length > 0
DataMapper.database.do( DataMapper.database.query("insert into approval_note(id,created,author,note) values ('%s',%s,'%s','%s')" %
"insert into approval_note(id,created,author,note) " + [
"values (?,?,?,?)", id, DbTime.now, DataMapper.database.escape(id.to_s),
DiaryEnv.instance.user.uid, message) "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 end
end end
@ -697,12 +699,12 @@ class DiaryUI
data["descr"].length < 10 data["descr"].length < 10
# Check total hours # Check total hours
total = DataMapper.database.select_one( total = DataMapper.database.query("SELECT SUM(hours) as sum FROM diary WHERE who='%s' AND ddate='%s'" %
"SELECT SUM(hours) FROM diary " + [
"WHERE who=? AND ddate=?" + data["who"],
(data.include?("id") ? data["ddate"]
" AND id<>#{data["id"]}" : ""), ] + (data.include?("id") ? " AND id<>#{data["id"]}" : "")
*([data["who"], data["ddate"]]))[0].to_i + ).first["sum"].to_i +
data["hours"] data["hours"]
raise "You have more than 24 hours " + raise "You have more than 24 hours " +
"for #{data["ddate"]}" if total > 24 "for #{data["ddate"]}" if total > 24
@ -753,12 +755,16 @@ class DiaryUI
else else
raise "You should specify at least 1 hour" if data["hours"] < 1 raise "You should specify at least 1 hour" if data["hours"] < 1
raise "You are inserting a duplicate diary record!" if raise "You are inserting a duplicate diary record!" if
DataMapper.database.select_one( DataMapper.database.query(
"SELECT COUNT(*) FROM diary WHERE " + "SELECT COUNT(*) as count FROM diary WHERE " +
"who = ? and descr = ? and hours = ? " + "who = '%s' and descr = '%s' and hours = '%s' and ddate = '%s'" %
"and ddate =?", [
*([data["who"], data["descr"], DataMapper.database.escape(data["who"].to_s),
data["hours"], data["ddate"]]))[0].to_i > 0 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"] data["created"] = data["modified"]
@diary_table.create(data) @diary_table.create(data)
end end

View File

@ -1,11 +1,11 @@
# SPDX-License-Identifier: Apache-2.0 # 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. # Class DataMapper for Diary Management Application.
# #
require 'dbi' require 'mysql2'
class DataMapper class DataMapper
@@mapper = Hash.new @@mapper = Hash.new
@ -16,13 +16,11 @@ class DataMapper
@table = table @table = table
@@mapper[@table] = self @@mapper[@table] = self
@cache = Hash.new @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 end
def self.setup(args) def self.setup(args)
raise "Database parameters is not a hash" unless args.is_a? Hash raise "Database parameters is not a hash" unless args.is_a? Hash
@@database = DBI.connect("dbi:#{args[:adapter]}:#{args[:database]}:" + @@database = Mysql2::Client.new(:host => args[:host], :username => args[:username], :password => args[:password], :database => args[:database])
"#{args[:host]}",
args[:username], args[:password])
end end
def self.database def self.database
@@database @@database
@ -37,14 +35,14 @@ class DataMapper
def find(id) def find(id)
return @cache[id] if @cache.has_key?(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 return nil unless row
pick(row) pick(row)
end end
def where(clause, *args) def where(clause, *args)
@@database.select_all("select * from #{@table} where " + clause, cmd = "select * from #{@table} where " + clause % args
*args).collect { |row| pick(row) } @@database.query(cmd).collect { |row| pick(row) }
end end
def all(args) def all(args)
@ -57,22 +55,20 @@ class DataMapper
if value.is_a?(Array) if value.is_a?(Array)
if value.length > 0 if value.length > 0
query_clause << "#{tag.to_s} " + query_clause << "#{tag.to_s} " +
"IN (#{value.collect {"?"}.join(",")})" "IN (#{value.collect {"'%s'"}.join(",")})"
query_args = query_args + value query_args = query_args + value
end end
elsif value.is_a?(Range) 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 query_args << value.first << value.last
else else
query_clause << "#{tag.to_s} = ?" query_clause << "#{tag.to_s} = '%s'"
query_args << value query_args << value
end end
end end
# raise "#{MyCGI.dump(query_clause)} : #{MyCGI.dump(query_args)}" # raise "#{MyCGI.dump(query_clause)} : #{MyCGI.dump(query_args)}"
@@database.select_all("select * from #{@table}" + cmd = "select * from #{@table}" + (query_clause.empty? ? "" : " where " + query_clause.join(" and ")) % query_args
(query_clause.empty? ? "" : @@database.query(cmd).collect { |row| pick(row) }
" where " + query_clause.join(" and ")),
*query_args).collect { |row| pick(row) }
end end
def insert(obj) def insert(obj)
@ -81,7 +77,7 @@ class DataMapper
@@database.do("insert into #{@table} (" + fields.join(",") + @@database.do("insert into #{@table} (" + fields.join(",") +
") values (" + fields.collect {"?"}.join(",") + ")", ") values (" + fields.collect {"?"}.join(",") + ")",
*(fields.collect {|field| obj[field]})) *(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 @@cache[obj.id] = obj
end end

View File

@ -42,15 +42,17 @@ class DiaryEnv
:bindpw => LDAP_BIND_PW, :bindpw => LDAP_BIND_PW,
:key => "uid") :key => "uid")
Person.set_local(HOME_ORGANIZATION, HOME_OU) Person.set_local(HOME_ORGANIZATION, HOME_OU)
DataMapper.setup(:adapter => "Mysql", DataMapper.setup(:adapter => "Mysql2",
:database => DB_DATABASE, :database => DB_DATABASE,
:host => DB_HOST, :host => DB_HOST,
:username => DB_USERNAME, :username => DB_USERNAME,
:password => DB_PASSWORD) :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 raise "'Director' table is not filled" unless
q and name = q.fetch[0] q and name = q.fetch['nick']
@director = [ Person.new('director') ] @director.push(Person.new(name))
end end
end end

View File

@ -1,5 +1,5 @@
# SPDX-License-Identifier: Apache-2.0 # 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. # Class Policy for Diary Management Application.
@ -95,7 +95,7 @@ class CustomerPolicy
end end
def project_list def project_list
(Project.where("customer=? AND extra_rights IS NULL", (Project.where("customer='%s' AND extra_rights IS NULL",
@user.organization.uid) + @user.organization.uid) +
extra_project_list).uniq.sort extra_project_list).uniq.sort
end end

View File

@ -1,5 +1,5 @@
# SPDX-License-Identifier: Apache-2.0 # 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. # Class Project for Diary Management Application.
@ -100,16 +100,17 @@ class ProjectMapper < DataMapper
def find_approvals(id) def find_approvals(id)
app = Hash.new app = Hash.new
@@database.select_all("select * from approval where prj_id = ?", @@database.query("select * from approval where prj_id = '%s'" % id).collect { |row| app[row["who"]] = row["approver"] }
id) { |row| app[row["who"]] = row["approver"] }
app app
end end
def save_approvals(id, app) 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| app.each do |who, approver|
@@database.do("insert into approval (prj_id, who, approver) " + cmd = "insert into approval (prj_id, who, approver) values ('%s', '%s', '%s')" %
"values (?, ?, ?)", id, who, approver) [@@database.escape(id.to_s), @@database.escape(who.to_s), @@database.escape(approver.to_s)]
@@database.query(cmd)
end end
end end
end end
@ -131,7 +132,7 @@ class ProjectUI < Hash
@id = id @id = id
self.clear self.clear
if @id 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 ### For some reason MySQL driver always returns 0 in q.rows
# if q.rows != 1 # if q.rows != 1
# raise "Project #{@id} has #{q.rows} instances" # raise "Project #{@id} has #{q.rows} instances"
@ -142,8 +143,8 @@ class ProjectUI < Hash
self.delete("id") self.delete("id")
end end
self["cc"] = Array.new self["cc"] = Array.new
DataMapper.database.select_all("select person from cc_list where " + DataMapper.database.query("select person from cc_list where " +
"prj_id = #{@id}") do |row| "prj_id = #{@id}").collect do |row|
self["cc"].push(row["person"]) self["cc"].push(row["person"])
end end
end end
@ -162,11 +163,10 @@ class ProjectUI < Hash
#raise "Create project #{data["name"]}" #raise "Create project #{data["name"]}"
inst = data.keys inst = data.keys
inst -= ["cc"] inst -= ["cc"]
DataMapper.database.do("insert into project (" + inst.join(", ") + cmd = ("insert into project (" + inst.join(", ") + ") values (" + (inst.collect do "'%s'" end).join(", ") + ")") %
") values (" + (inst.collect do "?" end).join(", ") + (inst.collect do |field| DataMapper.database.escape(data[field]) end)
")", DataMapper.database.query(cmd)
*(inst.collect do |field| data[field] end)) @id = DataMapper.database.query("select last_insert_id() as id").first["id"]
@id = DataMapper.database.select_one("select last_insert_id()")[0]
if data["cc"].length > 0 if data["cc"].length > 0
DataMapper.database.do("insert into cc_list (prj_id, person) values " + DataMapper.database.do("insert into cc_list (prj_id, person) values " +
(["(#{@id}, ?)"] * data["cc"].length).join(", "), (["(#{@id}, ?)"] * data["cc"].length).join(", "),
@ -184,12 +184,16 @@ class ProjectUI < Hash
end end
end end
if (changes - ["cc"]).length > 0 if (changes - ["cc"]).length > 0
DataMapper.database.do("update project set " + cmd = ("update project set " + (changes.collect do |field| field + " = %s" if field != "cc" end).join(", ") + " where id = #{@id}") %
(changes.collect do (changes.collect do |field|
|field| field + " = ?" if field != "cc" if data[field].class == DateTime
end).join(", ") + t = "STR_TO_DATE('%s'" % data[field] + ", '%Y-%m-%dT%H:%i:%s+00:00')"
" where id = #{@id}", else
*(changes.collect do |field| data[field] end)); t = "'%s'" % DataMapper.database.escape(data[field].to_s)
end
t
end)
DataMapper.database.query(cmd);
end end
if (current["cc"] - data["cc"]).length > 0 if (current["cc"] - data["cc"]).length > 0
DataMapper.database.do("delete from cc_list where " + DataMapper.database.do("delete from cc_list where " +
@ -422,7 +426,7 @@ class ProjectUI < Hash
if @cgi.tree_params["prj"].include?("edit") if @cgi.tree_params["prj"].include?("edit")
attrs = @cgi.tree_params["prj"]["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") if attrs.include?("id")
update(attrs["id"]) update(attrs["id"])
attrs.delete("id") attrs.delete("id")

View File

@ -1,5 +1,5 @@
# SPDX-License-Identifier: Apache-2.0 # 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 # SQL class for Diary Management Application
@ -11,7 +11,8 @@ class SQL_Cache < Hash
@name = table @name = table
@string_expr = string_expr @string_expr = string_expr
@lists = Hash.new @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) super(0)
end end
@ -20,7 +21,8 @@ class SQL_Cache < Hash
def search(where) def search(where)
list = Array.new 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 self[row["id"]] = row.to_h
list.push(self[row["id"]]) list.push(self[row["id"]])
end end
@ -53,12 +55,17 @@ class SQL_Cache < Hash
def create(data) def create(data)
fields = data.keys & @fields fields = data.keys & @fields
@sql.do("insert into #{@name} (" + cmd = ("insert into #{@name} (" + fields.join(", ") + ") values (" + fields.collect do "%s" end.join(", ") + ")") %
fields.join(", ") + (fields.collect do |field|
") values (" + fields.collect do "?" end.join(", ") + if data[field].class == DateTime
")", t = "STR_TO_DATE('%s'" % data[field] + ", '%Y-%m-%dT%H:%i:%s+00:00')"
*(fields.collect do |field| data[field] end)) else
@sql.select_one("select last_insert_id()")[0] 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 end
def modify(id, data) def modify(id, data)
@ -70,16 +77,20 @@ class SQL_Cache < Hash
ch ch
end end
end end
@sql.do("update #{@name} set " + cmd = ("update #{@name} set " + changes.collect do |field| field + " = %s" end.join(", ") + " where id = #{id}") %
changes.collect do |field| (changes.collect do |field|
field + " = ?" if data[field].class == DateTime
end.join(", ") + " where id = #{id}", t = "STR_TO_DATE('%s'" % data[field] + ", '%Y-%m-%dT%H:%i:%s+00:00')"
*(changes.collect do |field| data[field] end) else
) if changes.length > 0 t = "'%s'" % @sql.escape(data[field].to_s)
end
t
end)
@sql.query(cmd) if changes.length > 0
end end
def delete(id) def delete(id)
@sql.do("delete from #{@name} where id = #{id}") @sql.query("delete from #{@name} where id = #{id}")
super(id) super(id)
end end
end end