baza 0.0.14 → 0.0.15

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