25 |
MysqlError.module_eval('ER_NO_SUCH_TABLE = 1146') |
MysqlError.module_eval('ER_NO_SUCH_TABLE = 1146') |
26 |
end |
end |
27 |
|
|
28 |
|
class MysqlRes |
29 |
|
include Enumerable |
30 |
|
end |
31 |
|
|
32 |
require 'bugcomm/bug' |
require 'bugcomm/bug' |
33 |
require 'bugcomm/field' |
require 'bugcomm/field' |
34 |
require 'bugcomm/followup' |
require 'bugcomm/followup' |
35 |
require 'bugcomm/attachment' |
require 'bugcomm/attachment' |
36 |
|
require 'bugcomm/exception' |
37 |
|
require 'bugcomm/utils' |
38 |
|
|
39 |
module BugCommunicator |
module BugCommunicator |
40 |
|
|
|
# FIXME: just a skelton. |
|
41 |
class Database |
class Database |
42 |
|
|
43 |
|
MAX_PROJECT_NAME = 32 |
44 |
|
SIZE_OF_CID = 32 |
45 |
|
|
46 |
PROJECTS = %w(foo bar) |
def self.setup(config) |
47 |
|
db = Mysql.new(config.db_host, config.db_user, config.db_password) |
48 |
|
db.query_with_result = false |
49 |
|
|
50 |
|
if db.list_dbs(config.db_name).empty? |
51 |
|
Utils.info("creating a new database `#{config.db_name}'") |
52 |
|
db.query("CREATE DATABASE #{Mysql.escape_string(config.db_name)}") |
53 |
|
end |
54 |
|
|
55 |
|
db.select_db(config.db_name) |
56 |
|
|
57 |
|
if db.list_tables('projects').empty? |
58 |
|
Utils.info("creating a new table `projects' in `#{config.db_name}'") |
59 |
|
db.query("CREATE TABLE projects ( \ |
60 |
|
name VARCHAR(#{MAX_PROJECT_NAME}) PRIMARY KEY, \ |
61 |
|
ctime DATETIME NOT NULL \ |
62 |
|
)") |
63 |
|
end |
64 |
|
if db.list_tables('confirmations').empty? |
65 |
|
Utils.info("creating a new table `confirmations' in `#{config.db_name}'") |
66 |
|
db.query("CREATE TABLE confirmations ( \ |
67 |
|
cid CHAR(#{SIZE_OF_CID}) PRIMARY KEY, \ |
68 |
|
project VARCHAR(#{MAX_PROJECT_NAME}) NOT NULL, \ |
69 |
|
ctime DATETIME NOT NULL, \ |
70 |
|
actions MEDIUMBLOB NOT NULL \ |
71 |
|
)") |
72 |
|
end |
73 |
|
end |
74 |
|
|
75 |
def initialize(config) |
def initialize(config) |
76 |
|
@config = config |
77 |
|
@db = Mysql.new(config.db_host, config.db_user, |
78 |
|
config.db_password, config.db_name) |
79 |
|
@db.query_with_result = false |
80 |
end |
end |
81 |
|
|
82 |
def lock(project = nil, read_only = true) |
private |
83 |
|
|
84 |
|
def bug_table(project); '_' + project + ':bug'; end |
85 |
|
def followup_table(project); '_' + project + ':followup'; end |
86 |
|
def sf_table(project); '_' + project + ':sf'; end |
87 |
|
def tf_table(project); '_' + project + ':tf'; end |
88 |
|
def admins_table(project); '_' + project + ':admins'; end |
89 |
|
def lists_table(project); '_' + project + ':lists'; end |
90 |
|
|
91 |
|
def e(str) |
92 |
|
Mysql.escape_string(str) |
93 |
end |
end |
94 |
|
|
95 |
|
def q(str) |
96 |
|
@db.query(str) |
97 |
|
end |
98 |
|
|
99 |
|
def r() |
100 |
|
@db.store_result() |
101 |
|
end |
102 |
|
|
103 |
|
public |
104 |
|
|
105 |
|
def lock(project = nil, read_only = true) |
106 |
|
query = 'LOCK TABLES ' |
107 |
|
if project or read_only |
108 |
|
query += 'projects READ, confirmations READ' |
109 |
|
else |
110 |
|
query += 'projects WRITE, confirmations WRITE' |
111 |
|
end |
112 |
|
|
113 |
|
if project |
114 |
|
tables = [bug_table(project), followup_table(project), |
115 |
|
sf_table(project), tf_project(project), admins_table(project), |
116 |
|
lists_table(project)] |
117 |
|
query += ', ' + tables.collect {|t| |
118 |
|
e(t) + if read_only then ' READ' else ' WRITE' end |
119 |
|
}.join(', ') |
120 |
|
end |
121 |
|
|
122 |
|
begin |
123 |
|
q(query) |
124 |
|
rescue MysqlError => e |
125 |
|
if e.errno == MysqlError::ER_NO_SUCH_TABLE |
126 |
|
if project |
127 |
|
raise MalformedRequestError, "no such project `#{project}'" |
128 |
|
else |
129 |
|
raise MalformedDataError, "system table is missing" |
130 |
|
end |
131 |
|
end |
132 |
|
end |
133 |
|
end |
134 |
|
|
135 |
def unlock |
def unlock |
136 |
|
q('UNLOCK TABLES') |
137 |
end |
end |
138 |
|
|
139 |
def close |
def close() |
140 |
|
if @db |
141 |
|
@db.close |
142 |
|
@db = nil |
143 |
|
end |
144 |
end |
end |
145 |
|
|
146 |
def confirm(cid) |
def confirm(cid) |
149 |
def add_followup(project, bug_id, message) |
def add_followup(project, bug_id, message) |
150 |
end |
end |
151 |
|
|
152 |
def projects |
def projects() |
153 |
PROJECTS |
q('SELECT name FROM projects') |
154 |
|
r().collect {|a| a[0]} |
155 |
end |
end |
156 |
|
|
157 |
def include?(project) |
def include?(project) |
158 |
PROJECTS.include?(project) |
q("SELECT name FROM projects WHERE name = '#{e(project)}'") |
159 |
|
case r().num_rows() |
160 |
|
when 0 |
161 |
|
false |
162 |
|
when 1 |
163 |
|
true |
164 |
|
else |
165 |
|
raise MalformedDataError, "the project `#{project}' is duplicated" |
166 |
|
end |
167 |
end |
end |
168 |
|
|
169 |
def store_actions(actions) |
def store_actions(actions) |
170 |
cid = Time.now.strftime("%y%j%H%M%S") |
actions = actions.to_a unless actions.kind_of?(Array) |
171 |
8.times do |
project = actions.first.project |
172 |
cid << sprintf("%x", rand(16)) |
|
173 |
|
cid = nil |
174 |
|
while true |
175 |
|
cid = Time.now.strftime("%Y%j%H%M%S") |
176 |
|
(SIZE_OF_CID - cid.length).times do |
177 |
|
cid << sprintf("%x", rand(16)) |
178 |
|
end |
179 |
|
|
180 |
|
q("SELECT cid FROM confirmations WHERE cid = '#{e(cid)}'") |
181 |
|
break if r().num_rows() == 0 |
182 |
end |
end |
183 |
|
|
184 |
|
q("INSERT INTO confirmations VALUES ( \ |
185 |
|
'#{e(cid)}', \ |
186 |
|
'#{e(project)}', \ |
187 |
|
NOW(), \ |
188 |
|
'#{e(Marshal.dump(actions))}' \ |
189 |
|
)") |
190 |
cid |
cid |
191 |
end |
end |
192 |
|
|