sequel 3.34.0 → 3.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +56 -0
- data/README.rdoc +3 -1
- data/Rakefile +2 -10
- data/doc/active_record.rdoc +1 -0
- data/doc/migration.rdoc +18 -7
- data/doc/model_hooks.rdoc +6 -0
- data/doc/opening_databases.rdoc +3 -0
- data/doc/prepared_statements.rdoc +0 -1
- data/doc/release_notes/3.35.0.txt +144 -0
- data/doc/schema_modification.rdoc +16 -1
- data/doc/thread_safety.rdoc +17 -0
- data/lib/sequel/adapters/do/postgres.rb +1 -52
- data/lib/sequel/adapters/do/sqlite.rb +0 -5
- data/lib/sequel/adapters/do.rb +2 -2
- data/lib/sequel/adapters/firebird.rb +1 -1
- data/lib/sequel/adapters/ibmdb.rb +2 -2
- data/lib/sequel/adapters/jdbc/db2.rb +0 -5
- data/lib/sequel/adapters/jdbc/derby.rb +29 -2
- data/lib/sequel/adapters/jdbc/firebird.rb +0 -5
- data/lib/sequel/adapters/jdbc/h2.rb +1 -1
- data/lib/sequel/adapters/jdbc/hsqldb.rb +7 -0
- data/lib/sequel/adapters/jdbc/informix.rb +0 -5
- data/lib/sequel/adapters/jdbc/jtds.rb +0 -5
- data/lib/sequel/adapters/jdbc/mysql.rb +0 -5
- data/lib/sequel/adapters/jdbc/postgresql.rb +4 -35
- data/lib/sequel/adapters/jdbc/sqlite.rb +0 -5
- data/lib/sequel/adapters/jdbc/sqlserver.rb +0 -5
- data/lib/sequel/adapters/jdbc/transactions.rb +4 -4
- data/lib/sequel/adapters/jdbc.rb +23 -19
- data/lib/sequel/adapters/mysql2.rb +1 -1
- data/lib/sequel/adapters/odbc/mssql.rb +14 -1
- data/lib/sequel/adapters/odbc.rb +3 -3
- data/lib/sequel/adapters/oracle.rb +6 -18
- data/lib/sequel/adapters/postgres.rb +36 -53
- data/lib/sequel/adapters/shared/db2.rb +16 -2
- data/lib/sequel/adapters/shared/mssql.rb +40 -9
- data/lib/sequel/adapters/shared/mysql.rb +16 -4
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +2 -2
- data/lib/sequel/adapters/shared/oracle.rb +2 -0
- data/lib/sequel/adapters/shared/postgres.rb +135 -211
- data/lib/sequel/adapters/sqlite.rb +2 -2
- data/lib/sequel/adapters/swift/postgres.rb +1 -71
- data/lib/sequel/adapters/swift.rb +1 -1
- data/lib/sequel/adapters/tinytds.rb +3 -3
- data/lib/sequel/core.rb +27 -4
- data/lib/sequel/database/connecting.rb +7 -8
- data/lib/sequel/database/logging.rb +6 -1
- data/lib/sequel/database/misc.rb +20 -4
- data/lib/sequel/database/query.rb +38 -18
- data/lib/sequel/database/schema_generator.rb +5 -2
- data/lib/sequel/database/schema_methods.rb +34 -8
- data/lib/sequel/dataset/prepared_statements.rb +1 -1
- data/lib/sequel/dataset/sql.rb +18 -24
- data/lib/sequel/extensions/core_extensions.rb +0 -23
- data/lib/sequel/extensions/migration.rb +22 -8
- data/lib/sequel/extensions/pg_auto_parameterize.rb +4 -0
- data/lib/sequel/extensions/schema_dumper.rb +1 -1
- data/lib/sequel/model/associations.rb +95 -70
- data/lib/sequel/model/base.rb +19 -20
- data/lib/sequel/model.rb +2 -2
- data/lib/sequel/plugins/dirty.rb +214 -0
- data/lib/sequel/plugins/identity_map.rb +1 -1
- data/lib/sequel/plugins/json_serializer.rb +16 -1
- data/lib/sequel/plugins/many_through_many.rb +22 -32
- data/lib/sequel/plugins/many_to_one_pk_lookup.rb +2 -2
- data/lib/sequel/plugins/prepared_statements.rb +22 -8
- data/lib/sequel/plugins/prepared_statements_associations.rb +2 -3
- data/lib/sequel/plugins/prepared_statements_with_pk.rb +1 -1
- data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
- data/lib/sequel/plugins/subclasses.rb +10 -2
- data/lib/sequel/plugins/timestamps.rb +1 -1
- data/lib/sequel/plugins/xml_serializer.rb +12 -1
- data/lib/sequel/sql.rb +1 -1
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/postgres_spec.rb +30 -79
- data/spec/core/database_spec.rb +46 -2
- data/spec/core/dataset_spec.rb +28 -22
- data/spec/core/schema_generator_spec.rb +1 -1
- data/spec/core/schema_spec.rb +51 -0
- data/spec/extensions/arbitrary_servers_spec.rb +0 -4
- data/spec/extensions/association_autoreloading_spec.rb +17 -0
- data/spec/extensions/association_proxies_spec.rb +4 -4
- data/spec/extensions/core_extensions_spec.rb +1 -24
- data/spec/extensions/dirty_spec.rb +155 -0
- data/spec/extensions/json_serializer_spec.rb +13 -0
- data/spec/extensions/migration_spec.rb +28 -15
- data/spec/extensions/named_timezones_spec.rb +6 -8
- data/spec/extensions/pg_auto_parameterize_spec.rb +6 -5
- data/spec/extensions/schema_dumper_spec.rb +3 -1
- data/spec/extensions/single_table_inheritance_spec.rb +5 -0
- data/spec/extensions/xml_serializer_spec.rb +13 -0
- data/spec/files/{transactionless_migrations → transaction_specified_migrations}/001_create_alt_basic.rb +1 -1
- data/spec/integration/associations_test.rb +5 -7
- data/spec/integration/dataset_test.rb +25 -7
- data/spec/integration/plugin_test.rb +1 -1
- data/spec/integration/schema_test.rb +16 -1
- data/spec/model/associations_spec.rb +2 -2
- metadata +14 -9
- data/lib/sequel/adapters/odbc/db2.rb +0 -17
- /data/spec/files/{transactionless_migrations → transaction_specified_migrations}/002_create_basic.rb +0 -0
- /data/spec/files/{transaction_migrations → transaction_unspecified_migrations}/001_create_alt_basic.rb +0 -0
- /data/spec/files/{transaction_migrations → transaction_unspecified_migrations}/002_create_basic.rb +0 -0
|
@@ -72,6 +72,11 @@ module Sequel
|
|
|
72
72
|
true
|
|
73
73
|
end
|
|
74
74
|
|
|
75
|
+
# MSSQL supports transaction DDL statements.
|
|
76
|
+
def supports_transactional_ddl?
|
|
77
|
+
true
|
|
78
|
+
end
|
|
79
|
+
|
|
75
80
|
# Microsoft SQL Server supports using the INFORMATION_SCHEMA to get
|
|
76
81
|
# information on tables.
|
|
77
82
|
def tables(opts={})
|
|
@@ -141,7 +146,7 @@ module Sequel
|
|
|
141
146
|
# Commit the active transaction on the connection, does not commit/release
|
|
142
147
|
# savepoints.
|
|
143
148
|
def commit_transaction(conn, opts={})
|
|
144
|
-
log_connection_execute(conn, commit_transaction_sql) unless
|
|
149
|
+
log_connection_execute(conn, commit_transaction_sql) unless _trans(conn)[:savepoint_level] > 1
|
|
145
150
|
end
|
|
146
151
|
|
|
147
152
|
# SQL to COMMIT a transaction.
|
|
@@ -152,10 +157,19 @@ module Sequel
|
|
|
152
157
|
# MSSQL uses the name of the table to decide the difference between
|
|
153
158
|
# a regular and temporary table, with temporary table names starting with
|
|
154
159
|
# a #.
|
|
155
|
-
def
|
|
156
|
-
"CREATE TABLE #{quote_schema_table(options[:temp] ? "##{name}" : name)}
|
|
160
|
+
def create_table_prefix_sql(name, options)
|
|
161
|
+
"CREATE TABLE #{quote_schema_table(options[:temp] ? "##{name}" : name)}"
|
|
157
162
|
end
|
|
158
163
|
|
|
164
|
+
# MSSQL doesn't support CREATE TABLE AS, it only supports SELECT INTO.
|
|
165
|
+
# Emulating CREATE TABLE AS using SELECT INTO is only possible if a dataset
|
|
166
|
+
# is given as the argument, it can't work with a string, so raise an
|
|
167
|
+
# Error if a string is given.
|
|
168
|
+
def create_table_as(name, ds, options)
|
|
169
|
+
raise(Error, "must provide dataset instance as value of create_table :as option on MSSQL") unless ds.is_a?(Sequel::Dataset)
|
|
170
|
+
run(ds.into(name).sql)
|
|
171
|
+
end
|
|
172
|
+
|
|
159
173
|
# The name of the constraint for setting the default value on the table and column.
|
|
160
174
|
def default_constraint_name(table, column)
|
|
161
175
|
from(:sysobjects___c_obj).
|
|
@@ -325,12 +339,16 @@ module Sequel
|
|
|
325
339
|
OUTPUT_INSERTED = " OUTPUT INSERTED.*".freeze
|
|
326
340
|
HEX_START = '0x'.freeze
|
|
327
341
|
UNICODE_STRING_START = "N'".freeze
|
|
342
|
+
BACKSLASH_CRLF_RE = /\\((?:\r\n)|\n)/.freeze
|
|
343
|
+
BACKSLASH_CRLF_REPLACE = '\\\\\\\\\\1\\1'.freeze
|
|
328
344
|
TOP_PAREN = " TOP (".freeze
|
|
329
345
|
TOP = " TOP ".freeze
|
|
330
346
|
OUTPUT = " OUTPUT ".freeze
|
|
331
347
|
HSTAR = "H*".freeze
|
|
332
348
|
CASE_SENSITIVE_COLLATION = 'Latin1_General_CS_AS'.freeze
|
|
333
349
|
CASE_INSENSITIVE_COLLATION = 'Latin1_General_CI_AS'.freeze
|
|
350
|
+
DEFAULT_TIMESTAMP_FORMAT = "'%Y-%m-%dT%H:%M:%S%N%z'".freeze
|
|
351
|
+
FORMAT_DATE = "'%Y%m%d'".freeze
|
|
334
352
|
|
|
335
353
|
# Allow overriding of the mssql_unicode_strings option at the dataset level.
|
|
336
354
|
attr_accessor :mssql_unicode_strings
|
|
@@ -557,6 +575,13 @@ module Sequel
|
|
|
557
575
|
server_version >= 10000000
|
|
558
576
|
end
|
|
559
577
|
|
|
578
|
+
# Use strict ISO-8601 format with T between date and time,
|
|
579
|
+
# since that is the format that is multilanguage and not
|
|
580
|
+
# DATEFORMAT dependent.
|
|
581
|
+
def default_timestamp_format
|
|
582
|
+
DEFAULT_TIMESTAMP_FORMAT
|
|
583
|
+
end
|
|
584
|
+
|
|
560
585
|
# MSSQL supports the OUTPUT clause for DELETE statements.
|
|
561
586
|
# It also allows prepending a WITH clause.
|
|
562
587
|
def delete_clause_methods
|
|
@@ -612,18 +637,24 @@ module Sequel
|
|
|
612
637
|
sql << HEX_START << v.unpack(HSTAR).first
|
|
613
638
|
end
|
|
614
639
|
|
|
615
|
-
#
|
|
616
|
-
#
|
|
617
|
-
def
|
|
618
|
-
|
|
619
|
-
sql << v.gsub(APOS_RE, DOUBLE_APOS) << APOS
|
|
640
|
+
# Use YYYYmmdd format, since that's the only want that is
|
|
641
|
+
# multilanguage and not DATEFORMAT dependent.
|
|
642
|
+
def literal_date(v)
|
|
643
|
+
v.strftime(FORMAT_DATE)
|
|
620
644
|
end
|
|
621
|
-
|
|
645
|
+
|
|
622
646
|
# Use 0 for false on MSSQL
|
|
623
647
|
def literal_false
|
|
624
648
|
BOOL_FALSE
|
|
625
649
|
end
|
|
626
650
|
|
|
651
|
+
# Optionally use unicode string syntax for all strings. Don't double
|
|
652
|
+
# backslashes.
|
|
653
|
+
def literal_string_append(sql, v)
|
|
654
|
+
sql << (mssql_unicode_strings ? UNICODE_STRING_START : APOS)
|
|
655
|
+
sql << v.gsub(APOS_RE, DOUBLE_APOS).gsub(BACKSLASH_CRLF_RE, BACKSLASH_CRLF_REPLACE) << APOS
|
|
656
|
+
end
|
|
657
|
+
|
|
627
658
|
# Use 1 for true on MSSQL
|
|
628
659
|
def literal_true
|
|
629
660
|
BOOL_TRUE
|
|
@@ -223,7 +223,7 @@ module Sequel
|
|
|
223
223
|
# Use XA START to start a new prepared transaction if the :prepare
|
|
224
224
|
# option is given.
|
|
225
225
|
def begin_transaction(conn, opts={})
|
|
226
|
-
if (s = opts[:prepare]) && (th =
|
|
226
|
+
if (s = opts[:prepare]) && (th = _trans(conn))[:savepoint_level] == 0
|
|
227
227
|
log_connection_execute(conn, "XA START #{literal(s)}")
|
|
228
228
|
th[:savepoint_level] += 1
|
|
229
229
|
else
|
|
@@ -246,7 +246,7 @@ module Sequel
|
|
|
246
246
|
# Prepare the XA transaction for a two-phase commit if the
|
|
247
247
|
# :prepare option is given.
|
|
248
248
|
def commit_transaction(conn, opts={})
|
|
249
|
-
if (s = opts[:prepare]) &&
|
|
249
|
+
if (s = opts[:prepare]) && _trans(conn)[:savepoint_level] <= 1
|
|
250
250
|
log_connection_execute(conn, "XA END #{literal(s)}")
|
|
251
251
|
log_connection_execute(conn, "XA PREPARE #{literal(s)}")
|
|
252
252
|
else
|
|
@@ -335,7 +335,7 @@ module Sequel
|
|
|
335
335
|
|
|
336
336
|
# Rollback the currently open XA transaction
|
|
337
337
|
def rollback_transaction(conn, opts={})
|
|
338
|
-
if (s = opts[:prepare]) &&
|
|
338
|
+
if (s = opts[:prepare]) && _trans(conn)[:savepoint_level] <= 1
|
|
339
339
|
log_connection_execute(conn, "XA END #{literal(s)}")
|
|
340
340
|
log_connection_execute(conn, "XA PREPARE #{literal(s)}")
|
|
341
341
|
log_connection_execute(conn, "XA ROLLBACK #{literal(s)}")
|
|
@@ -353,7 +353,9 @@ module Sequel
|
|
|
353
353
|
def schema_parse_table(table_name, opts)
|
|
354
354
|
m = output_identifier_meth(opts[:dataset])
|
|
355
355
|
im = input_identifier_meth(opts[:dataset])
|
|
356
|
-
|
|
356
|
+
table = SQL::Identifier.new(im.call(table_name))
|
|
357
|
+
table = SQL::QualifiedIdentifier.new(im.call(opts[:schema]), table) if opts[:schema]
|
|
358
|
+
metadata_dataset.with_sql("DESCRIBE ?", table).map do |row|
|
|
357
359
|
row[:auto_increment] = true if row.delete(:Extra).to_s =~ /auto_increment/io
|
|
358
360
|
row[:allow_null] = row.delete(:Null) == 'YES'
|
|
359
361
|
row[:default] = row.delete(:Default)
|
|
@@ -414,6 +416,9 @@ module Sequel
|
|
|
414
416
|
INSERT_CLAUSE_METHODS = Dataset.clause_methods(:insert, %w'insert ignore into columns values on_duplicate_key_update')
|
|
415
417
|
SELECT_CLAUSE_METHODS = Dataset.clause_methods(:select, %w'select distinct calc_found_rows columns from join where group having compounds order limit lock')
|
|
416
418
|
UPDATE_CLAUSE_METHODS = Dataset.clause_methods(:update, %w'update ignore table set where order limit')
|
|
419
|
+
APOS = Dataset::APOS
|
|
420
|
+
APOS_RE = Dataset::APOS_RE
|
|
421
|
+
DOUBLE_APOS = Dataset::DOUBLE_APOS
|
|
417
422
|
SPACE = Dataset::SPACE
|
|
418
423
|
PAREN_OPEN = Dataset::PAREN_OPEN
|
|
419
424
|
PAREN_CLOSE = Dataset::PAREN_CLOSE
|
|
@@ -446,6 +451,8 @@ module Sequel
|
|
|
446
451
|
MATCH_AGAINST_BOOLEAN = ["(MATCH ".freeze, " AGAINST (".freeze, " IN BOOLEAN MODE))".freeze].freeze
|
|
447
452
|
EXPLAIN = 'EXPLAIN '.freeze
|
|
448
453
|
EXPLAIN_EXTENDED = 'EXPLAIN EXTENDED '.freeze
|
|
454
|
+
BACKSLASH_RE = /\\/.freeze
|
|
455
|
+
QUAD_BACKSLASH = "\\\\\\\\".freeze
|
|
449
456
|
|
|
450
457
|
# MySQL specific syntax for LIKE/REGEXP searches, as well as
|
|
451
458
|
# string concatenation.
|
|
@@ -772,6 +779,11 @@ module Sequel
|
|
|
772
779
|
BOOL_FALSE
|
|
773
780
|
end
|
|
774
781
|
|
|
782
|
+
# SQL fragment for String. Doubles \ and ' by default.
|
|
783
|
+
def literal_string_append(sql, v)
|
|
784
|
+
sql << APOS << v.gsub(BACKSLASH_RE, QUAD_BACKSLASH).gsub(APOS_RE, DOUBLE_APOS) << APOS
|
|
785
|
+
end
|
|
786
|
+
|
|
775
787
|
# Use 1 for true on MySQL
|
|
776
788
|
def literal_true
|
|
777
789
|
BOOL_TRUE
|
|
@@ -41,7 +41,7 @@ module Sequel
|
|
|
41
41
|
# arguments.
|
|
42
42
|
def execute_prepared_statement(ps_name, opts, &block)
|
|
43
43
|
args = opts[:arguments]
|
|
44
|
-
ps =
|
|
44
|
+
ps = prepared_statement(ps_name)
|
|
45
45
|
sql = ps.prepared_sql
|
|
46
46
|
synchronize(opts[:server]) do |conn|
|
|
47
47
|
unless conn.prepared_statements[ps_name] == sql
|
|
@@ -137,7 +137,7 @@ module Sequel
|
|
|
137
137
|
ps.extend(PreparedStatementMethods)
|
|
138
138
|
if name
|
|
139
139
|
ps.prepared_statement_name = name
|
|
140
|
-
db.
|
|
140
|
+
db.set_prepared_statement(name, ps)
|
|
141
141
|
end
|
|
142
142
|
ps
|
|
143
143
|
end
|
|
@@ -217,6 +217,8 @@ module Sequel
|
|
|
217
217
|
sql << complex_expression_arg_pairs(args){|a, b| "(#{literal(a)} * power(2, #{literal b}))"}
|
|
218
218
|
when :>>
|
|
219
219
|
sql << complex_expression_arg_pairs(args){|a, b| "(#{literal(a)} / power(2, #{literal b}))"}
|
|
220
|
+
when :%
|
|
221
|
+
sql << complex_expression_arg_pairs(args){|a, b| "MOD(#{literal(a)}, #{literal(b)})"}
|
|
220
222
|
when :ILIKE, :'NOT ILIKE'
|
|
221
223
|
sql << ILIKE_0
|
|
222
224
|
literal_append(sql, args.at(0))
|