baza 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +18 -0
- data/Gemfile.lock +55 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +19 -0
- data/Rakefile +49 -0
- data/VERSION +1 -0
- data/include/db.rb +784 -0
- data/include/dbtime.rb +35 -0
- data/include/drivers/.DS_Store +0 -0
- data/include/drivers/mysql/mysql.rb +604 -0
- data/include/drivers/mysql/mysql_columns.rb +155 -0
- data/include/drivers/mysql/mysql_indexes.rb +69 -0
- data/include/drivers/mysql/mysql_sqlspecs.rb +5 -0
- data/include/drivers/mysql/mysql_tables.rb +443 -0
- data/include/drivers/sqlite3/libknjdb_java_sqlite3.rb +83 -0
- data/include/drivers/sqlite3/libknjdb_sqlite3_ironruby.rb +69 -0
- data/include/drivers/sqlite3/sqlite3.rb +184 -0
- data/include/drivers/sqlite3/sqlite3_columns.rb +177 -0
- data/include/drivers/sqlite3/sqlite3_indexes.rb +29 -0
- data/include/drivers/sqlite3/sqlite3_sqlspecs.rb +5 -0
- data/include/drivers/sqlite3/sqlite3_tables.rb +449 -0
- data/include/dump.rb +122 -0
- data/include/idquery.rb +109 -0
- data/include/model.rb +873 -0
- data/include/model_custom.rb +153 -0
- data/include/model_handler.rb +957 -0
- data/include/model_handler_sqlhelper.rb +499 -0
- data/include/query_buffer.rb +87 -0
- data/include/revision.rb +342 -0
- data/include/row.rb +153 -0
- data/include/sqlspecs.rb +5 -0
- data/lib/baza.rb +8 -0
- data/spec/baza_spec.rb +286 -0
- data/spec/db_spec_encoding_test_file.txt +1 -0
- data/spec/spec_helper.rb +12 -0
- metadata +215 -0
data/include/dbtime.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
#This class helps handeling time-columns in databases.
|
2
|
+
class Baza::Dbtime
|
3
|
+
#These variables return information about the object.
|
4
|
+
attr_reader :hours, :mins, :secs, :total_secs
|
5
|
+
|
6
|
+
#Initializes the object from arguments useually given by Baza::Datarow.
|
7
|
+
def initialize(args)
|
8
|
+
args = {:time => args} if args.is_a?(String)
|
9
|
+
|
10
|
+
raise "Invalid arguments given." if !args.is_a?(Hash)
|
11
|
+
raise "No time given." if !args[:time]
|
12
|
+
raise "Invalid time given." if !args[:time].is_a?(String)
|
13
|
+
|
14
|
+
match = args[:time].match(/^(\d+):(\d+):(\d+)$/)
|
15
|
+
raise "Could not understand time format." if !match
|
16
|
+
|
17
|
+
@hours = match[1].to_i
|
18
|
+
@mins = match[2].to_i
|
19
|
+
@secs = match[3].to_i
|
20
|
+
|
21
|
+
@total_secs = @hours * 3600
|
22
|
+
@total_secs += @mins * 60
|
23
|
+
@total_secs += @secs
|
24
|
+
end
|
25
|
+
|
26
|
+
#Returns the total amount of hours.
|
27
|
+
def hours_total
|
28
|
+
return (@total_secs.to_f / 3600)
|
29
|
+
end
|
30
|
+
|
31
|
+
#Return the total amount of minutes.
|
32
|
+
def mins_total
|
33
|
+
return (@total_secs.to_f / 60)
|
34
|
+
end
|
35
|
+
end
|
Binary file
|
@@ -0,0 +1,604 @@
|
|
1
|
+
class Baza::Driver::Mysql
|
2
|
+
attr_reader :knjdb, :conn, :conns, :sep_table, :sep_col, :sep_val
|
3
|
+
attr_accessor :tables, :cols, :indexes
|
4
|
+
|
5
|
+
def initialize(knjdb_ob)
|
6
|
+
@knjdb = knjdb_ob
|
7
|
+
@opts = @knjdb.opts
|
8
|
+
@sep_table = "`"
|
9
|
+
@sep_col = "`"
|
10
|
+
@sep_val = "'"
|
11
|
+
|
12
|
+
require "monitor"
|
13
|
+
@mutex = Monitor.new
|
14
|
+
|
15
|
+
if @opts[:encoding]
|
16
|
+
@encoding = @opts[:encoding]
|
17
|
+
else
|
18
|
+
@encoding = "utf8"
|
19
|
+
end
|
20
|
+
|
21
|
+
if @knjdb.opts.key?(:port)
|
22
|
+
@port = @knjdb.opts[:port].to_i
|
23
|
+
else
|
24
|
+
@port = 3306
|
25
|
+
end
|
26
|
+
|
27
|
+
@java_rs_data = {}
|
28
|
+
@subtype = @knjdb.opts[:subtype]
|
29
|
+
@subtype = "mysql" if @subtype.to_s.length <= 0
|
30
|
+
self.reconnect
|
31
|
+
end
|
32
|
+
|
33
|
+
#This method handels the closing of statements and results for the Java MySQL-mode.
|
34
|
+
def java_mysql_resultset_killer(id)
|
35
|
+
data = @java_rs_data[id]
|
36
|
+
return nil if !data
|
37
|
+
|
38
|
+
data[:res].close
|
39
|
+
data[:stmt].close
|
40
|
+
@java_rs_data.delete(id)
|
41
|
+
end
|
42
|
+
|
43
|
+
#Cleans the wref-map holding the tables.
|
44
|
+
def clean
|
45
|
+
self.tables.clean if self.tables
|
46
|
+
end
|
47
|
+
|
48
|
+
#Respawns the connection to the MySQL-database.
|
49
|
+
def reconnect
|
50
|
+
@mutex.synchronize do
|
51
|
+
case @subtype
|
52
|
+
when "mysql"
|
53
|
+
@conn = Mysql.real_connect(@knjdb.opts[:host], @knjdb.opts[:user], @knjdb.opts[:pass], @knjdb.opts[:db], @port)
|
54
|
+
when "mysql2"
|
55
|
+
require "rubygems"
|
56
|
+
require "mysql2"
|
57
|
+
|
58
|
+
args = {
|
59
|
+
:host => @knjdb.opts[:host],
|
60
|
+
:username => @knjdb.opts[:user],
|
61
|
+
:password => @knjdb.opts[:pass],
|
62
|
+
:database => @knjdb.opts[:db],
|
63
|
+
:port => @port,
|
64
|
+
:symbolize_keys => true,
|
65
|
+
:cache_rows => false
|
66
|
+
}
|
67
|
+
|
68
|
+
#Symbolize keys should also be given here, else table-data wont be symbolized for some reason - knj.
|
69
|
+
@query_args = {:symbolize_keys => true}
|
70
|
+
@query_args.merge!(@knjdb.opts[:query_args]) if @knjdb.opts[:query_args]
|
71
|
+
|
72
|
+
pos_args = [:as, :async, :cast_booleans, :database_timezone, :application_timezone, :cache_rows, :connect_flags, :cast]
|
73
|
+
pos_args.each do |key|
|
74
|
+
args[key] = @knjdb.opts[key] if @knjdb.opts.key?(key)
|
75
|
+
end
|
76
|
+
|
77
|
+
args[:as] = :array if @opts[:result] == "array"
|
78
|
+
|
79
|
+
tries = 0
|
80
|
+
begin
|
81
|
+
tries += 1
|
82
|
+
@conn = Mysql2::Client.new(args)
|
83
|
+
rescue => e
|
84
|
+
if tries <= 3
|
85
|
+
if e.message == "Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (111)"
|
86
|
+
sleep 1
|
87
|
+
retry
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
raise e
|
92
|
+
end
|
93
|
+
when "java"
|
94
|
+
if !@jdbc_loaded
|
95
|
+
require "java"
|
96
|
+
require "/usr/share/java/mysql-connector-java.jar" if File.exists?("/usr/share/java/mysql-connector-java.jar")
|
97
|
+
import "com.mysql.jdbc.Driver"
|
98
|
+
@jdbc_loaded = true
|
99
|
+
end
|
100
|
+
|
101
|
+
@conn = java.sql::DriverManager.getConnection("jdbc:mysql://#{@knjdb.opts[:host]}:#{@port}/#{@knjdb.opts[:db]}?user=#{@knjdb.opts[:user]}&password=#{@knjdb.opts[:pass]}&populateInsertRowWithDefaultValues=true&zeroDateTimeBehavior=round&characterEncoding=#{@encoding}&holdResultsOpenOverStatementClose=true")
|
102
|
+
self.query("SET SQL_MODE = ''")
|
103
|
+
else
|
104
|
+
raise "Unknown subtype: #{@subtype}"
|
105
|
+
end
|
106
|
+
|
107
|
+
self.query("SET NAMES '#{self.esc(@encoding)}'") if @encoding
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
#Executes a query and returns the result.
|
112
|
+
def query(str)
|
113
|
+
str = str.to_s
|
114
|
+
str = str.force_encoding("UTF-8") if @encoding == "utf8" and str.respond_to?(:force_encoding)
|
115
|
+
tries = 0
|
116
|
+
|
117
|
+
begin
|
118
|
+
tries += 1
|
119
|
+
@mutex.synchronize do
|
120
|
+
case @subtype
|
121
|
+
when "mysql"
|
122
|
+
return Baza::Driver::Mysql_result.new(self, @conn.query(str))
|
123
|
+
when "mysql2"
|
124
|
+
return Baza::Driver::Mysql2_result.new(@conn.query(str, @query_args))
|
125
|
+
when "java"
|
126
|
+
stmt = conn.create_statement
|
127
|
+
|
128
|
+
if str.match(/^\s*(delete|update|create|drop|insert\s+into|alter)\s+/i)
|
129
|
+
begin
|
130
|
+
stmt.execute(str)
|
131
|
+
ensure
|
132
|
+
stmt.close
|
133
|
+
end
|
134
|
+
|
135
|
+
return nil
|
136
|
+
else
|
137
|
+
id = nil
|
138
|
+
|
139
|
+
begin
|
140
|
+
res = stmt.execute_query(str)
|
141
|
+
ret = KnjDB_java_mysql_result.new(@knjdb, @opts, res)
|
142
|
+
id = ret.__id__
|
143
|
+
|
144
|
+
#If ID is being reused we have to free the result.
|
145
|
+
self.java_mysql_resultset_killer(id) if @java_rs_data.key?(id)
|
146
|
+
|
147
|
+
#Save reference to result and statement, so we can close them when they are garbage collected.
|
148
|
+
@java_rs_data[id] = {:res => res, :stmt => stmt}
|
149
|
+
ObjectSpace.define_finalizer(ret, self.method(:java_mysql_resultset_killer))
|
150
|
+
|
151
|
+
return ret
|
152
|
+
rescue => e
|
153
|
+
res.close if res
|
154
|
+
stmt.close
|
155
|
+
@java_rs_data.delete(id) if ret and id
|
156
|
+
raise e
|
157
|
+
end
|
158
|
+
end
|
159
|
+
else
|
160
|
+
raise "Unknown subtype: '#{@subtype}'."
|
161
|
+
end
|
162
|
+
end
|
163
|
+
rescue => e
|
164
|
+
if tries <= 3
|
165
|
+
if e.message == "MySQL server has gone away" or e.message == "closed MySQL connection" or e.message == "Can't connect to local MySQL server through socket"
|
166
|
+
sleep 0.5
|
167
|
+
self.reconnect
|
168
|
+
retry
|
169
|
+
elsif e.message.include?("No operations allowed after connection closed") or e.message == "This connection is still waiting for a result, try again once you have the result" or e.message == "Lock wait timeout exceeded; try restarting transaction"
|
170
|
+
self.reconnect
|
171
|
+
retry
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
raise e
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
#Executes an unbuffered query and returns the result that can be used to access the data.
|
180
|
+
def query_ubuf(str)
|
181
|
+
@mutex.synchronize do
|
182
|
+
case @subtype
|
183
|
+
when "mysql"
|
184
|
+
@conn.query_with_result = false
|
185
|
+
return Baza::Driver::Mysql_unbuffered_result.new(@conn, @opts, @conn.query(str))
|
186
|
+
when "mysql2"
|
187
|
+
return Baza::Driver::Mysql2_result.new(@conn.query(str, @query_args.merge(:stream => true)))
|
188
|
+
when "java"
|
189
|
+
if str.match(/^\s*(delete|update|create|drop|insert\s+into)\s+/i)
|
190
|
+
stmt = @conn.createStatement
|
191
|
+
|
192
|
+
begin
|
193
|
+
stmt.execute(str)
|
194
|
+
ensure
|
195
|
+
stmt.close
|
196
|
+
end
|
197
|
+
|
198
|
+
return nil
|
199
|
+
else
|
200
|
+
stmt = @conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY)
|
201
|
+
stmt.setFetchSize(java.lang.Integer::MIN_VALUE)
|
202
|
+
|
203
|
+
begin
|
204
|
+
res = stmt.executeQuery(str)
|
205
|
+
ret = KnjDB_java_mysql_result.new(@knjdb, @opts, res)
|
206
|
+
|
207
|
+
#Save reference to result and statement, so we can close them when they are garbage collected.
|
208
|
+
@java_rs_data[ret.__id__] = {:res => res, :stmt => stmt}
|
209
|
+
ObjectSpace.define_finalizer(ret, self.method("java_mysql_resultset_killer"))
|
210
|
+
|
211
|
+
return ret
|
212
|
+
rescue => e
|
213
|
+
res.close if res
|
214
|
+
stmt.close
|
215
|
+
raise e
|
216
|
+
end
|
217
|
+
end
|
218
|
+
else
|
219
|
+
raise "Unknown subtype: '#{@subtype}'"
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
#Escapes a string to be safe to use in a query.
|
225
|
+
def escape_alternative(string)
|
226
|
+
case @subtype
|
227
|
+
when "mysql"
|
228
|
+
return @conn.escape_string(string.to_s)
|
229
|
+
when "mysql2"
|
230
|
+
return @conn.escape(string.to_s)
|
231
|
+
when "java"
|
232
|
+
return self.escape(string)
|
233
|
+
else
|
234
|
+
raise "Unknown subtype: '#{@subtype}'."
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
#An alternative to the MySQL framework's escape. This is copied from the Ruby/MySQL framework at: http://www.tmtm.org/en/ruby/mysql/
|
239
|
+
def escape(string)
|
240
|
+
return string.to_s.gsub(/([\0\n\r\032\'\"\\])/) do
|
241
|
+
case $1
|
242
|
+
when "\0" then "\\0"
|
243
|
+
when "\n" then "\\n"
|
244
|
+
when "\r" then "\\r"
|
245
|
+
when "\032" then "\\Z"
|
246
|
+
else "\\#{$1}"
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
#Escapes a string to be safe to use as a column in a query.
|
252
|
+
def esc_col(string)
|
253
|
+
string = string.to_s
|
254
|
+
raise "Invalid column-string: #{string}" if string.index(@sep_col) != nil
|
255
|
+
return string
|
256
|
+
end
|
257
|
+
|
258
|
+
alias :esc_table :esc_col
|
259
|
+
alias :esc :escape
|
260
|
+
|
261
|
+
#Returns the last inserted ID for the connection.
|
262
|
+
def lastID
|
263
|
+
case @subtype
|
264
|
+
when "mysql"
|
265
|
+
@mutex.synchronize do
|
266
|
+
return @conn.insert_id.to_i
|
267
|
+
end
|
268
|
+
when "mysql2"
|
269
|
+
@mutex.synchronize do
|
270
|
+
return @conn.last_id.to_i
|
271
|
+
end
|
272
|
+
when "java"
|
273
|
+
data = self.query("SELECT LAST_INSERT_ID() AS id").fetch
|
274
|
+
return data[:id].to_i if data.key?(:id)
|
275
|
+
raise "Could not figure out last inserted ID."
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
#Closes the connection threadsafe.
|
280
|
+
def close
|
281
|
+
@mutex.synchronize do
|
282
|
+
@conn.close
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
#Destroyes the connection.
|
287
|
+
def destroy
|
288
|
+
@conn = nil
|
289
|
+
@knjdb = nil
|
290
|
+
@mutex = nil
|
291
|
+
@subtype = nil
|
292
|
+
@encoding = nil
|
293
|
+
@query_args = nil
|
294
|
+
@port = nil
|
295
|
+
end
|
296
|
+
|
297
|
+
#Inserts multiple rows in a table. Can return the inserted IDs if asked to in arguments.
|
298
|
+
def insert_multi(tablename, arr_hashes, args = nil)
|
299
|
+
sql = "INSERT INTO `#{tablename}` ("
|
300
|
+
|
301
|
+
first = true
|
302
|
+
if args and args[:keys]
|
303
|
+
keys = args[:keys]
|
304
|
+
elsif arr_hashes.first.is_a?(Hash)
|
305
|
+
keys = arr_hashes.first.keys
|
306
|
+
else
|
307
|
+
raise "Could not figure out keys."
|
308
|
+
end
|
309
|
+
|
310
|
+
keys.each do |col_name|
|
311
|
+
sql << "," if !first
|
312
|
+
first = false if first
|
313
|
+
sql << "`#{self.esc_col(col_name)}`"
|
314
|
+
end
|
315
|
+
|
316
|
+
sql << ") VALUES ("
|
317
|
+
|
318
|
+
first = true
|
319
|
+
arr_hashes.each do |hash|
|
320
|
+
if first
|
321
|
+
first = false
|
322
|
+
else
|
323
|
+
sql << "),("
|
324
|
+
end
|
325
|
+
|
326
|
+
first_key = true
|
327
|
+
if hash.is_a?(Array)
|
328
|
+
hash.each do |val|
|
329
|
+
if first_key
|
330
|
+
first_key = false
|
331
|
+
else
|
332
|
+
sql << ","
|
333
|
+
end
|
334
|
+
|
335
|
+
sql << @knjdb.sqlval(val)
|
336
|
+
end
|
337
|
+
else
|
338
|
+
hash.each do |key, val|
|
339
|
+
if first_key
|
340
|
+
first_key = false
|
341
|
+
else
|
342
|
+
sql << ","
|
343
|
+
end
|
344
|
+
|
345
|
+
sql << @knjdb.sqlval(val)
|
346
|
+
end
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
sql << ")"
|
351
|
+
|
352
|
+
return sql if args and args[:return_sql]
|
353
|
+
|
354
|
+
self.query(sql)
|
355
|
+
|
356
|
+
if args and args[:return_id]
|
357
|
+
first_id = self.lastID
|
358
|
+
raise "Invalid ID: #{first_id}" if first_id.to_i <= 0
|
359
|
+
ids = [first_id]
|
360
|
+
1.upto(arr_hashes.length - 1) do |count|
|
361
|
+
ids << first_id + count
|
362
|
+
end
|
363
|
+
|
364
|
+
ids_length = ids.length
|
365
|
+
arr_hashes_length = arr_hashes.length
|
366
|
+
raise "Invalid length (#{ids_length}, #{arr_hashes_length})." if ids_length != arr_hashes_length
|
367
|
+
|
368
|
+
return ids
|
369
|
+
else
|
370
|
+
return nil
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
#Starts a transaction, yields the database and commits at the end.
|
375
|
+
def transaction
|
376
|
+
@knjdb.q("START TRANSACTION")
|
377
|
+
|
378
|
+
begin
|
379
|
+
yield(@knjdb)
|
380
|
+
ensure
|
381
|
+
@knjdb.q("COMMIT")
|
382
|
+
end
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
386
|
+
#This class controls the results for the normal MySQL-driver.
|
387
|
+
class Baza::Driver::Mysql_result
|
388
|
+
#Constructor. This should not be called manually.
|
389
|
+
def initialize(driver, result)
|
390
|
+
@driver = driver
|
391
|
+
@result = result
|
392
|
+
@mutex = Mutex.new
|
393
|
+
|
394
|
+
if @result
|
395
|
+
@keys = []
|
396
|
+
keys = @result.fetch_fields
|
397
|
+
keys.each do |key|
|
398
|
+
@keys << key.name.to_sym
|
399
|
+
end
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
403
|
+
#Returns a single result.
|
404
|
+
def fetch
|
405
|
+
return self.fetch_hash_symbols if @driver.knjdb.opts[:return_keys] == "symbols"
|
406
|
+
return self.fetch_hash_strings
|
407
|
+
end
|
408
|
+
|
409
|
+
#Returns a single result as a hash with strings as keys.
|
410
|
+
def fetch_hash_strings
|
411
|
+
@mutex.synchronize do
|
412
|
+
return @result.fetch_hash
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
#Returns a single result as a hash with symbols as keys.
|
417
|
+
def fetch_hash_symbols
|
418
|
+
fetched = nil
|
419
|
+
@mutex.synchronize do
|
420
|
+
fetched = @result.fetch_row
|
421
|
+
end
|
422
|
+
|
423
|
+
return false if !fetched
|
424
|
+
|
425
|
+
ret = {}
|
426
|
+
count = 0
|
427
|
+
@keys.each do |key|
|
428
|
+
ret[key] = fetched[count]
|
429
|
+
count += 1
|
430
|
+
end
|
431
|
+
|
432
|
+
return ret
|
433
|
+
end
|
434
|
+
|
435
|
+
#Loops over every result yielding it.
|
436
|
+
def each
|
437
|
+
while data = self.fetch_hash_symbols
|
438
|
+
yield(data)
|
439
|
+
end
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
#This class controls the unbuffered result for the normal MySQL-driver.
|
444
|
+
class Baza::Driver::Mysql_unbuffered_result
|
445
|
+
#Constructor. This should not be called manually.
|
446
|
+
def initialize(conn, opts, result)
|
447
|
+
@conn = conn
|
448
|
+
@result = result
|
449
|
+
|
450
|
+
if !opts.key?(:result) or opts[:result] == "hash"
|
451
|
+
@as_hash = true
|
452
|
+
elsif opts[:result] == "array"
|
453
|
+
@as_hash = false
|
454
|
+
else
|
455
|
+
raise "Unknown type of result: '#{opts[:result]}'."
|
456
|
+
end
|
457
|
+
end
|
458
|
+
|
459
|
+
#Lods the keys for the object.
|
460
|
+
def load_keys
|
461
|
+
@keys = []
|
462
|
+
keys = @res.fetch_fields
|
463
|
+
keys.each do |key|
|
464
|
+
@keys << key.name.to_sym
|
465
|
+
end
|
466
|
+
end
|
467
|
+
|
468
|
+
#Returns a single result.
|
469
|
+
def fetch
|
470
|
+
if @enum
|
471
|
+
begin
|
472
|
+
ret = @enum.next
|
473
|
+
rescue StopIteration
|
474
|
+
@enum = nil
|
475
|
+
@res = nil
|
476
|
+
end
|
477
|
+
end
|
478
|
+
|
479
|
+
if !ret and !@res and !@enum
|
480
|
+
begin
|
481
|
+
@res = @conn.use_result
|
482
|
+
@enum = @res.to_enum
|
483
|
+
ret = @enum.next
|
484
|
+
rescue Mysql::Error
|
485
|
+
#Reset it to run non-unbuffered again and then return false.
|
486
|
+
@conn.query_with_result = true
|
487
|
+
return false
|
488
|
+
rescue StopIteration
|
489
|
+
sleep 0.1
|
490
|
+
retry
|
491
|
+
end
|
492
|
+
end
|
493
|
+
|
494
|
+
if !@as_hash
|
495
|
+
return ret
|
496
|
+
else
|
497
|
+
self.load_keys if !@keys
|
498
|
+
|
499
|
+
ret_h = {}
|
500
|
+
@keys.each_index do |key_no|
|
501
|
+
ret_h[@keys[key_no]] = ret[key_no]
|
502
|
+
end
|
503
|
+
|
504
|
+
return ret_h
|
505
|
+
end
|
506
|
+
end
|
507
|
+
|
508
|
+
#Loops over every single result yielding it.
|
509
|
+
def each
|
510
|
+
while data = self.fetch
|
511
|
+
yield(data)
|
512
|
+
end
|
513
|
+
end
|
514
|
+
end
|
515
|
+
|
516
|
+
#This class controls the result for the MySQL2 driver.
|
517
|
+
class Baza::Driver::Mysql2_result
|
518
|
+
#Constructor. This should not be called manually.
|
519
|
+
def initialize(result)
|
520
|
+
@result = result
|
521
|
+
end
|
522
|
+
|
523
|
+
#Returns a single result.
|
524
|
+
def fetch
|
525
|
+
@enum = @result.to_enum if !@enum
|
526
|
+
|
527
|
+
begin
|
528
|
+
return @enum.next
|
529
|
+
rescue StopIteration
|
530
|
+
return false
|
531
|
+
end
|
532
|
+
end
|
533
|
+
|
534
|
+
#Loops over every single result yielding it.
|
535
|
+
def each
|
536
|
+
@result.each do |res|
|
537
|
+
#This sometimes happens when streaming results...
|
538
|
+
next if !res
|
539
|
+
yield(res)
|
540
|
+
end
|
541
|
+
end
|
542
|
+
end
|
543
|
+
|
544
|
+
#This class controls the result for the Java-MySQL-driver.
|
545
|
+
class KnjDB_java_mysql_result
|
546
|
+
#Constructor. This should not be called manually.
|
547
|
+
def initialize(knjdb, opts, result)
|
548
|
+
@knjdb = knjdb
|
549
|
+
@result = result
|
550
|
+
|
551
|
+
if !opts.key?(:result) or opts[:result] == "hash"
|
552
|
+
@as_hash = true
|
553
|
+
elsif opts[:result] == "array"
|
554
|
+
@as_hash = false
|
555
|
+
else
|
556
|
+
raise "Unknown type of result: '#{opts[:result]}'."
|
557
|
+
end
|
558
|
+
end
|
559
|
+
|
560
|
+
#Reads meta-data about the query like keys and count.
|
561
|
+
def read_meta
|
562
|
+
@result.before_first
|
563
|
+
meta = @result.meta_data
|
564
|
+
@count = meta.column_count
|
565
|
+
|
566
|
+
@keys = []
|
567
|
+
1.upto(@count) do |count|
|
568
|
+
@keys << meta.column_label(count).to_sym
|
569
|
+
end
|
570
|
+
end
|
571
|
+
|
572
|
+
def fetch
|
573
|
+
return false if !@result
|
574
|
+
self.read_meta if !@keys
|
575
|
+
status = @result.next
|
576
|
+
|
577
|
+
if !status
|
578
|
+
@result = nil
|
579
|
+
@keys = nil
|
580
|
+
@count = nil
|
581
|
+
return false
|
582
|
+
end
|
583
|
+
|
584
|
+
if @as_hash
|
585
|
+
ret = {}
|
586
|
+
1.upto(@count) do |count|
|
587
|
+
ret[@keys[count - 1]] = @result.object(count)
|
588
|
+
end
|
589
|
+
else
|
590
|
+
ret = []
|
591
|
+
1.upto(@count) do |count|
|
592
|
+
ret << @result.object(count)
|
593
|
+
end
|
594
|
+
end
|
595
|
+
|
596
|
+
return ret
|
597
|
+
end
|
598
|
+
|
599
|
+
def each
|
600
|
+
while data = self.fetch
|
601
|
+
yield(data)
|
602
|
+
end
|
603
|
+
end
|
604
|
+
end
|