sequel 3.33.0 → 3.34.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (152) hide show
  1. data/CHANGELOG +140 -0
  2. data/Rakefile +7 -0
  3. data/bin/sequel +22 -2
  4. data/doc/dataset_basics.rdoc +1 -1
  5. data/doc/mass_assignment.rdoc +3 -1
  6. data/doc/querying.rdoc +28 -4
  7. data/doc/reflection.rdoc +23 -3
  8. data/doc/release_notes/3.34.0.txt +671 -0
  9. data/doc/schema_modification.rdoc +18 -2
  10. data/doc/virtual_rows.rdoc +49 -0
  11. data/lib/sequel/adapters/do/mysql.rb +0 -5
  12. data/lib/sequel/adapters/ibmdb.rb +9 -4
  13. data/lib/sequel/adapters/jdbc.rb +9 -4
  14. data/lib/sequel/adapters/jdbc/h2.rb +8 -2
  15. data/lib/sequel/adapters/jdbc/mysql.rb +0 -5
  16. data/lib/sequel/adapters/jdbc/postgresql.rb +43 -0
  17. data/lib/sequel/adapters/jdbc/sqlite.rb +19 -0
  18. data/lib/sequel/adapters/mock.rb +24 -3
  19. data/lib/sequel/adapters/mysql.rb +29 -50
  20. data/lib/sequel/adapters/mysql2.rb +13 -28
  21. data/lib/sequel/adapters/oracle.rb +8 -2
  22. data/lib/sequel/adapters/postgres.rb +115 -20
  23. data/lib/sequel/adapters/shared/db2.rb +1 -1
  24. data/lib/sequel/adapters/shared/mssql.rb +14 -3
  25. data/lib/sequel/adapters/shared/mysql.rb +59 -11
  26. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +6 -0
  27. data/lib/sequel/adapters/shared/oracle.rb +1 -1
  28. data/lib/sequel/adapters/shared/postgres.rb +127 -30
  29. data/lib/sequel/adapters/shared/sqlite.rb +55 -38
  30. data/lib/sequel/adapters/sqlite.rb +9 -3
  31. data/lib/sequel/adapters/swift.rb +2 -2
  32. data/lib/sequel/adapters/swift/mysql.rb +0 -5
  33. data/lib/sequel/adapters/swift/postgres.rb +10 -0
  34. data/lib/sequel/ast_transformer.rb +4 -0
  35. data/lib/sequel/connection_pool.rb +8 -0
  36. data/lib/sequel/connection_pool/sharded_single.rb +5 -0
  37. data/lib/sequel/connection_pool/sharded_threaded.rb +17 -0
  38. data/lib/sequel/connection_pool/single.rb +5 -0
  39. data/lib/sequel/connection_pool/threaded.rb +14 -0
  40. data/lib/sequel/core.rb +24 -3
  41. data/lib/sequel/database/connecting.rb +24 -14
  42. data/lib/sequel/database/dataset_defaults.rb +1 -0
  43. data/lib/sequel/database/misc.rb +16 -25
  44. data/lib/sequel/database/query.rb +20 -2
  45. data/lib/sequel/database/schema_generator.rb +2 -2
  46. data/lib/sequel/database/schema_methods.rb +120 -23
  47. data/lib/sequel/dataset/actions.rb +91 -18
  48. data/lib/sequel/dataset/features.rb +5 -0
  49. data/lib/sequel/dataset/prepared_statements.rb +6 -2
  50. data/lib/sequel/dataset/sql.rb +68 -51
  51. data/lib/sequel/extensions/_pretty_table.rb +79 -0
  52. data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +18 -13
  53. data/lib/sequel/extensions/migration.rb +4 -0
  54. data/lib/sequel/extensions/null_dataset.rb +90 -0
  55. data/lib/sequel/extensions/pg_array.rb +460 -0
  56. data/lib/sequel/extensions/pg_array_ops.rb +220 -0
  57. data/lib/sequel/extensions/pg_auto_parameterize.rb +174 -0
  58. data/lib/sequel/extensions/pg_hstore.rb +296 -0
  59. data/lib/sequel/extensions/pg_hstore_ops.rb +259 -0
  60. data/lib/sequel/extensions/pg_statement_cache.rb +316 -0
  61. data/lib/sequel/extensions/pretty_table.rb +5 -71
  62. data/lib/sequel/extensions/query_literals.rb +79 -0
  63. data/lib/sequel/extensions/schema_caching.rb +76 -0
  64. data/lib/sequel/extensions/schema_dumper.rb +227 -31
  65. data/lib/sequel/extensions/select_remove.rb +35 -0
  66. data/lib/sequel/extensions/sql_expr.rb +4 -110
  67. data/lib/sequel/extensions/to_dot.rb +1 -1
  68. data/lib/sequel/model.rb +11 -2
  69. data/lib/sequel/model/associations.rb +35 -7
  70. data/lib/sequel/model/base.rb +159 -36
  71. data/lib/sequel/no_core_ext.rb +2 -0
  72. data/lib/sequel/plugins/caching.rb +25 -18
  73. data/lib/sequel/plugins/composition.rb +1 -1
  74. data/lib/sequel/plugins/hook_class_methods.rb +1 -1
  75. data/lib/sequel/plugins/identity_map.rb +11 -3
  76. data/lib/sequel/plugins/instance_filters.rb +10 -0
  77. data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
  78. data/lib/sequel/plugins/nested_attributes.rb +4 -3
  79. data/lib/sequel/plugins/prepared_statements.rb +3 -1
  80. data/lib/sequel/plugins/prepared_statements_associations.rb +5 -1
  81. data/lib/sequel/plugins/schema.rb +7 -2
  82. data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
  83. data/lib/sequel/plugins/static_cache.rb +99 -0
  84. data/lib/sequel/plugins/validation_class_methods.rb +1 -1
  85. data/lib/sequel/sql.rb +417 -7
  86. data/lib/sequel/version.rb +1 -1
  87. data/spec/adapters/firebird_spec.rb +1 -1
  88. data/spec/adapters/mssql_spec.rb +12 -15
  89. data/spec/adapters/mysql_spec.rb +81 -23
  90. data/spec/adapters/postgres_spec.rb +444 -77
  91. data/spec/adapters/spec_helper.rb +2 -0
  92. data/spec/adapters/sqlite_spec.rb +8 -8
  93. data/spec/core/connection_pool_spec.rb +85 -0
  94. data/spec/core/database_spec.rb +29 -5
  95. data/spec/core/dataset_spec.rb +171 -3
  96. data/spec/core/expression_filters_spec.rb +364 -0
  97. data/spec/core/mock_adapter_spec.rb +17 -3
  98. data/spec/core/schema_spec.rb +133 -0
  99. data/spec/extensions/association_dependencies_spec.rb +13 -13
  100. data/spec/extensions/caching_spec.rb +26 -3
  101. data/spec/extensions/class_table_inheritance_spec.rb +2 -2
  102. data/spec/{core/core_sql_spec.rb → extensions/core_extensions_spec.rb} +23 -94
  103. data/spec/extensions/force_encoding_spec.rb +4 -2
  104. data/spec/extensions/hook_class_methods_spec.rb +5 -2
  105. data/spec/extensions/identity_map_spec.rb +17 -0
  106. data/spec/extensions/instance_filters_spec.rb +1 -1
  107. data/spec/extensions/lazy_attributes_spec.rb +2 -2
  108. data/spec/extensions/list_spec.rb +4 -4
  109. data/spec/extensions/many_to_one_pk_lookup_spec.rb +140 -0
  110. data/spec/extensions/migration_spec.rb +6 -2
  111. data/spec/extensions/nested_attributes_spec.rb +20 -0
  112. data/spec/extensions/null_dataset_spec.rb +85 -0
  113. data/spec/extensions/optimistic_locking_spec.rb +2 -2
  114. data/spec/extensions/pg_array_ops_spec.rb +105 -0
  115. data/spec/extensions/pg_array_spec.rb +196 -0
  116. data/spec/extensions/pg_auto_parameterize_spec.rb +64 -0
  117. data/spec/extensions/pg_hstore_ops_spec.rb +136 -0
  118. data/spec/extensions/pg_hstore_spec.rb +195 -0
  119. data/spec/extensions/pg_statement_cache_spec.rb +209 -0
  120. data/spec/extensions/prepared_statements_spec.rb +4 -0
  121. data/spec/extensions/pretty_table_spec.rb +6 -0
  122. data/spec/extensions/query_literals_spec.rb +168 -0
  123. data/spec/extensions/schema_caching_spec.rb +41 -0
  124. data/spec/extensions/schema_dumper_spec.rb +231 -11
  125. data/spec/extensions/schema_spec.rb +14 -2
  126. data/spec/extensions/select_remove_spec.rb +38 -0
  127. data/spec/extensions/sharding_spec.rb +6 -6
  128. data/spec/extensions/skip_create_refresh_spec.rb +1 -1
  129. data/spec/extensions/spec_helper.rb +2 -1
  130. data/spec/extensions/sql_expr_spec.rb +28 -19
  131. data/spec/extensions/static_cache_spec.rb +145 -0
  132. data/spec/extensions/touch_spec.rb +1 -1
  133. data/spec/extensions/typecast_on_load_spec.rb +9 -1
  134. data/spec/integration/associations_test.rb +6 -6
  135. data/spec/integration/database_test.rb +1 -1
  136. data/spec/integration/dataset_test.rb +89 -26
  137. data/spec/integration/migrator_test.rb +2 -3
  138. data/spec/integration/model_test.rb +3 -3
  139. data/spec/integration/plugin_test.rb +85 -22
  140. data/spec/integration/prepared_statement_test.rb +28 -8
  141. data/spec/integration/schema_test.rb +78 -7
  142. data/spec/integration/spec_helper.rb +1 -0
  143. data/spec/integration/timezone_test.rb +1 -1
  144. data/spec/integration/transaction_test.rb +4 -6
  145. data/spec/integration/type_test.rb +2 -2
  146. data/spec/model/associations_spec.rb +94 -8
  147. data/spec/model/base_spec.rb +4 -4
  148. data/spec/model/hooks_spec.rb +2 -2
  149. data/spec/model/model_spec.rb +19 -7
  150. data/spec/model/record_spec.rb +135 -58
  151. data/spec/model/spec_helper.rb +1 -0
  152. 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, can be
148
- :restrict, :cascade, :set_null, or :set_default.
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,
@@ -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
@@ -36,11 +36,6 @@ module Sequel
36
36
  false
37
37
  end
38
38
 
39
- # Use execute_insert to execute the replace_sql.
40
- def replace(*args)
41
- execute_insert(replace_sql(*args))
42
- end
43
-
44
39
  private
45
40
 
46
41
  # do_mysql sets NO_BACKSLASH_ESCAPES, so use standard SQL string escaping
@@ -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, &block)
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("Preparing #{ps_name}: #{sql}"){conn.prepare(sql, ps_name)}
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
- stmt = log_yield("Executing #{ps_name}: #{args.inspect}"){conn.execute_prepared(ps_name, *args)}
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)
@@ -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("Closing #{name}"){cps[1].close} if cps
347
- cps = log_yield("Preparing#{" #{name}:" if name} #{sql}"){conn.prepareStatement(sql)}
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 = "Executing#{" #{name}" if name}"
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(? AS VARCHAR_IGNORECASE)".freeze
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.
@@ -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, &block)
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, &block)
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 << "'"