sequel 3.33.0 → 3.34.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +140 -0
- data/Rakefile +7 -0
- data/bin/sequel +22 -2
- data/doc/dataset_basics.rdoc +1 -1
- data/doc/mass_assignment.rdoc +3 -1
- data/doc/querying.rdoc +28 -4
- data/doc/reflection.rdoc +23 -3
- data/doc/release_notes/3.34.0.txt +671 -0
- data/doc/schema_modification.rdoc +18 -2
- data/doc/virtual_rows.rdoc +49 -0
- data/lib/sequel/adapters/do/mysql.rb +0 -5
- data/lib/sequel/adapters/ibmdb.rb +9 -4
- data/lib/sequel/adapters/jdbc.rb +9 -4
- data/lib/sequel/adapters/jdbc/h2.rb +8 -2
- data/lib/sequel/adapters/jdbc/mysql.rb +0 -5
- data/lib/sequel/adapters/jdbc/postgresql.rb +43 -0
- data/lib/sequel/adapters/jdbc/sqlite.rb +19 -0
- data/lib/sequel/adapters/mock.rb +24 -3
- data/lib/sequel/adapters/mysql.rb +29 -50
- data/lib/sequel/adapters/mysql2.rb +13 -28
- data/lib/sequel/adapters/oracle.rb +8 -2
- data/lib/sequel/adapters/postgres.rb +115 -20
- data/lib/sequel/adapters/shared/db2.rb +1 -1
- data/lib/sequel/adapters/shared/mssql.rb +14 -3
- data/lib/sequel/adapters/shared/mysql.rb +59 -11
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +6 -0
- data/lib/sequel/adapters/shared/oracle.rb +1 -1
- data/lib/sequel/adapters/shared/postgres.rb +127 -30
- data/lib/sequel/adapters/shared/sqlite.rb +55 -38
- data/lib/sequel/adapters/sqlite.rb +9 -3
- data/lib/sequel/adapters/swift.rb +2 -2
- data/lib/sequel/adapters/swift/mysql.rb +0 -5
- data/lib/sequel/adapters/swift/postgres.rb +10 -0
- data/lib/sequel/ast_transformer.rb +4 -0
- data/lib/sequel/connection_pool.rb +8 -0
- data/lib/sequel/connection_pool/sharded_single.rb +5 -0
- data/lib/sequel/connection_pool/sharded_threaded.rb +17 -0
- data/lib/sequel/connection_pool/single.rb +5 -0
- data/lib/sequel/connection_pool/threaded.rb +14 -0
- data/lib/sequel/core.rb +24 -3
- data/lib/sequel/database/connecting.rb +24 -14
- data/lib/sequel/database/dataset_defaults.rb +1 -0
- data/lib/sequel/database/misc.rb +16 -25
- data/lib/sequel/database/query.rb +20 -2
- data/lib/sequel/database/schema_generator.rb +2 -2
- data/lib/sequel/database/schema_methods.rb +120 -23
- data/lib/sequel/dataset/actions.rb +91 -18
- data/lib/sequel/dataset/features.rb +5 -0
- data/lib/sequel/dataset/prepared_statements.rb +6 -2
- data/lib/sequel/dataset/sql.rb +68 -51
- data/lib/sequel/extensions/_pretty_table.rb +79 -0
- data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +18 -13
- data/lib/sequel/extensions/migration.rb +4 -0
- data/lib/sequel/extensions/null_dataset.rb +90 -0
- data/lib/sequel/extensions/pg_array.rb +460 -0
- data/lib/sequel/extensions/pg_array_ops.rb +220 -0
- data/lib/sequel/extensions/pg_auto_parameterize.rb +174 -0
- data/lib/sequel/extensions/pg_hstore.rb +296 -0
- data/lib/sequel/extensions/pg_hstore_ops.rb +259 -0
- data/lib/sequel/extensions/pg_statement_cache.rb +316 -0
- data/lib/sequel/extensions/pretty_table.rb +5 -71
- data/lib/sequel/extensions/query_literals.rb +79 -0
- data/lib/sequel/extensions/schema_caching.rb +76 -0
- data/lib/sequel/extensions/schema_dumper.rb +227 -31
- data/lib/sequel/extensions/select_remove.rb +35 -0
- data/lib/sequel/extensions/sql_expr.rb +4 -110
- data/lib/sequel/extensions/to_dot.rb +1 -1
- data/lib/sequel/model.rb +11 -2
- data/lib/sequel/model/associations.rb +35 -7
- data/lib/sequel/model/base.rb +159 -36
- data/lib/sequel/no_core_ext.rb +2 -0
- data/lib/sequel/plugins/caching.rb +25 -18
- data/lib/sequel/plugins/composition.rb +1 -1
- data/lib/sequel/plugins/hook_class_methods.rb +1 -1
- data/lib/sequel/plugins/identity_map.rb +11 -3
- data/lib/sequel/plugins/instance_filters.rb +10 -0
- data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
- data/lib/sequel/plugins/nested_attributes.rb +4 -3
- data/lib/sequel/plugins/prepared_statements.rb +3 -1
- data/lib/sequel/plugins/prepared_statements_associations.rb +5 -1
- data/lib/sequel/plugins/schema.rb +7 -2
- data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
- data/lib/sequel/plugins/static_cache.rb +99 -0
- data/lib/sequel/plugins/validation_class_methods.rb +1 -1
- data/lib/sequel/sql.rb +417 -7
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/firebird_spec.rb +1 -1
- data/spec/adapters/mssql_spec.rb +12 -15
- data/spec/adapters/mysql_spec.rb +81 -23
- data/spec/adapters/postgres_spec.rb +444 -77
- data/spec/adapters/spec_helper.rb +2 -0
- data/spec/adapters/sqlite_spec.rb +8 -8
- data/spec/core/connection_pool_spec.rb +85 -0
- data/spec/core/database_spec.rb +29 -5
- data/spec/core/dataset_spec.rb +171 -3
- data/spec/core/expression_filters_spec.rb +364 -0
- data/spec/core/mock_adapter_spec.rb +17 -3
- data/spec/core/schema_spec.rb +133 -0
- data/spec/extensions/association_dependencies_spec.rb +13 -13
- data/spec/extensions/caching_spec.rb +26 -3
- data/spec/extensions/class_table_inheritance_spec.rb +2 -2
- data/spec/{core/core_sql_spec.rb → extensions/core_extensions_spec.rb} +23 -94
- data/spec/extensions/force_encoding_spec.rb +4 -2
- data/spec/extensions/hook_class_methods_spec.rb +5 -2
- data/spec/extensions/identity_map_spec.rb +17 -0
- data/spec/extensions/instance_filters_spec.rb +1 -1
- data/spec/extensions/lazy_attributes_spec.rb +2 -2
- data/spec/extensions/list_spec.rb +4 -4
- data/spec/extensions/many_to_one_pk_lookup_spec.rb +140 -0
- data/spec/extensions/migration_spec.rb +6 -2
- data/spec/extensions/nested_attributes_spec.rb +20 -0
- data/spec/extensions/null_dataset_spec.rb +85 -0
- data/spec/extensions/optimistic_locking_spec.rb +2 -2
- data/spec/extensions/pg_array_ops_spec.rb +105 -0
- data/spec/extensions/pg_array_spec.rb +196 -0
- data/spec/extensions/pg_auto_parameterize_spec.rb +64 -0
- data/spec/extensions/pg_hstore_ops_spec.rb +136 -0
- data/spec/extensions/pg_hstore_spec.rb +195 -0
- data/spec/extensions/pg_statement_cache_spec.rb +209 -0
- data/spec/extensions/prepared_statements_spec.rb +4 -0
- data/spec/extensions/pretty_table_spec.rb +6 -0
- data/spec/extensions/query_literals_spec.rb +168 -0
- data/spec/extensions/schema_caching_spec.rb +41 -0
- data/spec/extensions/schema_dumper_spec.rb +231 -11
- data/spec/extensions/schema_spec.rb +14 -2
- data/spec/extensions/select_remove_spec.rb +38 -0
- data/spec/extensions/sharding_spec.rb +6 -6
- data/spec/extensions/skip_create_refresh_spec.rb +1 -1
- data/spec/extensions/spec_helper.rb +2 -1
- data/spec/extensions/sql_expr_spec.rb +28 -19
- data/spec/extensions/static_cache_spec.rb +145 -0
- data/spec/extensions/touch_spec.rb +1 -1
- data/spec/extensions/typecast_on_load_spec.rb +9 -1
- data/spec/integration/associations_test.rb +6 -6
- data/spec/integration/database_test.rb +1 -1
- data/spec/integration/dataset_test.rb +89 -26
- data/spec/integration/migrator_test.rb +2 -3
- data/spec/integration/model_test.rb +3 -3
- data/spec/integration/plugin_test.rb +85 -22
- data/spec/integration/prepared_statement_test.rb +28 -8
- data/spec/integration/schema_test.rb +78 -7
- data/spec/integration/spec_helper.rb +1 -0
- data/spec/integration/timezone_test.rb +1 -1
- data/spec/integration/transaction_test.rb +4 -6
- data/spec/integration/type_test.rb +2 -2
- data/spec/model/associations_spec.rb +94 -8
- data/spec/model/base_spec.rb +4 -4
- data/spec/model/hooks_spec.rb +2 -2
- data/spec/model/model_spec.rb +19 -7
- data/spec/model/record_spec.rb +135 -58
- data/spec/model/spec_helper.rb +1 -0
- metadata +35 -7
@@ -143,9 +143,10 @@ as it's third argument. A simple example is:
|
|
143
143
|
on most databases.
|
144
144
|
:on_delete :: Specify the behavior of this foreign key column when the row with the primary key
|
145
145
|
it references is deleted , can be :restrict, :cascade, :set_null, or :set_default.
|
146
|
+
You can also use a string, which is used literally.
|
146
147
|
:on_update :: Specify the behavior of this foreign key column when the row with the primary key
|
147
|
-
it references modifies the value of the primary key
|
148
|
-
:
|
148
|
+
it references modifies the value of the primary key. Takes the same options as
|
149
|
+
:on_delete.
|
149
150
|
|
150
151
|
Like +primary_key+, if you provide +foreign_key+ with an array of symbols, it will not create a
|
151
152
|
column, but create a foreign key constraint:
|
@@ -253,6 +254,21 @@ and it creates an unnamed constraint
|
|
253
254
|
check{char_length(name) > 2}
|
254
255
|
end
|
255
256
|
|
257
|
+
== +create_join_table+
|
258
|
+
|
259
|
+
+create_join_table+ is a shortcut that you can use to create simple many-to-many join tables:
|
260
|
+
|
261
|
+
create_join_table(:artist_id=>:artists, :album_id=>:albums)
|
262
|
+
|
263
|
+
which expands to:
|
264
|
+
|
265
|
+
create_table(:albums_artists) do
|
266
|
+
foreign_key :album_id, :albums, :null=>false
|
267
|
+
foreign_key :artist_id, :artists, :null=>false
|
268
|
+
primary_key [:album_id, :artist_id]
|
269
|
+
index [:artist_id, :album_id]
|
270
|
+
end
|
271
|
+
|
256
272
|
== +alter_table+
|
257
273
|
|
258
274
|
+alter_table+ is used to alter existing tables, changing their columns, indexes,
|
data/doc/virtual_rows.rdoc
CHANGED
@@ -205,6 +205,55 @@ call, with an optional hash as the second argument: Here are some examples of us
|
|
205
205
|
ds.select{sum(:over, :args=>col1, :partition=>col2, :order=>col3){}}
|
206
206
|
# SELECT sum(col1) OVER (PARTITION BY col2 ORDER BY col3)
|
207
207
|
|
208
|
+
== Operators
|
209
|
+
|
210
|
+
VirtualRows use method_missing to handle almost all method calls. However, they
|
211
|
+
have special handling of some operator methods to make certain things easier. The
|
212
|
+
operators all use a prefix form.
|
213
|
+
|
214
|
+
=== Math Operators
|
215
|
+
|
216
|
+
The standard +, -, *, and / mathematical operators are defined:
|
217
|
+
|
218
|
+
ds.select{|o| o.-(1, o.a).as(b)}
|
219
|
+
ds.select{self.-(1, a).as(b)}
|
220
|
+
# SELECT (1 - a) AS b
|
221
|
+
|
222
|
+
=== Boolean Operators
|
223
|
+
|
224
|
+
The & and | methods are defined to use AND and OR:
|
225
|
+
|
226
|
+
ds.where{|o| o.&({:a=>:b}, :c)}
|
227
|
+
ds.where{self.&({:a=>:b}, :c)}
|
228
|
+
# WHERE ((a = b) AND c)
|
229
|
+
|
230
|
+
The ~ method is defined to do inversion:
|
231
|
+
|
232
|
+
ds.where{|o| o.~({:a=>1, :b=>2})}
|
233
|
+
ds.where{self.~({:a=>1, :b=>2})}
|
234
|
+
# WHERE ((a != 1) OR (b != 2))
|
235
|
+
|
236
|
+
=== Inequality Operators
|
237
|
+
|
238
|
+
The standard >, <, >=, and <= inequality operators are defined:
|
239
|
+
|
240
|
+
ds.where{|o| o.>(1, :c)}
|
241
|
+
ds.where{self.>(1, :c)}
|
242
|
+
# WHERE (1 > c)
|
243
|
+
|
244
|
+
== Literal Strings
|
245
|
+
|
246
|
+
The backtick operator can be used inside an instance-evaled
|
247
|
+
virtual row block to create a literal string:
|
248
|
+
|
249
|
+
ds.where{a > `some SQL`}
|
250
|
+
# WHERE (a > some SQL)
|
251
|
+
|
252
|
+
You can use this on a regular virtual row block too, but it
|
253
|
+
doesn't look as nice:
|
254
|
+
|
255
|
+
ds.where{|o| o.>(:a, o.`('some SQL')}
|
256
|
+
|
208
257
|
== Returning multiple values
|
209
258
|
|
210
259
|
It's common when using select and order virtual row blocks to want to
|
@@ -174,7 +174,7 @@ module Sequel
|
|
174
174
|
# REORG the related table whenever it is altered. This is not always
|
175
175
|
# required, but it is necessary for compatibilty with other Sequel
|
176
176
|
# code in many cases.
|
177
|
-
def alter_table(name, generator=nil
|
177
|
+
def alter_table(name, generator=nil)
|
178
178
|
res = super
|
179
179
|
reorg(name)
|
180
180
|
res
|
@@ -231,11 +231,16 @@ module Sequel
|
|
231
231
|
sql = ps.prepared_sql
|
232
232
|
synchronize(opts[:server]) do |conn|
|
233
233
|
unless conn.prepared_statements.fetch(ps_name, []).first == sql
|
234
|
-
log_yield("
|
234
|
+
log_yield("PREPARE #{ps_name}: #{sql}"){conn.prepare(sql, ps_name)}
|
235
235
|
end
|
236
236
|
args = args.map{|v| v.nil? ? nil : prepared_statement_arg(v)}
|
237
|
-
|
238
|
-
|
237
|
+
log_sql = "EXECUTE #{ps_name}"
|
238
|
+
if ps.log_sql
|
239
|
+
log_sql << " ("
|
240
|
+
log_sql << sql
|
241
|
+
log_sql << ")"
|
242
|
+
end
|
243
|
+
stmt = log_yield(log_sql, args){conn.execute_prepared(ps_name, *args)}
|
239
244
|
if block_given?
|
240
245
|
begin
|
241
246
|
yield(stmt)
|
data/lib/sequel/adapters/jdbc.rb
CHANGED
@@ -343,13 +343,18 @@ module Sequel
|
|
343
343
|
if name and cps = conn.prepared_statements[name] and cps[0] == sql
|
344
344
|
cps = cps[1]
|
345
345
|
else
|
346
|
-
log_yield("
|
347
|
-
cps = log_yield("
|
346
|
+
log_yield("CLOSE #{name}"){cps[1].close} if cps
|
347
|
+
cps = log_yield("PREPARE#{" #{name}:" if name} #{sql}"){conn.prepareStatement(sql)}
|
348
348
|
conn.prepared_statements[name] = [sql, cps] if name
|
349
349
|
end
|
350
350
|
i = 0
|
351
351
|
args.each{|arg| set_ps_arg(cps, arg, i+=1)}
|
352
|
-
msg = "
|
352
|
+
msg = "EXECUTE#{" #{name}" if name}"
|
353
|
+
if ps.log_sql
|
354
|
+
msg << " ("
|
355
|
+
msg << sql
|
356
|
+
msg << ")"
|
357
|
+
end
|
353
358
|
begin
|
354
359
|
if block_given?
|
355
360
|
yield log_yield(msg, args){cps.executeQuery}
|
@@ -623,7 +628,7 @@ module Sequel
|
|
623
628
|
# Handle type conversions for common Java types.
|
624
629
|
class TYPE_TRANSLATOR
|
625
630
|
LF = "\n".freeze
|
626
|
-
def time(v) Sequel.string_to_time(v.to_string) end
|
631
|
+
def time(v) Sequel.string_to_time(v.to_string) + v.getTime.divmod(1000).last/1000.0 end
|
627
632
|
def date(v) Date.civil(v.getYear + 1900, v.getMonth + 1, v.getDate) end
|
628
633
|
def decimal(v) BigDecimal.new(v.to_string) end
|
629
634
|
def byte_array(v) Sequel::SQL::Blob.new(String.from_java_bytes(v)) end
|
@@ -25,7 +25,7 @@ module Sequel
|
|
25
25
|
|
26
26
|
# H2 uses an IDENTITY type
|
27
27
|
def serial_primary_key_options
|
28
|
-
{:primary_key => true, :type => :identity}
|
28
|
+
{:primary_key => true, :type => :identity, :identity=>true}
|
29
29
|
end
|
30
30
|
|
31
31
|
# H2 supports CREATE TABLE IF NOT EXISTS syntax.
|
@@ -114,6 +114,12 @@ module Sequel
|
|
114
114
|
def schema_column_type(db_type)
|
115
115
|
db_type == 'clob' ? :string : super
|
116
116
|
end
|
117
|
+
|
118
|
+
# Use BIGINT IDENTITY for identity columns that use bigint, fixes
|
119
|
+
# the case where primary_key :column, :type=>Bignum is used.
|
120
|
+
def type_literal_generic_bignum(column)
|
121
|
+
column[:identity] ? 'BIGINT IDENTITY' : super
|
122
|
+
end
|
117
123
|
end
|
118
124
|
|
119
125
|
# Dataset class for H2 datasets accessed via JDBC.
|
@@ -124,7 +130,7 @@ module Sequel
|
|
124
130
|
HSTAR = "H*".freeze
|
125
131
|
BITCOMP_OPEN = "((0 - ".freeze
|
126
132
|
BITCOMP_CLOSE = ") - 1)".freeze
|
127
|
-
ILIKE_PLACEHOLDER = "CAST(
|
133
|
+
ILIKE_PLACEHOLDER = ["CAST(".freeze, " AS VARCHAR_IGNORECASE)".freeze].freeze
|
128
134
|
TIME_FORMAT = "'%H:%M:%S'".freeze
|
129
135
|
|
130
136
|
# Emulate the case insensitive LIKE operator and the bitwise operators.
|
@@ -66,11 +66,6 @@ module Sequel
|
|
66
66
|
# Dataset class for MySQL datasets accessed via JDBC.
|
67
67
|
class Dataset < JDBC::Dataset
|
68
68
|
include Sequel::MySQL::DatasetMethods
|
69
|
-
|
70
|
-
# Use execute_insert to execute the replace_sql.
|
71
|
-
def replace(*args)
|
72
|
-
execute_insert(replace_sql(*args))
|
73
|
-
end
|
74
69
|
end
|
75
70
|
end
|
76
71
|
end
|
@@ -75,6 +75,49 @@ module Sequel
|
|
75
75
|
include Sequel::Postgres::DatasetMethods
|
76
76
|
APOS = Dataset::APOS
|
77
77
|
|
78
|
+
class ::Sequel::JDBC::Dataset::TYPE_TRANSLATOR
|
79
|
+
# Convert Java::OrgPostgresqlJdbc4::Jdbc4Array to ruby arrays
|
80
|
+
def pg_array(v)
|
81
|
+
_pg_array(v.array)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Convert Java::OrgPostgresqlUtil::PGobject to ruby strings
|
85
|
+
def pg_object(v)
|
86
|
+
v.to_string
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
# Handle multi-dimensional Java arrays by recursively mapping them
|
92
|
+
# to ruby arrays.
|
93
|
+
def _pg_array(v)
|
94
|
+
v.to_ary.map do |i|
|
95
|
+
if i.respond_to?(:to_ary)
|
96
|
+
_pg_array(i)
|
97
|
+
else
|
98
|
+
i
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
PG_ARRAY_METHOD = TYPE_TRANSLATOR_INSTANCE.method(:pg_array)
|
105
|
+
PG_OBJECT_METHOD = TYPE_TRANSLATOR_INSTANCE.method(:pg_object)
|
106
|
+
|
107
|
+
# Handle PostgreSQL array and object types. Object types are just
|
108
|
+
# turned into strings, similarly to how the native adapter treats
|
109
|
+
# the types.
|
110
|
+
def convert_type_proc(v)
|
111
|
+
case v
|
112
|
+
when Java::OrgPostgresqlJdbc4::Jdbc4Array
|
113
|
+
PG_ARRAY_METHOD
|
114
|
+
when Java::OrgPostgresqlUtil::PGobject
|
115
|
+
PG_OBJECT_METHOD
|
116
|
+
else
|
117
|
+
super
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
78
121
|
# Add the shared PostgreSQL prepared statement methods
|
79
122
|
def prepare(*args)
|
80
123
|
ps = super
|
@@ -8,7 +8,26 @@ module Sequel
|
|
8
8
|
module DatabaseMethods
|
9
9
|
include Sequel::SQLite::DatabaseMethods
|
10
10
|
LAST_INSERT_ROWID = 'SELECT last_insert_rowid()'.freeze
|
11
|
+
FOREIGN_KEY_ERROR_RE = /query does not return ResultSet/.freeze
|
11
12
|
|
13
|
+
# Swallow pointless exceptions when the foreign key list pragma
|
14
|
+
# doesn't return any rows.
|
15
|
+
def foreign_key_list(table, opts={})
|
16
|
+
super
|
17
|
+
rescue Sequel::DatabaseError => e
|
18
|
+
raise unless e.message =~ FOREIGN_KEY_ERROR_RE
|
19
|
+
[]
|
20
|
+
end
|
21
|
+
|
22
|
+
# Swallow pointless exceptions when the index list pragma
|
23
|
+
# doesn't return any rows.
|
24
|
+
def indexes(table, opts={})
|
25
|
+
super
|
26
|
+
rescue Sequel::DatabaseError => e
|
27
|
+
raise unless e.message =~ FOREIGN_KEY_ERROR_RE
|
28
|
+
{}
|
29
|
+
end
|
30
|
+
|
12
31
|
private
|
13
32
|
|
14
33
|
# Use last_insert_rowid() to get the last inserted id.
|
data/lib/sequel/adapters/mock.rb
CHANGED
@@ -44,6 +44,21 @@ module Sequel
|
|
44
44
|
'sqlite'=>'SQLite'
|
45
45
|
}
|
46
46
|
|
47
|
+
# Procs to run for specific database types to get the mock adapter
|
48
|
+
# to work with the shared adapter
|
49
|
+
SHARED_ADAPTER_SETUP = {
|
50
|
+
'postgres' => lambda do |db|
|
51
|
+
db.instance_eval do
|
52
|
+
@server_version = 90103
|
53
|
+
@primary_keys = {}
|
54
|
+
@primary_key_sequences = {}
|
55
|
+
def primary_key(table)
|
56
|
+
:id
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
}
|
61
|
+
|
47
62
|
# Set the autogenerated primary key integer
|
48
63
|
# to be returned when running an insert query.
|
49
64
|
# Argument types supported:
|
@@ -98,6 +113,9 @@ module Sequel
|
|
98
113
|
# instance an raise it wrapped in a DatabaseError.
|
99
114
|
attr_writer :numrows
|
100
115
|
|
116
|
+
# Mock the server version, useful when using the shared adapters
|
117
|
+
attr_accessor :server_version
|
118
|
+
|
101
119
|
# Additional options supported:
|
102
120
|
#
|
103
121
|
# :autoid :: Call #autoid= with the value
|
@@ -114,6 +132,9 @@ module Sequel
|
|
114
132
|
require "sequel/adapters/shared/#{opts[:host]}"
|
115
133
|
extend Sequel.const_get(mod_name)::DatabaseMethods
|
116
134
|
extend_datasets Sequel.const_get(mod_name)::DatasetMethods
|
135
|
+
if pr = SHARED_ADAPTER_SETUP[opts[:host]]
|
136
|
+
pr.call(self)
|
137
|
+
end
|
117
138
|
end
|
118
139
|
self.autoid = opts[:autoid]
|
119
140
|
self.columns = opts[:columns]
|
@@ -186,12 +207,12 @@ module Sequel
|
|
186
207
|
begin
|
187
208
|
if block
|
188
209
|
columns(ds, sql) if ds
|
189
|
-
_fetch(sql, ds._fetch || @fetch, &block)
|
210
|
+
_fetch(sql, (ds._fetch if ds) || @fetch, &block)
|
190
211
|
elsif meth = opts[:meth]
|
191
212
|
if meth == :numrows
|
192
|
-
_numrows(sql, ds.numrows || @numrows)
|
213
|
+
_numrows(sql, (ds.numrows if ds) || @numrows)
|
193
214
|
else
|
194
|
-
v = ds.autoid
|
215
|
+
v = ds.autoid if ds
|
195
216
|
_autoid(sql, v || @autoid, (ds if v))
|
196
217
|
end
|
197
218
|
end
|
@@ -43,6 +43,10 @@ module Sequel
|
|
43
43
|
|
44
44
|
# Mysql::Error messages that indicate the current connection should be disconnected
|
45
45
|
MYSQL_DATABASE_DISCONNECT_ERRORS = /\A(Commands out of sync; you can't run this command now|Can't connect to local MySQL server through socket|MySQL server has gone away|Lost connection to MySQL server during query)/
|
46
|
+
|
47
|
+
# Regular expression used for getting accurate number of rows
|
48
|
+
# matched by an update statement.
|
49
|
+
AFFECTED_ROWS_RE = /Rows matched:\s+(\d+)\s+Changed:\s+\d+\s+Warnings:\s+\d+/.freeze
|
46
50
|
|
47
51
|
set_adapter_scheme :mysql
|
48
52
|
|
@@ -155,6 +159,16 @@ module Sequel
|
|
155
159
|
@convert_tinyint_to_bool = v
|
156
160
|
end
|
157
161
|
|
162
|
+
# Return the number of matched rows when executing a delete/update statement.
|
163
|
+
def execute_dui(sql, opts={})
|
164
|
+
execute(sql, opts){|c| return affected_rows(c)}
|
165
|
+
end
|
166
|
+
|
167
|
+
# Return the last inserted id when executing an insert statement.
|
168
|
+
def execute_insert(sql, opts={})
|
169
|
+
execute(sql, opts){|c| return c.insert_id}
|
170
|
+
end
|
171
|
+
|
158
172
|
# Return the version of the MySQL server two which we are connecting.
|
159
173
|
def server_version(server=nil)
|
160
174
|
@server_version ||= (synchronize(server){|conn| conn.server_version if conn.respond_to?(:server_version)} || super)
|
@@ -167,7 +181,7 @@ module Sequel
|
|
167
181
|
# yield the connection if a block is given.
|
168
182
|
def _execute(conn, sql, opts)
|
169
183
|
begin
|
170
|
-
r = log_yield(sql){conn.query(sql)}
|
184
|
+
r = log_yield((log_sql = opts[:log_sql]) ? sql + log_sql : sql){conn.query(sql)}
|
171
185
|
if opts[:type] == :select
|
172
186
|
yield r if r
|
173
187
|
elsif block_given?
|
@@ -209,6 +223,18 @@ module Sequel
|
|
209
223
|
end
|
210
224
|
end
|
211
225
|
|
226
|
+
# Try to get an accurate number of rows matched using the query
|
227
|
+
# info. Fall back to affected_rows if there was no match, but
|
228
|
+
# that may be inaccurate.
|
229
|
+
def affected_rows(conn)
|
230
|
+
s = conn.info
|
231
|
+
if s && s =~ AFFECTED_ROWS_RE
|
232
|
+
$1.to_i
|
233
|
+
else
|
234
|
+
conn.affected_rows
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
212
238
|
# MySQL connections use the query method to execute SQL without a result
|
213
239
|
def connection_execute_method
|
214
240
|
:query
|
@@ -269,19 +295,10 @@ module Sequel
|
|
269
295
|
|
270
296
|
Database::DatasetClass = self
|
271
297
|
|
272
|
-
# Regular expression used for getting accurate number of rows
|
273
|
-
# matched by an update statement.
|
274
|
-
AFFECTED_ROWS_RE = /Rows matched:\s+(\d+)\s+Changed:\s+\d+\s+Warnings:\s+\d+/.freeze
|
275
|
-
|
276
|
-
# Delete rows matching this dataset
|
277
|
-
def delete
|
278
|
-
execute_dui(delete_sql){|c| return c.affected_rows}
|
279
|
-
end
|
280
|
-
|
281
298
|
# Yield all rows matching this dataset. If the dataset is set to
|
282
299
|
# split multiple statements, yield arrays of hashes one per statement
|
283
300
|
# instead of yielding results for all statements as hashes.
|
284
|
-
def fetch_rows(sql
|
301
|
+
def fetch_rows(sql)
|
285
302
|
execute(sql) do |r|
|
286
303
|
i = -1
|
287
304
|
cps = db.conversion_procs
|
@@ -298,7 +315,7 @@ module Sequel
|
|
298
315
|
yield_rows(r, cols){|h| s << h}
|
299
316
|
yield s
|
300
317
|
else
|
301
|
-
yield_rows(r, cols
|
318
|
+
yield_rows(r, cols){|h| yield h}
|
302
319
|
end
|
303
320
|
end
|
304
321
|
self
|
@@ -310,22 +327,6 @@ module Sequel
|
|
310
327
|
super
|
311
328
|
end
|
312
329
|
|
313
|
-
# Insert a new value into this dataset
|
314
|
-
def insert(*values)
|
315
|
-
execute_dui(insert_sql(*values)){|c| return c.insert_id}
|
316
|
-
end
|
317
|
-
|
318
|
-
# You can parse out the correct number of rows matched using the query info,
|
319
|
-
# even though affected_rows doesn't provide an accurate number.
|
320
|
-
def provides_accurate_rows_matched?
|
321
|
-
true
|
322
|
-
end
|
323
|
-
|
324
|
-
# Replace (update or insert) the matching row.
|
325
|
-
def replace(*args)
|
326
|
-
execute_dui(replace_sql(*args)){|c| return c.insert_id}
|
327
|
-
end
|
328
|
-
|
329
330
|
# Makes each yield arrays of rows, with each array containing the rows
|
330
331
|
# for a given result set. Does not work with graphing. So you can submit
|
331
332
|
# SQL with multiple statements and easily determine which statement
|
@@ -342,35 +343,13 @@ module Sequel
|
|
342
343
|
ds
|
343
344
|
end
|
344
345
|
|
345
|
-
# Update the matching rows.
|
346
|
-
def update(values={})
|
347
|
-
execute_dui(update_sql(values)){|c| return affected_rows(c)}
|
348
|
-
end
|
349
|
-
|
350
346
|
private
|
351
347
|
|
352
|
-
# Try to get an accurate number of rows matched using the query
|
353
|
-
# info. Fall back to affected_rows if there was no match, but
|
354
|
-
# that may be inaccurate.
|
355
|
-
def affected_rows(conn)
|
356
|
-
s = conn.info
|
357
|
-
if s && s =~ AFFECTED_ROWS_RE
|
358
|
-
$1.to_i
|
359
|
-
else
|
360
|
-
conn.affected_rows
|
361
|
-
end
|
362
|
-
end
|
363
|
-
|
364
348
|
# Set the :type option to :select if it hasn't been set.
|
365
349
|
def execute(sql, opts={}, &block)
|
366
350
|
super(sql, {:type=>:select}.merge(opts), &block)
|
367
351
|
end
|
368
352
|
|
369
|
-
# Set the :type option to :dui if it hasn't been set.
|
370
|
-
def execute_dui(sql, opts={}, &block)
|
371
|
-
super(sql, {:type=>:dui}.merge(opts), &block)
|
372
|
-
end
|
373
|
-
|
374
353
|
# Handle correct quoting of strings using ::MySQL.quote.
|
375
354
|
def literal_string_append(sql, v)
|
376
355
|
sql << "'"
|