sequel 4.42.1 → 4.43.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +35 -1
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -4
  5. data/doc/release_notes/4.43.0.txt +87 -0
  6. data/doc/sql.rdoc +26 -27
  7. data/doc/testing.rdoc +2 -0
  8. data/doc/validations.rdoc +1 -1
  9. data/lib/sequel/adapters/ado.rb +5 -0
  10. data/lib/sequel/adapters/cubrid.rb +5 -0
  11. data/lib/sequel/adapters/ibmdb.rb +5 -0
  12. data/lib/sequel/adapters/jdbc.rb +6 -0
  13. data/lib/sequel/adapters/jdbc/derby.rb +5 -0
  14. data/lib/sequel/adapters/jdbc/hsqldb.rb +9 -5
  15. data/lib/sequel/adapters/jdbc/postgresql.rb +1 -1
  16. data/lib/sequel/adapters/jdbc/sqlite.rb +5 -0
  17. data/lib/sequel/adapters/jdbc/transactions.rb +5 -0
  18. data/lib/sequel/adapters/mock.rb +12 -9
  19. data/lib/sequel/adapters/mysql.rb +6 -0
  20. data/lib/sequel/adapters/mysql2.rb +7 -2
  21. data/lib/sequel/adapters/oracle.rb +5 -0
  22. data/lib/sequel/adapters/shared/db2.rb +7 -1
  23. data/lib/sequel/adapters/shared/mssql.rb +5 -0
  24. data/lib/sequel/adapters/shared/mysql.rb +8 -1
  25. data/lib/sequel/adapters/shared/oracle.rb +20 -12
  26. data/lib/sequel/adapters/shared/postgres.rb +11 -2
  27. data/lib/sequel/adapters/shared/sqlanywhere.rb +6 -0
  28. data/lib/sequel/adapters/shared/sqlite.rb +29 -0
  29. data/lib/sequel/adapters/sqlanywhere.rb +5 -0
  30. data/lib/sequel/adapters/sqlite.rb +13 -0
  31. data/lib/sequel/connection_pool/sharded_single.rb +5 -0
  32. data/lib/sequel/connection_pool/sharded_threaded.rb +5 -0
  33. data/lib/sequel/connection_pool/single.rb +15 -6
  34. data/lib/sequel/database/dataset.rb +3 -0
  35. data/lib/sequel/database/misc.rb +22 -1
  36. data/lib/sequel/database/query.rb +2 -4
  37. data/lib/sequel/dataset/actions.rb +0 -1
  38. data/lib/sequel/dataset/misc.rb +2 -4
  39. data/lib/sequel/dataset/query.rb +23 -6
  40. data/lib/sequel/extensions/_model_constraint_validations.rb +16 -0
  41. data/lib/sequel/extensions/_model_pg_row.rb +47 -0
  42. data/lib/sequel/extensions/looser_typecasting.rb +2 -0
  43. data/lib/sequel/extensions/migration.rb +12 -1
  44. data/lib/sequel/extensions/pg_array.rb +6 -0
  45. data/lib/sequel/extensions/pg_enum.rb +2 -1
  46. data/lib/sequel/extensions/pg_range.rb +6 -0
  47. data/lib/sequel/extensions/pg_row.rb +8 -0
  48. data/lib/sequel/model/associations.rb +3 -1
  49. data/lib/sequel/model/base.rb +14 -3
  50. data/lib/sequel/plugins/constraint_validations.rb +1 -8
  51. data/lib/sequel/plugins/instance_filters.rb +1 -1
  52. data/lib/sequel/plugins/pg_row.rb +1 -40
  53. data/lib/sequel/plugins/prepared_statements.rb +51 -20
  54. data/lib/sequel/plugins/prepared_statements_associations.rb +22 -4
  55. data/lib/sequel/plugins/prepared_statements_with_pk.rb +9 -1
  56. data/lib/sequel/plugins/sharding.rb +5 -0
  57. data/lib/sequel/plugins/update_primary_key.rb +1 -1
  58. data/lib/sequel/version.rb +2 -2
  59. data/spec/adapters/spec_helper.rb +4 -0
  60. data/spec/core/connection_pool_spec.rb +10 -0
  61. data/spec/core/database_spec.rb +29 -0
  62. data/spec/extensions/blacklist_security_spec.rb +4 -4
  63. data/spec/extensions/defaults_setter_spec.rb +1 -1
  64. data/spec/extensions/force_encoding_spec.rb +3 -2
  65. data/spec/extensions/identifier_mangling_spec.rb +7 -0
  66. data/spec/extensions/instance_filters_spec.rb +1 -0
  67. data/spec/extensions/migration_spec.rb +19 -0
  68. data/spec/extensions/pg_array_spec.rb +5 -0
  69. data/spec/extensions/pg_range_spec.rb +5 -0
  70. data/spec/extensions/pg_row_spec.rb +9 -0
  71. data/spec/extensions/prepared_statements_associations_spec.rb +45 -1
  72. data/spec/extensions/prepared_statements_spec.rb +138 -41
  73. data/spec/extensions/prepared_statements_with_pk_spec.rb +7 -0
  74. data/spec/extensions/serialization_spec.rb +6 -6
  75. data/spec/extensions/single_table_inheritance_spec.rb +3 -3
  76. data/spec/extensions/skip_create_refresh_spec.rb +1 -1
  77. data/spec/integration/associations_test.rb +2 -2
  78. data/spec/integration/dataset_test.rb +0 -4
  79. data/spec/integration/eager_loader_test.rb +5 -5
  80. data/spec/integration/plugin_test.rb +8 -6
  81. data/spec/integration/schema_test.rb +2 -2
  82. data/spec/integration/spec_helper.rb +10 -0
  83. data/spec/integration/timezone_test.rb +1 -1
  84. data/spec/integration/transaction_test.rb +5 -5
  85. data/spec/model/associations_spec.rb +13 -6
  86. data/spec/model/base_spec.rb +1 -1
  87. data/spec/model/hooks_spec.rb +4 -4
  88. data/spec/model/model_spec.rb +2 -2
  89. data/spec/model/record_spec.rb +17 -18
  90. metadata +6 -2
@@ -283,6 +283,12 @@ module Sequel
283
283
  execute(sql, opts)
284
284
  end
285
285
 
286
+ def freeze
287
+ @type_convertor_map.freeze
288
+ @basic_type_convertor_map.freeze
289
+ super
290
+ end
291
+
286
292
  # Use the JDBC metadata to get a list of foreign keys for the table.
287
293
  def foreign_key_list(table, opts=OPTS)
288
294
  m = output_identifier_meth
@@ -34,6 +34,11 @@ module Sequel
34
34
  :derby
35
35
  end
36
36
 
37
+ def freeze
38
+ svn_version
39
+ super
40
+ end
41
+
37
42
  # Derby uses an IDENTITY sequence for autoincrementing columns.
38
43
  def serial_primary_key_options
39
44
  {:primary_key => true, :type => :integer, :identity=>true, :start_with=>1}
@@ -26,6 +26,11 @@ module Sequel
26
26
  :hsqldb
27
27
  end
28
28
 
29
+ def freeze
30
+ db_version
31
+ super
32
+ end
33
+
29
34
  # HSQLDB uses an IDENTITY sequence as the default value for primary
30
35
  # key columns.
31
36
  def serial_primary_key_options
@@ -34,11 +39,10 @@ module Sequel
34
39
 
35
40
  # The version of the database, as an integer (e.g 2.2.5 -> 20205)
36
41
  def db_version
37
- @db_version ||= begin
38
- v = get{DATABASE_VERSION(){}}
39
- if v =~ /(\d+)\.(\d+)\.(\d+)/
40
- $1.to_i * 10000 + $2.to_i * 100 + $3.to_i
41
- end
42
+ return @db_version if defined?(@db_version)
43
+ v = get{DATABASE_VERSION(){}}
44
+ @db_version = if v =~ /(\d+)\.(\d+)\.(\d+)/
45
+ $1.to_i * 10000 + $2.to_i * 100 + $3.to_i
42
46
  end
43
47
  end
44
48
 
@@ -9,8 +9,8 @@ module Sequel
9
9
  module JDBC
10
10
  Sequel.synchronize do
11
11
  DATABASE_SETUP[:postgresql] = proc do |db|
12
- db.extend(Sequel::JDBC::Postgres::DatabaseMethods)
13
12
  db.dataset_class = Sequel::JDBC::Postgres::Dataset
13
+ db.extend(Sequel::JDBC::Postgres::DatabaseMethods)
14
14
  org.postgresql.Driver
15
15
  end
16
16
  end
@@ -90,6 +90,11 @@ module Sequel
90
90
  end
91
91
  end
92
92
  end
93
+
94
+ # The result code for the exception, if the jdbc driver supports result codes for exceptions.
95
+ def sqlite_error_code(exception)
96
+ exception.resultCode.code if exception.respond_to?(:resultCode)
97
+ end
93
98
  end
94
99
  end
95
100
  end
@@ -10,6 +10,11 @@ module Sequel
10
10
  TRANSACTION_ROLLBACK_SP = 'Transaction.rollback_savepoint'.freeze
11
11
  TRANSACTION_SAVEPOINT= 'Transaction.savepoint'.freeze
12
12
 
13
+ def freeze
14
+ supports_savepoints?
15
+ super
16
+ end
17
+
13
18
  # Check the JDBC DatabaseMetaData for savepoint support
14
19
  def supports_savepoints?
15
20
  return @supports_savepoints if defined?(@supports_savepoints)
@@ -48,7 +48,15 @@ module Sequel
48
48
  # the value returned
49
49
  # Class :: Should be an Exception subclass, will create a new
50
50
  # instance an raise it wrapped in a DatabaseError.
51
- attr_writer :autoid
51
+ def autoid=(v)
52
+ @autoid = case v
53
+ when Integer
54
+ i = v - 1
55
+ proc{Sequel.synchronize{i+=1}}
56
+ else
57
+ v
58
+ end
59
+ end
52
60
 
53
61
  # Set the columns to set in the dataset when the dataset fetches
54
62
  # rows. Argument types supported:
@@ -133,13 +141,8 @@ module Sequel
133
141
  private
134
142
 
135
143
  def _autoid(sql, v, ds=nil)
136
- case v
137
- when Integer
138
- if ds
139
- ds.send(:cache_set, :_autoid, ds.autoid + 1) if ds.autoid.is_a?(Integer)
140
- else
141
- @autoid += 1
142
- end
144
+ if ds
145
+ ds.send(:cache_set, :_autoid, ds.autoid + 1) if ds.autoid.is_a?(Integer)
143
146
  v
144
147
  else
145
148
  _nextres(v, sql, nil)
@@ -192,7 +195,7 @@ module Sequel
192
195
  if f < Exception
193
196
  raise f
194
197
  else
195
- raise Error, "Invalid @autoid/@numrows attribute: #{v.inspect}"
198
+ raise Error, "Invalid @fetch attribute: #{v.inspect}"
196
199
  end
197
200
  when nil
198
201
  # nothing
@@ -163,6 +163,12 @@ module Sequel
163
163
  execute(sql, opts){|c| return c.insert_id}
164
164
  end
165
165
 
166
+ def freeze
167
+ server_version
168
+ @conversion_procs.freeze
169
+ super
170
+ end
171
+
166
172
  # Return the version of the MySQL server two which we are connecting.
167
173
  def server_version(server=nil)
168
174
  @server_version ||= (synchronize(server){|conn| conn.server_version if conn.respond_to?(:server_version)} || super)
@@ -47,7 +47,7 @@ module Sequel
47
47
  conn.query_options.merge!(:symbolize_keys=>true, :cache_rows=>false)
48
48
 
49
49
  if NativePreparedStatements
50
- @default_query_options ||= conn.query_options.dup
50
+ conn.instance_variable_set(:@sequel_default_query_options, conn.query_options.dup)
51
51
  end
52
52
 
53
53
  sqls = mysql_connection_setting_sqls
@@ -76,6 +76,11 @@ module Sequel
76
76
  execute(sql, opts){|c| return c.last_id}
77
77
  end
78
78
 
79
+ def freeze
80
+ server_version
81
+ super
82
+ end
83
+
79
84
  # Return the version of the MySQL server to which we are connecting.
80
85
  def server_version(server=nil)
81
86
  @server_version ||= (synchronize(server){|conn| conn.server_info[:id]} || super)
@@ -158,7 +163,7 @@ module Sequel
158
163
  raise_error(e)
159
164
  ensure
160
165
  if stmt
161
- conn.query_options.replace(@default_query_options)
166
+ conn.query_options.replace(conn.instance_variable_get(:@sequel_default_query_options))
162
167
  stmt.close if close_stmt
163
168
  end
164
169
  end
@@ -71,6 +71,11 @@ module Sequel
71
71
  _execute(:insert, sql, opts)
72
72
  end
73
73
 
74
+ def freeze
75
+ @conversion_procs.freeze
76
+ super
77
+ end
78
+
74
79
  private
75
80
 
76
81
  def _execute(type, sql, opts=OPTS, &block)
@@ -26,11 +26,17 @@ module Sequel
26
26
  # Return the database version as a string. Don't rely on this,
27
27
  # it may return an integer in the future.
28
28
  def db2_version
29
- return @db2_version if @db2_version
29
+ return @db2_version if defined?(@db2_version)
30
30
  @db2_version = metadata_dataset.with_sql("select service_level from sysibmadm.env_inst_info").first[:service_level]
31
31
  end
32
32
  alias_method :server_version, :db2_version
33
33
 
34
+ def freeze
35
+ db2_version
36
+ offset_strategy
37
+ super
38
+ end
39
+
34
40
  # Use SYSIBM.SYSCOLUMNS to get the information on the tables.
35
41
  def schema_parse_table(table, opts = OPTS)
36
42
  m = output_identifier_meth(opts[:dataset])
@@ -173,6 +173,11 @@ module Sequel
173
173
  h.values
174
174
  end
175
175
 
176
+ def freeze
177
+ server_version
178
+ super
179
+ end
180
+
176
181
  # Use the system tables to get index information
177
182
  def indexes(table, opts=OPTS)
178
183
  m = output_identifier_meth
@@ -89,6 +89,12 @@ module Sequel
89
89
  h.values
90
90
  end
91
91
 
92
+ def freeze
93
+ server_version
94
+ supports_timestamp_usecs?
95
+ super
96
+ end
97
+
92
98
  # MySQL namespaces indexes per table.
93
99
  def global_index_namespace?
94
100
  false
@@ -155,7 +161,8 @@ module Sequel
155
161
  # automatic initialization of datetime values wasn't supported to 5.6.5+,
156
162
  # and this is related to that.
157
163
  def supports_timestamp_usecs?
158
- @supports_timestamp_usecs ||= server_version >= 50605 && typecast_value_boolean(opts[:fractional_seconds])
164
+ return @supports_timestamp_usecs if defined?(@supports_timestamp_usecs)
165
+ @supports_timestamp_usecs = server_version >= 50605 && typecast_value_boolean(opts[:fractional_seconds])
159
166
  end
160
167
 
161
168
  # MySQL supports transaction isolation levels
@@ -74,6 +74,13 @@ module Sequel
74
74
  fks.values
75
75
  end
76
76
 
77
+ def freeze
78
+ current_user
79
+ server_version
80
+ @conversion_procs.freeze
81
+ super
82
+ end
83
+
77
84
  # Oracle namespaces indexes per table.
78
85
  def global_index_namespace?
79
86
  false
@@ -237,7 +244,7 @@ module Sequel
237
244
  end
238
245
 
239
246
  def remove_cached_schema(table)
240
- @primary_key_sequences.delete(table)
247
+ Sequel.synchronize{@primary_key_sequences.delete(table)}
241
248
  super
242
249
  end
243
250
 
@@ -253,19 +260,20 @@ module Sequel
253
260
 
254
261
  def sequence_for_table(table)
255
262
  return nil unless autosequence
256
- @primary_key_sequences.fetch(table) do |key|
257
- begin
258
- sch = schema(table)
259
- rescue Sequel::Error
260
- return nil
261
- end
263
+ Sequel.synchronize{return @primary_key_sequences[table] if @primary_key_sequences.has_key?(table)}
262
264
 
263
- pk = sch.select{|k, v| v[:primary_key]}
264
- @primary_key_sequences[table] = if pk.length == 1
265
- seq = "seq_#{table}_#{pk.first.first}"
266
- seq.to_sym unless from(:user_sequences).where(:sequence_name=>input_identifier_meth.call(seq)).empty?
267
- end
265
+ begin
266
+ sch = schema(table)
267
+ rescue Sequel::Error
268
+ return nil
269
+ end
270
+
271
+ pk = sch.select{|k, v| v[:primary_key]}
272
+ pks = if pk.length == 1
273
+ seq = "seq_#{table}_#{pk.first.first}"
274
+ seq.to_sym unless from(:user_sequences).where(:sequence_name=>input_identifier_meth.call(seq)).empty?
268
275
  end
276
+ Sequel.synchronize{@primary_key_sequences[table] = pks}
269
277
  end
270
278
 
271
279
  # Oracle supports CREATE OR REPLACE VIEW.
@@ -373,6 +373,13 @@ module Sequel
373
373
  h.values
374
374
  end
375
375
 
376
+ def freeze
377
+ server_version
378
+ supports_prepared_transactions?
379
+ @conversion_procs.freeze
380
+ super
381
+ end
382
+
376
383
  # Use the pg_* system tables to determine indexes on a table
377
384
  def indexes(table, opts=OPTS)
378
385
  m = output_identifier_meth
@@ -580,8 +587,9 @@ module Sequel
580
587
  # Check whether the given type name string/symbol (e.g. :hstore) is supported by
581
588
  # the database.
582
589
  def type_supported?(type)
583
- @supported_types ||= {}
584
- @supported_types.fetch(type){@supported_types[type] = (from(:pg_type).where(:typtype=>'b', :typname=>type.to_s).count > 0)}
590
+ Sequel.synchronize{return @supported_types[type] if @supported_types.has_key?(type)}
591
+ supported = from(:pg_type).where(:typtype=>'b', :typname=>type.to_s).count > 0
592
+ Sequel.synchronize{return @supported_types[type] = supported}
585
593
  end
586
594
 
587
595
  # Creates a dataset that uses the VALUES clause:
@@ -1032,6 +1040,7 @@ module Sequel
1032
1040
  def initialize_postgres_adapter
1033
1041
  @primary_keys = {}
1034
1042
  @primary_key_sequences = {}
1043
+ @supported_types = {}
1035
1044
  @conversion_procs = PG_TYPES.dup
1036
1045
  reset_conversion_procs
1037
1046
  end
@@ -37,6 +37,12 @@ module Sequel
37
37
  :sqlanywhere
38
38
  end
39
39
 
40
+ def freeze
41
+ convert_smallint_to_bool
42
+ @conversion_procs.freeze
43
+ super
44
+ end
45
+
40
46
  def to_application_timestamp_sa(v)
41
47
  to_application_timestamp(v.to_s) if v
42
48
  end
@@ -101,6 +101,12 @@ module Sequel
101
101
  h.values
102
102
  end
103
103
 
104
+ def freeze
105
+ sqlite_version
106
+ use_timestamp_timezones?
107
+ super
108
+ end
109
+
104
110
  # Use the index_list and index_info PRAGMAs to determine the indexes on the table.
105
111
  def indexes(table, opts=OPTS)
106
112
  m = output_identifier_meth
@@ -359,6 +365,24 @@ module Sequel
359
365
  DATABASE_ERROR_REGEXPS
360
366
  end
361
367
 
368
+ # Recognize SQLite error codes if the exception provides access to them.
369
+ def database_specific_error_class(exception, opts)
370
+ case sqlite_error_code(exception)
371
+ when 1299
372
+ NotNullConstraintViolation
373
+ when 2067
374
+ UniqueConstraintViolation
375
+ when 787
376
+ ForeignKeyConstraintViolation
377
+ when 275
378
+ CheckConstraintViolation
379
+ when 19
380
+ ConstraintViolation
381
+ else
382
+ super
383
+ end
384
+ end
385
+
362
386
  # The array of column schema hashes for the current columns in the table
363
387
  def defined_columns_for(table)
364
388
  cols = parse_pragma(table, {})
@@ -497,6 +521,11 @@ module Sequel
497
521
  end
498
522
  end
499
523
 
524
+ # Don't support SQLite error codes for exceptions by default.
525
+ def sqlite_error_code(exception)
526
+ nil
527
+ end
528
+
500
529
  # Backbone of the tables and views support.
501
530
  def tables_and_views(filter, opts)
502
531
  m = output_identifier_meth
@@ -98,6 +98,11 @@ module Sequel
98
98
  end
99
99
  end
100
100
 
101
+ def freeze
102
+ @conversion_procs.freeze
103
+ super
104
+ end
105
+
101
106
  private
102
107
 
103
108
  LAST_INSERT_ID = 'SELECT @@IDENTITY'.freeze
@@ -151,6 +151,11 @@ module Sequel
151
151
  _execute(:insert, sql, opts)
152
152
  end
153
153
 
154
+ def freeze
155
+ @conversion_procs.freeze
156
+ super
157
+ end
158
+
154
159
  # Handle Integer and Float arguments, since SQLite can store timestamps as integers and floats.
155
160
  def to_application_timestamp(s)
156
161
  case s
@@ -269,6 +274,14 @@ module Sequel
269
274
  def database_error_classes
270
275
  [SQLite3::Exception, ArgumentError]
271
276
  end
277
+
278
+ # Support SQLite exception codes if ruby-sqlite3 supports them.
279
+ # This is disabled by default because ruby-sqlite3 doesn't currently
280
+ # support them (returning nil), and even if it did, it doesn't support
281
+ # extended error codes, which would lead to worse behavior.
282
+ #def sqlite_error_code(exception)
283
+ # exception.code if exception.respond_to?(:code)
284
+ #end
272
285
  end
273
286
 
274
287
  # Dataset class for SQLite datasets that use the ruby-sqlite3 driver.
@@ -43,6 +43,11 @@ class Sequel::ShardedSingleConnectionPool < Sequel::ConnectionPool
43
43
  def disconnect(opts=OPTS)
44
44
  (opts[:server] ? Array(opts[:server]) : servers).each{|s| disconnect_server(s)}
45
45
  end
46
+
47
+ def freeze
48
+ @servers.freeze
49
+ super
50
+ end
46
51
 
47
52
  # Yields the connection to the supplied block for the given server.
48
53
  # This method simulates the ConnectionPool#hold API.