sequel 4.42.1 → 4.43.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +35 -1
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -4
- data/doc/release_notes/4.43.0.txt +87 -0
- data/doc/sql.rdoc +26 -27
- data/doc/testing.rdoc +2 -0
- data/doc/validations.rdoc +1 -1
- data/lib/sequel/adapters/ado.rb +5 -0
- data/lib/sequel/adapters/cubrid.rb +5 -0
- data/lib/sequel/adapters/ibmdb.rb +5 -0
- data/lib/sequel/adapters/jdbc.rb +6 -0
- data/lib/sequel/adapters/jdbc/derby.rb +5 -0
- data/lib/sequel/adapters/jdbc/hsqldb.rb +9 -5
- data/lib/sequel/adapters/jdbc/postgresql.rb +1 -1
- data/lib/sequel/adapters/jdbc/sqlite.rb +5 -0
- data/lib/sequel/adapters/jdbc/transactions.rb +5 -0
- data/lib/sequel/adapters/mock.rb +12 -9
- data/lib/sequel/adapters/mysql.rb +6 -0
- data/lib/sequel/adapters/mysql2.rb +7 -2
- data/lib/sequel/adapters/oracle.rb +5 -0
- data/lib/sequel/adapters/shared/db2.rb +7 -1
- data/lib/sequel/adapters/shared/mssql.rb +5 -0
- data/lib/sequel/adapters/shared/mysql.rb +8 -1
- data/lib/sequel/adapters/shared/oracle.rb +20 -12
- data/lib/sequel/adapters/shared/postgres.rb +11 -2
- data/lib/sequel/adapters/shared/sqlanywhere.rb +6 -0
- data/lib/sequel/adapters/shared/sqlite.rb +29 -0
- data/lib/sequel/adapters/sqlanywhere.rb +5 -0
- data/lib/sequel/adapters/sqlite.rb +13 -0
- data/lib/sequel/connection_pool/sharded_single.rb +5 -0
- data/lib/sequel/connection_pool/sharded_threaded.rb +5 -0
- data/lib/sequel/connection_pool/single.rb +15 -6
- data/lib/sequel/database/dataset.rb +3 -0
- data/lib/sequel/database/misc.rb +22 -1
- data/lib/sequel/database/query.rb +2 -4
- data/lib/sequel/dataset/actions.rb +0 -1
- data/lib/sequel/dataset/misc.rb +2 -4
- data/lib/sequel/dataset/query.rb +23 -6
- data/lib/sequel/extensions/_model_constraint_validations.rb +16 -0
- data/lib/sequel/extensions/_model_pg_row.rb +47 -0
- data/lib/sequel/extensions/looser_typecasting.rb +2 -0
- data/lib/sequel/extensions/migration.rb +12 -1
- data/lib/sequel/extensions/pg_array.rb +6 -0
- data/lib/sequel/extensions/pg_enum.rb +2 -1
- data/lib/sequel/extensions/pg_range.rb +6 -0
- data/lib/sequel/extensions/pg_row.rb +8 -0
- data/lib/sequel/model/associations.rb +3 -1
- data/lib/sequel/model/base.rb +14 -3
- data/lib/sequel/plugins/constraint_validations.rb +1 -8
- data/lib/sequel/plugins/instance_filters.rb +1 -1
- data/lib/sequel/plugins/pg_row.rb +1 -40
- data/lib/sequel/plugins/prepared_statements.rb +51 -20
- data/lib/sequel/plugins/prepared_statements_associations.rb +22 -4
- data/lib/sequel/plugins/prepared_statements_with_pk.rb +9 -1
- data/lib/sequel/plugins/sharding.rb +5 -0
- data/lib/sequel/plugins/update_primary_key.rb +1 -1
- data/lib/sequel/version.rb +2 -2
- data/spec/adapters/spec_helper.rb +4 -0
- data/spec/core/connection_pool_spec.rb +10 -0
- data/spec/core/database_spec.rb +29 -0
- data/spec/extensions/blacklist_security_spec.rb +4 -4
- data/spec/extensions/defaults_setter_spec.rb +1 -1
- data/spec/extensions/force_encoding_spec.rb +3 -2
- data/spec/extensions/identifier_mangling_spec.rb +7 -0
- data/spec/extensions/instance_filters_spec.rb +1 -0
- data/spec/extensions/migration_spec.rb +19 -0
- data/spec/extensions/pg_array_spec.rb +5 -0
- data/spec/extensions/pg_range_spec.rb +5 -0
- data/spec/extensions/pg_row_spec.rb +9 -0
- data/spec/extensions/prepared_statements_associations_spec.rb +45 -1
- data/spec/extensions/prepared_statements_spec.rb +138 -41
- data/spec/extensions/prepared_statements_with_pk_spec.rb +7 -0
- data/spec/extensions/serialization_spec.rb +6 -6
- data/spec/extensions/single_table_inheritance_spec.rb +3 -3
- data/spec/extensions/skip_create_refresh_spec.rb +1 -1
- data/spec/integration/associations_test.rb +2 -2
- data/spec/integration/dataset_test.rb +0 -4
- data/spec/integration/eager_loader_test.rb +5 -5
- data/spec/integration/plugin_test.rb +8 -6
- data/spec/integration/schema_test.rb +2 -2
- data/spec/integration/spec_helper.rb +10 -0
- data/spec/integration/timezone_test.rb +1 -1
- data/spec/integration/transaction_test.rb +5 -5
- data/spec/model/associations_spec.rb +13 -6
- data/spec/model/base_spec.rb +1 -1
- data/spec/model/hooks_spec.rb +4 -4
- data/spec/model/model_spec.rb +2 -2
- data/spec/model/record_spec.rb +17 -18
- metadata +6 -2
data/lib/sequel/adapters/jdbc.rb
CHANGED
@@ -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
|
38
|
-
|
39
|
-
|
40
|
-
|
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)
|
data/lib/sequel/adapters/mock.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
137
|
-
|
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 @
|
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
|
-
|
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(
|
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
|
@@ -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])
|
@@ -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
|
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.
|
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
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
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
|
-
|
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
|
@@ -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
|
@@ -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.
|