sequel 2.9.0 → 2.10.0
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|