sequel 3.44.0 → 3.45.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 +44 -0
- data/Rakefile +12 -4
- data/doc/reflection.rdoc +3 -3
- data/doc/release_notes/3.45.0.txt +179 -0
- data/doc/schema_modification.rdoc +1 -1
- data/doc/transactions.rdoc +23 -0
- data/lib/sequel/adapters/db2.rb +1 -0
- data/lib/sequel/adapters/ibmdb.rb +19 -3
- data/lib/sequel/adapters/jdbc.rb +15 -0
- data/lib/sequel/adapters/jdbc/derby.rb +1 -5
- data/lib/sequel/adapters/jdbc/h2.rb +1 -0
- data/lib/sequel/adapters/jdbc/hsqldb.rb +2 -1
- data/lib/sequel/adapters/jdbc/jtds.rb +5 -0
- data/lib/sequel/adapters/jdbc/mysql.rb +5 -0
- data/lib/sequel/adapters/jdbc/oracle.rb +7 -1
- data/lib/sequel/adapters/jdbc/sqlite.rb +1 -1
- data/lib/sequel/adapters/jdbc/transactions.rb +28 -1
- data/lib/sequel/adapters/mysql.rb +4 -0
- data/lib/sequel/adapters/mysql2.rb +5 -1
- data/lib/sequel/adapters/oracle.rb +18 -0
- data/lib/sequel/adapters/postgres.rb +11 -1
- data/lib/sequel/adapters/shared/access.rb +14 -2
- data/lib/sequel/adapters/shared/cubrid.rb +1 -11
- data/lib/sequel/adapters/shared/db2.rb +11 -6
- data/lib/sequel/adapters/shared/mssql.rb +10 -10
- data/lib/sequel/adapters/shared/mysql.rb +11 -1
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +17 -1
- data/lib/sequel/adapters/shared/oracle.rb +16 -15
- data/lib/sequel/adapters/shared/postgres.rb +91 -59
- data/lib/sequel/adapters/shared/sqlite.rb +1 -4
- data/lib/sequel/adapters/tinytds.rb +15 -0
- data/lib/sequel/connection_pool/threaded.rb +1 -1
- data/lib/sequel/core.rb +10 -0
- data/lib/sequel/database/connecting.rb +2 -0
- data/lib/sequel/database/misc.rb +46 -4
- data/lib/sequel/database/query.rb +33 -14
- data/lib/sequel/database/schema_methods.rb +0 -5
- data/lib/sequel/dataset/misc.rb +9 -0
- data/lib/sequel/dataset/mutation.rb +9 -7
- data/lib/sequel/dataset/sql.rb +13 -0
- data/lib/sequel/exceptions.rb +3 -0
- data/lib/sequel/extensions/connection_validator.rb +1 -1
- data/lib/sequel/extensions/date_arithmetic.rb +0 -8
- data/lib/sequel/extensions/eval_inspect.rb +2 -0
- data/lib/sequel/extensions/named_timezones.rb +18 -2
- data/lib/sequel/extensions/pg_array.rb +5 -1
- data/lib/sequel/extensions/pg_array_ops.rb +2 -0
- data/lib/sequel/extensions/pg_hstore.rb +2 -0
- data/lib/sequel/extensions/pg_hstore_ops.rb +2 -0
- data/lib/sequel/extensions/pg_json.rb +3 -1
- data/lib/sequel/extensions/pg_range.rb +2 -0
- data/lib/sequel/extensions/pg_range_ops.rb +2 -0
- data/lib/sequel/extensions/pg_row.rb +2 -0
- data/lib/sequel/extensions/pg_row_ops.rb +2 -0
- data/lib/sequel/extensions/query.rb +18 -22
- data/lib/sequel/model/associations.rb +3 -4
- data/lib/sequel/model/base.rb +2 -0
- data/lib/sequel/plugins/force_encoding.rb +2 -0
- data/lib/sequel/plugins/json_serializer.rb +155 -39
- data/lib/sequel/plugins/serialization.rb +14 -2
- data/lib/sequel/plugins/unlimited_update.rb +31 -0
- data/lib/sequel/plugins/validation_class_methods.rb +6 -4
- data/lib/sequel/plugins/xml_serializer.rb +133 -30
- data/lib/sequel/sql.rb +2 -0
- data/lib/sequel/timezones.rb +4 -0
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mysql_spec.rb +0 -11
- data/spec/adapters/postgres_spec.rb +86 -54
- data/spec/adapters/spec_helper.rb +6 -0
- data/spec/core/connection_pool_spec.rb +16 -0
- data/spec/core/database_spec.rb +77 -1
- data/spec/core/dataset_spec.rb +30 -15
- data/spec/core/expression_filters_spec.rb +55 -13
- data/spec/core/mock_adapter_spec.rb +4 -0
- data/spec/core/schema_spec.rb +0 -2
- data/spec/core/spec_helper.rb +5 -0
- data/spec/core_extensions_spec.rb +33 -28
- data/spec/extensions/constraint_validations_spec.rb +2 -2
- data/spec/extensions/core_refinements_spec.rb +12 -12
- data/spec/extensions/json_serializer_spec.rb +137 -31
- data/spec/extensions/named_timezones_spec.rb +10 -0
- data/spec/extensions/pg_auto_parameterize_spec.rb +5 -0
- data/spec/extensions/pg_json_spec.rb +14 -0
- data/spec/extensions/pg_row_spec.rb +11 -0
- data/spec/extensions/pretty_table_spec.rb +2 -2
- data/spec/extensions/query_spec.rb +11 -8
- data/spec/extensions/serialization_spec.rb +20 -0
- data/spec/extensions/spec_helper.rb +8 -2
- data/spec/extensions/sql_expr_spec.rb +1 -1
- data/spec/extensions/unlimited_update_spec.rb +20 -0
- data/spec/extensions/xml_serializer_spec.rb +68 -16
- data/spec/integration/dataset_test.rb +28 -0
- data/spec/integration/spec_helper.rb +6 -0
- data/spec/integration/transaction_test.rb +39 -0
- data/spec/model/model_spec.rb +1 -1
- data/spec/sequel_coverage.rb +15 -0
- metadata +8 -3
@@ -54,6 +54,11 @@ module Sequel
|
|
54
54
|
true
|
55
55
|
end
|
56
56
|
|
57
|
+
# DB2 supports transaction isolation levels.
|
58
|
+
def supports_transaction_isolation_levels?
|
59
|
+
true
|
60
|
+
end
|
61
|
+
|
57
62
|
private
|
58
63
|
|
59
64
|
# Handle Oracle specific ALTER TABLE SQL
|
@@ -141,6 +146,7 @@ module Sequel
|
|
141
146
|
/integrity constraint .+ violated/ => ForeignKeyConstraintViolation,
|
142
147
|
/check constraint .+ violated/ => CheckConstraintViolation,
|
143
148
|
/cannot insert NULL into|cannot update .+ to NULL/ => NotNullConstraintViolation,
|
149
|
+
/can't serialize access for this transaction/ => SerializationFailure,
|
144
150
|
}.freeze
|
145
151
|
def database_error_regexps
|
146
152
|
DATABASE_ERROR_REGEXPS
|
@@ -159,6 +165,16 @@ module Sequel
|
|
159
165
|
super
|
160
166
|
end
|
161
167
|
|
168
|
+
TRANSACTION_ISOLATION_LEVELS = {:uncommitted=>'READ COMMITTED'.freeze,
|
169
|
+
:committed=>'READ COMMITTED'.freeze,
|
170
|
+
:repeatable=>'SERIALIZABLE'.freeze,
|
171
|
+
:serializable=>'SERIALIZABLE'.freeze}
|
172
|
+
# Oracle doesn't support READ UNCOMMITTED OR REPEATABLE READ transaction
|
173
|
+
# isolation levels, so upgrade to the next highest level in those cases.
|
174
|
+
def set_transaction_isolation_sql(level)
|
175
|
+
"SET TRANSACTION ISOLATION LEVEL #{TRANSACTION_ISOLATION_LEVELS[level]}"
|
176
|
+
end
|
177
|
+
|
162
178
|
def sequence_for_table(table)
|
163
179
|
return nil unless autosequence
|
164
180
|
@primary_key_sequences.fetch(table) do |key|
|
@@ -217,12 +233,6 @@ module Sequel
|
|
217
233
|
FROM = Dataset::FROM
|
218
234
|
BITCOMP_OPEN = "((0 - ".freeze
|
219
235
|
BITCOMP_CLOSE = ") - 1)".freeze
|
220
|
-
ILIKE_0 = "(UPPER(".freeze
|
221
|
-
ILIKE_1 = ") ".freeze
|
222
|
-
ILIKE_2 = ' UPPER('.freeze
|
223
|
-
ILIKE_3 = "))".freeze
|
224
|
-
LIKE = 'LIKE'.freeze
|
225
|
-
NOT_LIKE = 'NOT LIKE'.freeze
|
226
236
|
TIMESTAMP_FORMAT = "TIMESTAMP '%Y-%m-%d %H:%M:%S%N %z'".freeze
|
227
237
|
TIMESTAMP_OFFSET_FORMAT = "%+03i:%02i".freeze
|
228
238
|
BOOL_FALSE = "'N'".freeze
|
@@ -230,7 +240,6 @@ module Sequel
|
|
230
240
|
HSTAR = "H*".freeze
|
231
241
|
DUAL = ['DUAL'.freeze].freeze
|
232
242
|
|
233
|
-
# Oracle needs to emulate bitwise operators and ILIKE/NOT ILIKE operators.
|
234
243
|
def complex_expression_sql_append(sql, op, args)
|
235
244
|
case op
|
236
245
|
when :&
|
@@ -249,14 +258,6 @@ module Sequel
|
|
249
258
|
sql << complex_expression_arg_pairs(args){|a, b| "(#{literal(a)} / power(2, #{literal b}))"}
|
250
259
|
when :%
|
251
260
|
sql << complex_expression_arg_pairs(args){|a, b| "MOD(#{literal(a)}, #{literal(b)})"}
|
252
|
-
when :ILIKE, :'NOT ILIKE'
|
253
|
-
sql << ILIKE_0
|
254
|
-
literal_append(sql, args.at(0))
|
255
|
-
sql << ILIKE_1
|
256
|
-
sql << (op == :ILIKE ? LIKE : NOT_LIKE)
|
257
|
-
sql<< ILIKE_2
|
258
|
-
literal_append(sql, args.at(1))
|
259
|
-
sql << ILIKE_3
|
260
261
|
else
|
261
262
|
super
|
262
263
|
end
|
@@ -4,15 +4,16 @@ module Sequel
|
|
4
4
|
# Top level module for holding all PostgreSQL-related modules and classes
|
5
5
|
# for Sequel. There are a few module level accessors that are added via
|
6
6
|
# metaprogramming. These are:
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
7
|
+
#
|
8
|
+
# client_min_messages :: Change the minimum level of messages that PostgreSQL will send to the
|
9
|
+
# the client. The PostgreSQL default is NOTICE, the Sequel default is
|
10
|
+
# WARNING. Set to nil to not change the server default. Overridable on
|
11
|
+
# a per instance basis via the :client_min_messages option.
|
12
|
+
# force_standard_strings :: Set to false to not force the use of standard strings. Overridable
|
13
|
+
# on a per instance basis via the :force_standard_strings option.
|
14
|
+
# use_iso_date_format :: (only available when using the native adapter)
|
15
|
+
# Set to false to not change the date format to
|
16
|
+
# ISO. This disables one of Sequel's optimizations.
|
16
17
|
#
|
17
18
|
# Changes in these settings only affect future connections. To make
|
18
19
|
# sure that they are applied, they should generally be called right
|
@@ -290,14 +291,13 @@ module Sequel
|
|
290
291
|
# :name, :on_delete, :on_update, and :deferrable entries in the hashes.
|
291
292
|
def foreign_key_list(table, opts={})
|
292
293
|
m = output_identifier_meth
|
293
|
-
|
294
|
-
schema, table = schema_and_table(table)
|
294
|
+
schema, _ = opts.fetch(:schema, schema_and_table(table))
|
295
295
|
range = 0...32
|
296
296
|
|
297
297
|
base_ds = metadata_dataset.
|
298
|
-
where(:cl__relkind=>'r', :co__contype=>'f', :cl__relname=>im.call(table)).
|
299
298
|
from(:pg_constraint___co).
|
300
|
-
join(:pg_class___cl, :oid=>:conrelid)
|
299
|
+
join(:pg_class___cl, :oid=>:conrelid).
|
300
|
+
where(:cl__relkind=>'r', :co__contype=>'f', :cl__oid=>regclass_oid(table))
|
301
301
|
|
302
302
|
# We split the parsing into two separate queries, which are merged manually later.
|
303
303
|
# This is because PostgreSQL stores both the referencing and referenced columns in
|
@@ -320,8 +320,6 @@ module Sequel
|
|
320
320
|
# If a schema is given, we only search in that schema, and the returned :table
|
321
321
|
# entry is schema qualified as well.
|
322
322
|
if schema
|
323
|
-
ds = ds.join(:pg_namespace___nsp, :oid=>:cl__relnamespace).
|
324
|
-
where(:nsp__nspname=>im.call(schema))
|
325
323
|
ref_ds = ref_ds.join(:pg_namespace___nsp2, :oid=>:cl2__relnamespace).
|
326
324
|
select_more(:nsp2__nspname___schema)
|
327
325
|
end
|
@@ -347,21 +345,18 @@ module Sequel
|
|
347
345
|
# Use the pg_* system tables to determine indexes on a table
|
348
346
|
def indexes(table, opts={})
|
349
347
|
m = output_identifier_meth
|
350
|
-
im = input_identifier_meth
|
351
|
-
schema, table = schema_and_table(table)
|
352
348
|
range = 0...32
|
353
349
|
attnums = server_version >= 80100 ? SQL::Function.new(:ANY, :ind__indkey) : range.map{|x| SQL::Subscript.new(:ind__indkey, [x])}
|
354
350
|
ds = metadata_dataset.
|
355
351
|
from(:pg_class___tab).
|
356
|
-
join(:pg_index___ind, :indrelid=>:oid
|
352
|
+
join(:pg_index___ind, :indrelid=>:oid).
|
357
353
|
join(:pg_class___indc, :oid=>:indexrelid).
|
358
354
|
join(:pg_attribute___att, :attrelid=>:tab__oid, :attnum=>attnums).
|
359
355
|
left_join(:pg_constraint___con, :conname=>:indc__relname).
|
360
|
-
filter(:indc__relkind=>'i', :ind__indisprimary=>false, :indexprs=>nil, :indpred=>nil, :indisvalid=>true).
|
356
|
+
filter(:indc__relkind=>'i', :ind__indisprimary=>false, :indexprs=>nil, :indpred=>nil, :indisvalid=>true, :tab__oid=>regclass_oid(table, opts)).
|
361
357
|
order(:indc__relname, SQL::CaseExpression.new(range.map{|x| [SQL::Subscript.new(:ind__indkey, [x]), x]}, 32, :att__attnum)).
|
362
358
|
select(:indc__relname___name, :ind__indisunique___unique, :att__attname___column, :con__condeferrable___deferrable)
|
363
359
|
|
364
|
-
ds.join!(:pg_namespace___nsp, :oid=>:tab__relnamespace, :nspname=>schema.to_s) if schema
|
365
360
|
ds.filter!(:indisready=>true, :indcheckxmin=>false) if server_version >= 80300
|
366
361
|
|
367
362
|
indexes = {}
|
@@ -391,9 +386,7 @@ module Sequel
|
|
391
386
|
def primary_key(table, opts={})
|
392
387
|
quoted_table = quote_schema_table(table)
|
393
388
|
Sequel.synchronize{return @primary_keys[quoted_table] if @primary_keys.has_key?(quoted_table)}
|
394
|
-
|
395
|
-
sql = "#{SELECT_PK_SQL} AND pg_class.relname = #{literal(table)}"
|
396
|
-
sql << " AND pg_namespace.nspname = #{literal(schema)}" if schema
|
389
|
+
sql = "#{SELECT_PK_SQL} AND pg_class.oid = #{literal(regclass_oid(table, opts))}"
|
397
390
|
value = fetch(sql).single_value
|
398
391
|
Sequel.synchronize{@primary_keys[quoted_table] = value}
|
399
392
|
end
|
@@ -402,16 +395,12 @@ module Sequel
|
|
402
395
|
def primary_key_sequence(table, opts={})
|
403
396
|
quoted_table = quote_schema_table(table)
|
404
397
|
Sequel.synchronize{return @primary_key_sequences[quoted_table] if @primary_key_sequences.has_key?(quoted_table)}
|
405
|
-
|
406
|
-
table = literal(table)
|
407
|
-
sql = "#{SELECT_SERIAL_SEQUENCE_SQL} AND t.relname = #{table}"
|
408
|
-
sql << " AND name.nspname = #{literal(schema)}" if schema
|
398
|
+
sql = "#{SELECT_SERIAL_SEQUENCE_SQL} AND t.oid = #{literal(regclass_oid(table, opts))}"
|
409
399
|
if pks = fetch(sql).single_record
|
410
400
|
value = literal(SQL::QualifiedIdentifier.new(pks[:schema], pks[:sequence]))
|
411
401
|
Sequel.synchronize{@primary_key_sequences[quoted_table] = value}
|
412
402
|
else
|
413
|
-
sql = "#{SELECT_CUSTOM_SEQUENCE_SQL} AND t.
|
414
|
-
sql << " AND name.nspname = #{literal(schema)}" if schema
|
403
|
+
sql = "#{SELECT_CUSTOM_SEQUENCE_SQL} AND t.oid = #{literal(regclass_oid(table, opts))}"
|
415
404
|
if pks = fetch(sql).single_record
|
416
405
|
value = literal(SQL::QualifiedIdentifier.new(pks[:schema], LiteralString.new(pks[:sequence])))
|
417
406
|
Sequel.synchronize{@primary_key_sequences[quoted_table] = value}
|
@@ -513,8 +502,10 @@ module Sequel
|
|
513
502
|
# otherwise, an array of symbols of table names is returned.
|
514
503
|
#
|
515
504
|
# Options:
|
516
|
-
#
|
517
|
-
#
|
505
|
+
# :qualify :: Return the tables as Sequel::SQL::QualifiedIdentifier instances,
|
506
|
+
# using the schema the table is located in as the qualifier.
|
507
|
+
# :schema :: The schema to search (default_schema by default)
|
508
|
+
# :server :: The server to use
|
518
509
|
def tables(opts={}, &block)
|
519
510
|
pg_class_relname('r', opts, &block)
|
520
511
|
end
|
@@ -529,8 +520,10 @@ module Sequel
|
|
529
520
|
# Array of symbols specifying view names in the current database.
|
530
521
|
#
|
531
522
|
# Options:
|
532
|
-
#
|
533
|
-
#
|
523
|
+
# :qualify :: Return the views as Sequel::SQL::QualifiedIdentifier instances,
|
524
|
+
# using the schema the view is located in as the qualifier.
|
525
|
+
# :schema :: The schema to search (default_schema by default)
|
526
|
+
# :server :: The server to use
|
534
527
|
def views(opts={})
|
535
528
|
pg_class_relname('v', opts)
|
536
529
|
end
|
@@ -606,8 +599,8 @@ module Sequel
|
|
606
599
|
# The SQL queries to execute when starting a new connection.
|
607
600
|
def connection_configuration_sqls
|
608
601
|
sqls = []
|
609
|
-
sqls << "SET standard_conforming_strings = ON" if Postgres.force_standard_strings
|
610
|
-
if cmm = Postgres.client_min_messages
|
602
|
+
sqls << "SET standard_conforming_strings = ON" if typecast_value_boolean(@opts.fetch(:force_standard_strings, Postgres.force_standard_strings))
|
603
|
+
if (cmm = @opts.fetch(:client_min_messages, Postgres.client_min_messages)) && !cmm.to_s.empty?
|
611
604
|
sqls << "SET client_min_messages = '#{cmm.to_s.upcase}'"
|
612
605
|
end
|
613
606
|
sqls
|
@@ -630,13 +623,26 @@ module Sequel
|
|
630
623
|
end
|
631
624
|
end
|
632
625
|
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
626
|
+
EXCLUSION_CONSTRAINT_SQL_STATE = '23P01'.freeze
|
627
|
+
def database_specific_error_class_from_sqlstate(sqlstate)
|
628
|
+
if sqlstate == EXCLUSION_CONSTRAINT_SQL_STATE
|
629
|
+
ExclusionConstraintViolation
|
630
|
+
else
|
631
|
+
super
|
632
|
+
end
|
633
|
+
end
|
634
|
+
|
635
|
+
DATABASE_ERROR_REGEXPS = [
|
636
|
+
# Add this check first, since otherwise it's possible for users to control
|
637
|
+
# which exception class is generated.
|
638
|
+
[/invalid input syntax/, DatabaseError],
|
639
|
+
[/duplicate key value violates unique constraint/, UniqueConstraintViolation],
|
640
|
+
[/violates foreign key constraint/, ForeignKeyConstraintViolation],
|
641
|
+
[/violates check constraint/, CheckConstraintViolation],
|
642
|
+
[/violates not-null constraint/, NotNullConstraintViolation],
|
643
|
+
[/conflicting key value violates exclusion constraint/, ExclusionConstraintViolation],
|
644
|
+
[/could not serialize access/, SerializationFailure],
|
645
|
+
].freeze
|
640
646
|
def database_error_regexps
|
641
647
|
DATABASE_ERROR_REGEXPS
|
642
648
|
end
|
@@ -834,7 +840,13 @@ module Sequel
|
|
834
840
|
ds = metadata_dataset.from(:pg_class).filter(:relkind=>type).select(:relname).exclude(SQL::StringExpression.like(:relname, SYSTEM_TABLE_REGEXP)).server(opts[:server]).join(:pg_namespace, :oid=>:relnamespace)
|
835
841
|
ds = filter_schema(ds, opts)
|
836
842
|
m = output_identifier_meth
|
837
|
-
block_given?
|
843
|
+
if block_given?
|
844
|
+
yield(ds)
|
845
|
+
elsif opts[:qualify]
|
846
|
+
ds.select_append(:pg_namespace__nspname).map{|r| Sequel.qualify(m.call(r[:nspname]), m.call(r[:relname]))}
|
847
|
+
else
|
848
|
+
ds.map{|r| m.call(r[:relname])}
|
849
|
+
end
|
838
850
|
end
|
839
851
|
|
840
852
|
# Use a dollar sign instead of question mark for the argument
|
@@ -843,6 +855,28 @@ module Sequel
|
|
843
855
|
PREPARED_ARG_PLACEHOLDER
|
844
856
|
end
|
845
857
|
|
858
|
+
# Return an expression the oid for the table expr. Used by the metadata parsing
|
859
|
+
# code to disambiguate unqualified tables.
|
860
|
+
def regclass_oid(expr, opts={})
|
861
|
+
if expr.is_a?(String) && !expr.is_a?(LiteralString)
|
862
|
+
expr = Sequel.identifier(expr)
|
863
|
+
end
|
864
|
+
|
865
|
+
sch, table = schema_and_table(expr)
|
866
|
+
sch ||= opts[:schema]
|
867
|
+
if sch
|
868
|
+
expr = Sequel.qualify(sch, table)
|
869
|
+
end
|
870
|
+
|
871
|
+
expr = if ds = opts[:dataset]
|
872
|
+
ds.literal(expr)
|
873
|
+
else
|
874
|
+
literal(expr)
|
875
|
+
end
|
876
|
+
|
877
|
+
Sequel.cast(expr.to_s,:regclass).cast(:oid)
|
878
|
+
end
|
879
|
+
|
846
880
|
# Remove the cached entries for primary keys and sequences when a table is
|
847
881
|
# changed.
|
848
882
|
def remove_cached_schema(table)
|
@@ -879,35 +913,22 @@ module Sequel
|
|
879
913
|
# The dataset used for parsing table schemas, using the pg_* system catalogs.
|
880
914
|
def schema_parse_table(table_name, opts)
|
881
915
|
m = output_identifier_meth(opts[:dataset])
|
882
|
-
m2 = input_identifier_meth(opts[:dataset])
|
883
916
|
ds = metadata_dataset.select(:pg_attribute__attname___name,
|
884
917
|
SQL::Cast.new(:pg_attribute__atttypid, :integer).as(:oid),
|
885
918
|
SQL::Function.new(:format_type, :pg_type__oid, :pg_attribute__atttypmod).as(:db_type),
|
886
919
|
SQL::Function.new(:pg_get_expr, :pg_attrdef__adbin, :pg_class__oid).as(:default),
|
887
920
|
SQL::BooleanExpression.new(:NOT, :pg_attribute__attnotnull).as(:allow_null),
|
888
|
-
SQL::Function.new(:COALESCE, SQL::BooleanExpression.from_value_pairs(:pg_attribute__attnum => SQL::Function.new(:ANY, :pg_index__indkey)), false).as(:primary_key)
|
889
|
-
:pg_namespace__nspname).
|
921
|
+
SQL::Function.new(:COALESCE, SQL::BooleanExpression.from_value_pairs(:pg_attribute__attnum => SQL::Function.new(:ANY, :pg_index__indkey)), false).as(:primary_key)).
|
890
922
|
from(:pg_class).
|
891
923
|
join(:pg_attribute, :attrelid=>:oid).
|
892
924
|
join(:pg_type, :oid=>:atttypid).
|
893
|
-
join(:pg_namespace, :oid=>:pg_class__relnamespace).
|
894
925
|
left_outer_join(:pg_attrdef, :adrelid=>:pg_class__oid, :adnum=>:pg_attribute__attnum).
|
895
926
|
left_outer_join(:pg_index, :indrelid=>:pg_class__oid, :indisprimary=>true).
|
896
927
|
filter(:pg_attribute__attisdropped=>false).
|
897
928
|
filter{|o| o.pg_attribute__attnum > 0}.
|
898
|
-
filter(:
|
929
|
+
filter(:pg_class__oid=>regclass_oid(table_name, opts)).
|
899
930
|
order(:pg_attribute__attnum)
|
900
|
-
ds = filter_schema(ds, opts)
|
901
|
-
current_schema = nil
|
902
931
|
ds.map do |row|
|
903
|
-
sch = row.delete(:nspname)
|
904
|
-
if current_schema
|
905
|
-
if sch != current_schema
|
906
|
-
raise Error, "columns from tables in two separate schema were returned (please specify a schema): #{current_schema.inspect}, #{sch.inspect}"
|
907
|
-
end
|
908
|
-
else
|
909
|
-
current_schema = sch
|
910
|
-
end
|
911
932
|
row[:default] = nil if blank_object?(row[:default])
|
912
933
|
row[:type] = schema_column_type(row[:db_type])
|
913
934
|
[m.call(row.delete(:name)), row]
|
@@ -1010,6 +1031,8 @@ module Sequel
|
|
1010
1031
|
PAREN_OPEN = Dataset::PAREN_OPEN
|
1011
1032
|
PAREN_CLOSE = Dataset::PAREN_CLOSE
|
1012
1033
|
COMMA = Dataset::COMMA
|
1034
|
+
ESCAPE = Dataset::ESCAPE
|
1035
|
+
BACKSLASH = Dataset::BACKSLASH
|
1013
1036
|
AS = Dataset::AS
|
1014
1037
|
XOR_OP = ' # '.freeze
|
1015
1038
|
CRLF = "\r\n".freeze
|
@@ -1042,7 +1065,8 @@ module Sequel
|
|
1042
1065
|
end
|
1043
1066
|
|
1044
1067
|
# Handle converting the ruby xor operator (^) into the
|
1045
|
-
# PostgreSQL xor operator (#)
|
1068
|
+
# PostgreSQL xor operator (#), and use the ILIKE and NOT ILIKE
|
1069
|
+
# operators.
|
1046
1070
|
def complex_expression_sql_append(sql, op, args)
|
1047
1071
|
case op
|
1048
1072
|
when :^
|
@@ -1053,6 +1077,14 @@ module Sequel
|
|
1053
1077
|
literal_append(sql, a)
|
1054
1078
|
c ||= true
|
1055
1079
|
end
|
1080
|
+
when :ILIKE, :'NOT ILIKE'
|
1081
|
+
sql << PAREN_OPEN
|
1082
|
+
literal_append(sql, args.at(0))
|
1083
|
+
sql << SPACE << op.to_s << SPACE
|
1084
|
+
literal_append(sql, args.at(1))
|
1085
|
+
sql << ESCAPE
|
1086
|
+
literal_append(sql, BACKSLASH)
|
1087
|
+
sql << PAREN_CLOSE
|
1056
1088
|
else
|
1057
1089
|
super
|
1058
1090
|
end
|
@@ -496,13 +496,10 @@ module Sequel
|
|
496
496
|
end
|
497
497
|
end
|
498
498
|
|
499
|
-
# SQLite
|
500
|
-
# It also doesn't support a NOT LIKE b, you need to use NOT (a LIKE b).
|
499
|
+
# SQLite doesn't support a NOT LIKE b, you need to use NOT (a LIKE b).
|
501
500
|
# It doesn't support xor or the extract function natively, so those have to be emulated.
|
502
501
|
def complex_expression_sql_append(sql, op, args)
|
503
502
|
case op
|
504
|
-
when :ILIKE
|
505
|
-
super(sql, :LIKE, args.map{|a| SQL::Function.new(:upper, a)})
|
506
503
|
when :"NOT LIKE", :"NOT ILIKE"
|
507
504
|
sql << NOT_SPACE
|
508
505
|
complex_expression_sql_append(sql, (op == :"NOT ILIKE" ? :ILIKE : :LIKE), args)
|
@@ -109,6 +109,21 @@ module Sequel
|
|
109
109
|
[TinyTds::Error]
|
110
110
|
end
|
111
111
|
|
112
|
+
# Stupid MSSQL maps foreign key and check constraint violations
|
113
|
+
# to the same error code, and doesn't expose the sqlstate. Use
|
114
|
+
# database error numbers if present and unambiguous, otherwise
|
115
|
+
# fallback to the regexp mapping.
|
116
|
+
def database_specific_error_class(exception, opts)
|
117
|
+
case exception.db_error_number
|
118
|
+
when 515
|
119
|
+
NotNullConstraintViolation
|
120
|
+
when 2627
|
121
|
+
UniqueConstraintViolation
|
122
|
+
else
|
123
|
+
super
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
112
127
|
# Return true if the :conn argument is present and not active.
|
113
128
|
def disconnect_error?(e, opts)
|
114
129
|
super || (opts[:conn] && !opts[:conn].active?)
|
@@ -30,7 +30,7 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
|
|
30
30
|
@connection_handling = opts[:connection_handling]
|
31
31
|
@available_connections = []
|
32
32
|
@allocated = {}
|
33
|
-
@timeout =
|
33
|
+
@timeout = Float(opts[:pool_timeout] || 5)
|
34
34
|
@sleep_time = Float(opts[:pool_sleep_time] || 0.001)
|
35
35
|
end
|
36
36
|
|
data/lib/sequel/core.rb
CHANGED
@@ -208,6 +208,12 @@ module Sequel
|
|
208
208
|
def self.identifier_output_method=(value)
|
209
209
|
Database.identifier_output_method = value
|
210
210
|
end
|
211
|
+
|
212
|
+
# Parse the string as JSON and return the result.
|
213
|
+
# This is solely for internal use, it should not be used externally.
|
214
|
+
def self.parse_json(json) # :nodoc:
|
215
|
+
JSON.parse(json, :create_additions=>false)
|
216
|
+
end
|
211
217
|
|
212
218
|
# Set whether to quote identifiers for all databases by default. By default,
|
213
219
|
# Sequel quotes identifiers in all SQL strings, so to turn that off:
|
@@ -312,6 +318,7 @@ module Sequel
|
|
312
318
|
end
|
313
319
|
|
314
320
|
if defined?(RUBY_ENGINE) && RUBY_ENGINE != 'ruby'
|
321
|
+
# :nocov:
|
315
322
|
# Mutex used to protect mutable data structures
|
316
323
|
@data_mutex = Mutex.new
|
317
324
|
|
@@ -321,6 +328,7 @@ module Sequel
|
|
321
328
|
def self.synchronize(&block)
|
322
329
|
@single_threaded ? yield : @data_mutex.synchronize(&block)
|
323
330
|
end
|
331
|
+
# :nocov:
|
324
332
|
else
|
325
333
|
# Yield directly to the block. You don't need to synchronize
|
326
334
|
# access on MRI because the GVL makes certain methods atomic.
|
@@ -424,7 +432,9 @@ module Sequel
|
|
424
432
|
|
425
433
|
require(%w"sql connection_pool exceptions dataset database timezones ast_transformer version")
|
426
434
|
if !defined?(::SEQUEL_NO_CORE_EXTENSIONS) && !ENV.has_key?('SEQUEL_NO_CORE_EXTENSIONS')
|
435
|
+
# :nocov:
|
427
436
|
extension(:core_extensions)
|
437
|
+
# :nocov:
|
428
438
|
end
|
429
439
|
|
430
440
|
# Add the database adapter class methods to Sequel via metaprogramming
|
@@ -236,9 +236,11 @@ module Sequel
|
|
236
236
|
@pool.hold(server || :default){|conn| yield conn}
|
237
237
|
end
|
238
238
|
else
|
239
|
+
# :nocov:
|
239
240
|
def synchronize(server=nil, &block)
|
240
241
|
@pool.hold(server || :default, &block)
|
241
242
|
end
|
243
|
+
# :nocov:
|
242
244
|
end
|
243
245
|
|
244
246
|
# Attempts to acquire a database connection. Returns true if successful.
|