sequel 2.9.0 → 2.10.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/CHANGELOG +56 -0
- data/{README → README.rdoc} +85 -57
- data/Rakefile +10 -5
- data/bin/sequel +7 -16
- data/doc/advanced_associations.rdoc +5 -17
- data/doc/cheat_sheet.rdoc +18 -20
- data/doc/dataset_filtering.rdoc +8 -32
- data/doc/schema.rdoc +20 -0
- data/lib/sequel_core.rb +35 -1
- data/lib/sequel_core/adapters/ado.rb +1 -1
- data/lib/sequel_core/adapters/db2.rb +2 -2
- data/lib/sequel_core/adapters/dbi.rb +2 -11
- data/lib/sequel_core/adapters/do.rb +205 -0
- data/lib/sequel_core/adapters/do/mysql.rb +38 -0
- data/lib/sequel_core/adapters/do/postgres.rb +92 -0
- data/lib/sequel_core/adapters/do/sqlite.rb +31 -0
- data/lib/sequel_core/adapters/firebird.rb +298 -0
- data/lib/sequel_core/adapters/informix.rb +10 -1
- data/lib/sequel_core/adapters/jdbc.rb +78 -19
- data/lib/sequel_core/adapters/jdbc/h2.rb +69 -0
- data/lib/sequel_core/adapters/jdbc/mysql.rb +10 -0
- data/lib/sequel_core/adapters/jdbc/postgresql.rb +7 -3
- data/lib/sequel_core/adapters/mysql.rb +53 -77
- data/lib/sequel_core/adapters/odbc.rb +1 -1
- data/lib/sequel_core/adapters/openbase.rb +1 -1
- data/lib/sequel_core/adapters/oracle.rb +2 -2
- data/lib/sequel_core/adapters/postgres.rb +16 -14
- data/lib/sequel_core/adapters/shared/mysql.rb +44 -9
- data/lib/sequel_core/adapters/shared/oracle.rb +4 -5
- data/lib/sequel_core/adapters/shared/postgres.rb +86 -82
- data/lib/sequel_core/adapters/shared/sqlite.rb +39 -24
- data/lib/sequel_core/adapters/sqlite.rb +11 -1
- data/lib/sequel_core/connection_pool.rb +10 -2
- data/lib/sequel_core/core_sql.rb +13 -3
- data/lib/sequel_core/database.rb +131 -30
- data/lib/sequel_core/database/schema.rb +5 -5
- data/lib/sequel_core/dataset.rb +31 -6
- data/lib/sequel_core/dataset/convenience.rb +11 -11
- data/lib/sequel_core/dataset/query.rb +2 -2
- data/lib/sequel_core/dataset/sql.rb +6 -6
- data/lib/sequel_core/exceptions.rb +4 -0
- data/lib/sequel_core/migration.rb +4 -4
- data/lib/sequel_core/schema/generator.rb +19 -3
- data/lib/sequel_core/schema/sql.rb +24 -20
- data/lib/sequel_core/sql.rb +13 -16
- data/lib/sequel_core/version.rb +11 -0
- data/lib/sequel_model.rb +2 -0
- data/lib/sequel_model/base.rb +2 -2
- data/lib/sequel_model/hooks.rb +46 -7
- data/lib/sequel_model/record.rb +11 -9
- data/lib/sequel_model/schema.rb +1 -1
- data/lib/sequel_model/validations.rb +72 -61
- data/spec/adapters/firebird_spec.rb +371 -0
- data/spec/adapters/mysql_spec.rb +118 -62
- data/spec/adapters/oracle_spec.rb +5 -5
- data/spec/adapters/postgres_spec.rb +33 -18
- data/spec/adapters/sqlite_spec.rb +2 -2
- data/spec/integration/dataset_test.rb +3 -3
- data/spec/integration/schema_test.rb +55 -5
- data/spec/integration/spec_helper.rb +11 -0
- data/spec/integration/type_test.rb +59 -16
- data/spec/sequel_core/connection_pool_spec.rb +14 -0
- data/spec/sequel_core/core_sql_spec.rb +24 -14
- data/spec/sequel_core/database_spec.rb +96 -11
- data/spec/sequel_core/dataset_spec.rb +97 -37
- data/spec/sequel_core/expression_filters_spec.rb +51 -40
- data/spec/sequel_core/object_graph_spec.rb +2 -2
- data/spec/sequel_core/schema_generator_spec.rb +31 -6
- data/spec/sequel_core/schema_spec.rb +25 -9
- data/spec/sequel_core/spec_helper.rb +4 -1
- data/spec/sequel_core/version_spec.rb +7 -0
- data/spec/sequel_model/associations_spec.rb +1 -1
- data/spec/sequel_model/hooks_spec.rb +68 -13
- data/spec/sequel_model/model_spec.rb +4 -4
- data/spec/sequel_model/record_spec.rb +22 -0
- data/spec/sequel_model/spec_helper.rb +2 -1
- data/spec/sequel_model/validations_spec.rb +107 -7
- metadata +15 -5
@@ -53,7 +53,16 @@ module Sequel
|
|
53
53
|
def fetch_rows(sql, &block)
|
54
54
|
execute(sql) do |cursor|
|
55
55
|
begin
|
56
|
-
|
56
|
+
col_map = nil
|
57
|
+
cursor.open.each_hash do |h|
|
58
|
+
unless col_map
|
59
|
+
col_map = {}
|
60
|
+
@columns = h.keys.map{|k| col_map[k] = output_identifier(k)}
|
61
|
+
end
|
62
|
+
h2 = {}
|
63
|
+
h.each{|k,v| h2[col_map[k]||k] = v}
|
64
|
+
yield h2
|
65
|
+
end
|
57
66
|
ensure
|
58
67
|
cursor.drop
|
59
68
|
end
|
@@ -61,6 +61,12 @@ module Sequel
|
|
61
61
|
require 'sequel_core/adapters/shared/mssql'
|
62
62
|
db.extend(Sequel::MSSQL::DatabaseMethods)
|
63
63
|
com.microsoft.sqlserver.jdbc.SQLServerDriver
|
64
|
+
end,
|
65
|
+
:h2=>proc do |db|
|
66
|
+
require 'sequel_core/adapters/jdbc/h2'
|
67
|
+
db.extend(Sequel::JDBC::H2::DatabaseMethods)
|
68
|
+
JDBC.load_gem('h2')
|
69
|
+
org.h2.Driver
|
64
70
|
end
|
65
71
|
}
|
66
72
|
|
@@ -87,11 +93,12 @@ module Sequel
|
|
87
93
|
# raise an error immediately if the connection doesn't have a
|
88
94
|
# uri, since JDBC requires one.
|
89
95
|
def initialize(opts)
|
90
|
-
|
96
|
+
@opts = opts
|
91
97
|
raise(Error, "No connection string specified") unless uri
|
92
98
|
if match = /\Ajdbc:([^:]+)/.match(uri) and prok = DATABASE_SETUP[match[1].to_sym]
|
93
99
|
prok.call(self)
|
94
100
|
end
|
101
|
+
super(opts)
|
95
102
|
end
|
96
103
|
|
97
104
|
# Execute the given stored procedure with the give name. If a block is
|
@@ -178,6 +185,14 @@ module Sequel
|
|
178
185
|
execute(sql, {:type=>:insert}.merge(opts))
|
179
186
|
end
|
180
187
|
|
188
|
+
# All tables in this database
|
189
|
+
def tables
|
190
|
+
ts = []
|
191
|
+
ds = dataset
|
192
|
+
metadata(:getTables, nil, nil, nil, ['TABLE'].to_java(:string)){|h| ts << ds.send(:output_identifier, h[:table_name])}
|
193
|
+
ts
|
194
|
+
end
|
195
|
+
|
181
196
|
# Default transaction method that should work on most JDBC
|
182
197
|
# databases. Does not use the JDBC transaction methods, uses
|
183
198
|
# SQL BEGIN/ROLLBACK/COMMIT statements instead.
|
@@ -214,10 +229,14 @@ module Sequel
|
|
214
229
|
ur = opts[:uri] || opts[:url] || opts[:database]
|
215
230
|
ur =~ /^\Ajdbc:/ ? ur : "jdbc:#{ur}"
|
216
231
|
end
|
217
|
-
alias url uri
|
218
232
|
|
219
233
|
private
|
220
234
|
|
235
|
+
# The JDBC adapter should not need the pool to convert exceptions.
|
236
|
+
def connection_pool_default_options
|
237
|
+
super.merge(:pool_convert_exceptions=>false)
|
238
|
+
end
|
239
|
+
|
221
240
|
# Close given adapter connections
|
222
241
|
def disconnect_connection(c)
|
223
242
|
c.close
|
@@ -283,6 +302,13 @@ module Sequel
|
|
283
302
|
nil
|
284
303
|
end
|
285
304
|
|
305
|
+
# Yield the metadata for this database
|
306
|
+
def metadata(*args, &block)
|
307
|
+
ds = dataset
|
308
|
+
ds.identifier_output_method = :downcase
|
309
|
+
synchronize{|c| ds.send(:process_result_set, c.getMetaData.send(*args), &block)}
|
310
|
+
end
|
311
|
+
|
286
312
|
# Java being java, you need to specify the type of each argument
|
287
313
|
# for the prepared statement, and bind it individually. This
|
288
314
|
# guesses which JDBC method to use, and hopefully JRuby will convert
|
@@ -313,9 +339,20 @@ module Sequel
|
|
313
339
|
conn
|
314
340
|
end
|
315
341
|
|
316
|
-
#
|
317
|
-
def
|
318
|
-
|
342
|
+
# All tables in this database
|
343
|
+
def schema_parse_table(table, opts={})
|
344
|
+
ds = dataset
|
345
|
+
schema, table = schema_and_table(table)
|
346
|
+
schema = ds.send(:input_identifier, schema) if schema
|
347
|
+
table = ds.send(:input_identifier, table)
|
348
|
+
pks, ts = [], []
|
349
|
+
metadata(:getPrimaryKeys, nil, schema, table) do |h|
|
350
|
+
pks << h[:column_name]
|
351
|
+
end
|
352
|
+
metadata(:getColumns, nil, schema, table, nil) do |h|
|
353
|
+
ts << [ds.send(:output_identifier, h[:column_name]), {:type=>schema_column_type(h[:type_name]), :db_type=>h[:type_name], :default=>(h[:column_def] == '' ? nil : h[:column_def]), :allow_null=>(h[:nullable] != 0), :primary_key=>pks.include?(h[:column_name])}]
|
354
|
+
end
|
355
|
+
ts
|
319
356
|
end
|
320
357
|
end
|
321
358
|
|
@@ -373,20 +410,7 @@ module Sequel
|
|
373
410
|
|
374
411
|
# Correctly return rows from the database and return them as hashes.
|
375
412
|
def fetch_rows(sql, &block)
|
376
|
-
execute(sql)
|
377
|
-
# get column names
|
378
|
-
meta = result.getMetaData
|
379
|
-
column_count = meta.getColumnCount
|
380
|
-
@columns = []
|
381
|
-
column_count.times {|i| @columns << meta.getColumnName(i+1).to_sym}
|
382
|
-
|
383
|
-
# get rows
|
384
|
-
while result.next
|
385
|
-
row = {}
|
386
|
-
@columns.each_with_index {|v, i| row[v] = result.getObject(i+1)}
|
387
|
-
yield row
|
388
|
-
end
|
389
|
-
end
|
413
|
+
execute(sql){|result| process_result_set(result, &block)}
|
390
414
|
self
|
391
415
|
end
|
392
416
|
|
@@ -416,10 +440,45 @@ module Sequel
|
|
416
440
|
|
417
441
|
private
|
418
442
|
|
443
|
+
# Convert the type. Used for converting Java types to ruby types.
|
444
|
+
def convert_type(v)
|
445
|
+
case v
|
446
|
+
when Java::JavaSQL::Timestamp, Java::JavaSQL::Time
|
447
|
+
v.to_string.to_sequel_time
|
448
|
+
when Java::JavaSQL::Date
|
449
|
+
v.to_string.to_date
|
450
|
+
when Java::JavaIo::BufferedReader
|
451
|
+
lines = []
|
452
|
+
while(line = v.read_line) do lines << line end
|
453
|
+
lines.join("\n")
|
454
|
+
when Java::JavaMath::BigDecimal
|
455
|
+
BigDecimal.new(v.to_string)
|
456
|
+
else
|
457
|
+
v
|
458
|
+
end
|
459
|
+
end
|
460
|
+
|
419
461
|
# Extend the dataset with the JDBC stored procedure methods.
|
420
462
|
def prepare_extend_sproc(ds)
|
421
463
|
ds.extend(StoredProcedureMethods)
|
422
464
|
end
|
465
|
+
|
466
|
+
# Split out from fetch rows to allow processing of JDBC result sets
|
467
|
+
# that don't come from issuing an SQL string.
|
468
|
+
def process_result_set(result)
|
469
|
+
# get column names
|
470
|
+
meta = result.getMetaData
|
471
|
+
column_count = meta.getColumnCount
|
472
|
+
@columns = []
|
473
|
+
column_count.times{|i| @columns << output_identifier(meta.getColumnName(i+1))}
|
474
|
+
|
475
|
+
# get rows
|
476
|
+
while result.next
|
477
|
+
row = {}
|
478
|
+
@columns.each_with_index{|v, i| row[v] = convert_type(result.getObject(i+1))}
|
479
|
+
yield row
|
480
|
+
end
|
481
|
+
end
|
423
482
|
end
|
424
483
|
end
|
425
484
|
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Sequel
|
2
|
+
module JDBC
|
3
|
+
# Database and Dataset support for H2 databases accessed via JDBC.
|
4
|
+
module H2
|
5
|
+
# Instance methods for H2 Database objects accessed via JDBC.
|
6
|
+
module DatabaseMethods
|
7
|
+
# H2 needs to add a primary key column as a constraint
|
8
|
+
def alter_table_sql(table, op)
|
9
|
+
case op[:op]
|
10
|
+
when :add_column
|
11
|
+
if op.delete(:primary_key)
|
12
|
+
sql = super(table, op)
|
13
|
+
[sql, "ALTER TABLE #{quote_schema_table(table)} ADD PRIMARY KEY (#{quote_identifier(op[:name])})"]
|
14
|
+
else
|
15
|
+
super(table, op)
|
16
|
+
end
|
17
|
+
else
|
18
|
+
super(table, op)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Return Sequel::JDBC::H2::Dataset object with the given opts.
|
23
|
+
def dataset(opts=nil)
|
24
|
+
Sequel::JDBC::H2::Dataset.new(self, opts)
|
25
|
+
end
|
26
|
+
|
27
|
+
# H2 uses an IDENTITY type
|
28
|
+
def serial_primary_key_options
|
29
|
+
{:primary_key => true, :type => :identity}
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
# Use IDENTITY() to get the last inserted id.
|
35
|
+
def last_insert_id(conn, opts={})
|
36
|
+
stmt = conn.createStatement
|
37
|
+
begin
|
38
|
+
rs = stmt.executeQuery('SELECT IDENTITY();')
|
39
|
+
rs.next
|
40
|
+
rs.getInt(1)
|
41
|
+
ensure
|
42
|
+
stmt.close
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Default to a single connection for a memory database.
|
47
|
+
def connection_pool_default_options
|
48
|
+
o = super
|
49
|
+
uri == 'jdbc:h2:mem:' ? o.merge(:max_connections=>1) : o
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Dataset class for H2 datasets accessed via JDBC.
|
54
|
+
class Dataset < JDBC::Dataset
|
55
|
+
# Use H2 syntax for Date, DateTime, and Time types.
|
56
|
+
def literal(v)
|
57
|
+
case v
|
58
|
+
when Date
|
59
|
+
v.strftime("DATE '%Y-%m-%d'")
|
60
|
+
when DateTime, Time
|
61
|
+
v.strftime("TIMESTAMP '%Y-%m-%d %H:%M:%S'")
|
62
|
+
else
|
63
|
+
super
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -46,6 +46,16 @@ module Sequel
|
|
46
46
|
execute_insert(insert_sql(*values))
|
47
47
|
end
|
48
48
|
|
49
|
+
# Handle time types correctly
|
50
|
+
def literal(v)
|
51
|
+
case v
|
52
|
+
when Time, DateTime
|
53
|
+
v.strftime("'%Y-%m-%d %H:%M:%S'")
|
54
|
+
else
|
55
|
+
super
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
49
59
|
# Use execute_insert to execute the replace_sql.
|
50
60
|
def replace(*args)
|
51
61
|
execute_insert(replace_sql(*args))
|
@@ -91,12 +91,16 @@ module Sequel
|
|
91
91
|
ps
|
92
92
|
end
|
93
93
|
|
94
|
-
# Convert Java::JavaSql::Timestamps correctly, and handle
|
95
|
-
#
|
94
|
+
# Convert Java::JavaSql::Timestamps correctly, and handle Strings
|
95
|
+
# similar to the native postgres adapter.
|
96
96
|
def literal(v)
|
97
97
|
case v
|
98
|
+
when LiteralString
|
99
|
+
v
|
98
100
|
when SQL::Blob
|
99
|
-
|
101
|
+
super
|
102
|
+
when String
|
103
|
+
db.synchronize{|c| "'#{c.escape_string(v)}'"}
|
100
104
|
when Java::JavaSql::Timestamp
|
101
105
|
"TIMESTAMP #{literal(v.to_s)}"
|
102
106
|
else
|
@@ -2,84 +2,40 @@ require 'mysql'
|
|
2
2
|
require 'sequel_core/adapters/shared/mysql'
|
3
3
|
require 'sequel_core/dataset/stored_procedures'
|
4
4
|
|
5
|
-
# Add methods to get columns, yield hashes with symbol keys, and do
|
6
|
-
# type conversion.
|
7
|
-
class Mysql::Result
|
8
|
-
# Mapping of type numbers to conversion methods.
|
9
|
-
MYSQL_TYPES = {
|
10
|
-
0 => :to_d, # MYSQL_TYPE_DECIMAL
|
11
|
-
1 => :to_i, # MYSQL_TYPE_TINY
|
12
|
-
2 => :to_i, # MYSQL_TYPE_SHORT
|
13
|
-
3 => :to_i, # MYSQL_TYPE_LONG
|
14
|
-
4 => :to_f, # MYSQL_TYPE_FLOAT
|
15
|
-
5 => :to_f, # MYSQL_TYPE_DOUBLE
|
16
|
-
# 6 => ??, # MYSQL_TYPE_NULL
|
17
|
-
7 => :to_sequel_time, # MYSQL_TYPE_TIMESTAMP
|
18
|
-
8 => :to_i, # MYSQL_TYPE_LONGLONG
|
19
|
-
9 => :to_i, # MYSQL_TYPE_INT24
|
20
|
-
10 => :to_date, # MYSQL_TYPE_DATE
|
21
|
-
11 => :to_time, # MYSQL_TYPE_TIME
|
22
|
-
12 => :to_sequel_time, # MYSQL_TYPE_DATETIME
|
23
|
-
13 => :to_i, # MYSQL_TYPE_YEAR
|
24
|
-
14 => :to_date, # MYSQL_TYPE_NEWDATE
|
25
|
-
# 15 => :to_s # MYSQL_TYPE_VARCHAR
|
26
|
-
# 16 => :to_s, # MYSQL_TYPE_BIT
|
27
|
-
246 => :to_d, # MYSQL_TYPE_NEWDECIMAL
|
28
|
-
247 => :to_i, # MYSQL_TYPE_ENUM
|
29
|
-
248 => :to_i, # MYSQL_TYPE_SET
|
30
|
-
249 => :to_blob, # MYSQL_TYPE_TINY_BLOB
|
31
|
-
250 => :to_blob, # MYSQL_TYPE_MEDIUM_BLOB
|
32
|
-
251 => :to_blob, # MYSQL_TYPE_LONG_BLOB
|
33
|
-
252 => :to_blob, # MYSQL_TYPE_BLOB
|
34
|
-
# 253 => :to_s, # MYSQL_TYPE_VAR_STRING
|
35
|
-
# 254 => :to_s, # MYSQL_TYPE_STRING
|
36
|
-
# 255 => :to_s # MYSQL_TYPE_GEOMETRY
|
37
|
-
}
|
38
|
-
|
39
|
-
# Return an array of column name symbols for this result set.
|
40
|
-
def columns(with_table = nil)
|
41
|
-
unless @columns
|
42
|
-
@column_types = []
|
43
|
-
@columns = fetch_fields.map do |f|
|
44
|
-
@column_types << f.type
|
45
|
-
(with_table ? "#{f.table}.#{f.name}" : f.name).to_sym
|
46
|
-
end
|
47
|
-
end
|
48
|
-
@columns
|
49
|
-
end
|
50
|
-
|
51
|
-
# yield a hash with symbol keys and type converted values.
|
52
|
-
def sequel_each_hash(with_table = nil)
|
53
|
-
c = columns
|
54
|
-
while row = fetch_row
|
55
|
-
h = {}
|
56
|
-
c.each_with_index {|f, i| h[f] = convert_type(row[i], @column_types[i])}
|
57
|
-
yield h
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
private
|
62
|
-
|
63
|
-
# Convert the type of v using the method in MYSQL_TYPES[type].
|
64
|
-
def convert_type(v, type)
|
65
|
-
if v
|
66
|
-
if type == 1 && Sequel.convert_tinyint_to_bool
|
67
|
-
# We special case tinyint here to avoid adding
|
68
|
-
# a method to an ancestor of Fixnum
|
69
|
-
v.to_i == 0 ? false : true
|
70
|
-
else
|
71
|
-
(t = MYSQL_TYPES[type]) ? v.send(t) : v
|
72
|
-
end
|
73
|
-
else
|
74
|
-
nil
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
end
|
79
|
-
|
80
5
|
module Sequel
|
81
6
|
# Module for holding all MySQL-related classes and modules for Sequel.
|
82
7
|
module MySQL
|
8
|
+
# Mapping of type numbers to conversion methods.
|
9
|
+
MYSQL_TYPES = {
|
10
|
+
0 => :to_d, # MYSQL_TYPE_DECIMAL
|
11
|
+
1 => :to_i, # MYSQL_TYPE_TINY
|
12
|
+
2 => :to_i, # MYSQL_TYPE_SHORT
|
13
|
+
3 => :to_i, # MYSQL_TYPE_LONG
|
14
|
+
4 => :to_f, # MYSQL_TYPE_FLOAT
|
15
|
+
5 => :to_f, # MYSQL_TYPE_DOUBLE
|
16
|
+
# 6 => ??, # MYSQL_TYPE_NULL
|
17
|
+
7 => :to_sequel_time, # MYSQL_TYPE_TIMESTAMP
|
18
|
+
8 => :to_i, # MYSQL_TYPE_LONGLONG
|
19
|
+
9 => :to_i, # MYSQL_TYPE_INT24
|
20
|
+
10 => :to_date, # MYSQL_TYPE_DATE
|
21
|
+
11 => :to_time, # MYSQL_TYPE_TIME
|
22
|
+
12 => :to_sequel_time, # MYSQL_TYPE_DATETIME
|
23
|
+
13 => :to_i, # MYSQL_TYPE_YEAR
|
24
|
+
14 => :to_date, # MYSQL_TYPE_NEWDATE
|
25
|
+
# 15 => :to_s # MYSQL_TYPE_VARCHAR
|
26
|
+
# 16 => :to_s, # MYSQL_TYPE_BIT
|
27
|
+
246 => :to_d, # MYSQL_TYPE_NEWDECIMAL
|
28
|
+
247 => :to_i, # MYSQL_TYPE_ENUM
|
29
|
+
248 => :to_i, # MYSQL_TYPE_SET
|
30
|
+
249 => :to_blob, # MYSQL_TYPE_TINY_BLOB
|
31
|
+
250 => :to_blob, # MYSQL_TYPE_MEDIUM_BLOB
|
32
|
+
251 => :to_blob, # MYSQL_TYPE_LONG_BLOB
|
33
|
+
252 => :to_blob, # MYSQL_TYPE_BLOB
|
34
|
+
# 253 => :to_s, # MYSQL_TYPE_VAR_STRING
|
35
|
+
# 254 => :to_s, # MYSQL_TYPE_STRING
|
36
|
+
# 255 => :to_s # MYSQL_TYPE_GEOMETRY
|
37
|
+
}
|
38
|
+
|
83
39
|
# Database class for MySQL databases used with Sequel.
|
84
40
|
class Database < Sequel::Database
|
85
41
|
include Sequel::MySQL::DatabaseMethods
|
@@ -316,8 +272,13 @@ module Sequel
|
|
316
272
|
# Yield all rows matching this dataset
|
317
273
|
def fetch_rows(sql)
|
318
274
|
execute(sql) do |r|
|
319
|
-
|
320
|
-
r.
|
275
|
+
column_types = []
|
276
|
+
@columns = r.fetch_fields.map{|f| column_types << f.type; output_identifier(f.name)}
|
277
|
+
while row = r.fetch_row
|
278
|
+
h = {}
|
279
|
+
@columns.each_with_index {|f, i| h[f] = convert_type(row[i], column_types[i])}
|
280
|
+
yield h
|
281
|
+
end
|
321
282
|
end
|
322
283
|
self
|
323
284
|
end
|
@@ -363,6 +324,21 @@ module Sequel
|
|
363
324
|
|
364
325
|
private
|
365
326
|
|
327
|
+
# Convert the type of v using the method in MYSQL_TYPES[type].
|
328
|
+
def convert_type(v, type)
|
329
|
+
if v
|
330
|
+
if type == 1 && Sequel.convert_tinyint_to_bool
|
331
|
+
# We special case tinyint here to avoid adding
|
332
|
+
# a method to an ancestor of Fixnum
|
333
|
+
v.to_i == 0 ? false : true
|
334
|
+
else
|
335
|
+
(t = MYSQL_TYPES[type]) ? v.send(t) : v
|
336
|
+
end
|
337
|
+
else
|
338
|
+
nil
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
366
342
|
# Set the :type option to :select if it hasn't been set.
|
367
343
|
def execute(sql, opts={}, &block)
|
368
344
|
super(sql, {:type=>:select}.merge(opts), &block)
|