sequel 5.39.0 → 5.63.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.
- checksums.yaml +4 -4
- data/CHANGELOG +308 -0
- data/MIT-LICENSE +1 -1
- data/README.rdoc +57 -25
- data/bin/sequel +11 -3
- data/doc/advanced_associations.rdoc +13 -13
- data/doc/association_basics.rdoc +89 -24
- data/doc/cheat_sheet.rdoc +11 -3
- data/doc/migration.rdoc +12 -6
- data/doc/model_hooks.rdoc +1 -1
- data/doc/object_model.rdoc +8 -8
- data/doc/opening_databases.rdoc +18 -11
- data/doc/postgresql.rdoc +16 -8
- data/doc/querying.rdoc +5 -3
- data/doc/release_notes/5.40.0.txt +40 -0
- data/doc/release_notes/5.41.0.txt +25 -0
- data/doc/release_notes/5.42.0.txt +136 -0
- data/doc/release_notes/5.43.0.txt +98 -0
- data/doc/release_notes/5.44.0.txt +32 -0
- data/doc/release_notes/5.45.0.txt +34 -0
- data/doc/release_notes/5.46.0.txt +87 -0
- data/doc/release_notes/5.47.0.txt +59 -0
- data/doc/release_notes/5.48.0.txt +14 -0
- data/doc/release_notes/5.49.0.txt +59 -0
- data/doc/release_notes/5.50.0.txt +78 -0
- data/doc/release_notes/5.51.0.txt +47 -0
- data/doc/release_notes/5.52.0.txt +87 -0
- data/doc/release_notes/5.53.0.txt +23 -0
- data/doc/release_notes/5.54.0.txt +27 -0
- data/doc/release_notes/5.55.0.txt +21 -0
- data/doc/release_notes/5.56.0.txt +51 -0
- data/doc/release_notes/5.57.0.txt +23 -0
- data/doc/release_notes/5.58.0.txt +31 -0
- data/doc/release_notes/5.59.0.txt +73 -0
- data/doc/release_notes/5.60.0.txt +22 -0
- data/doc/release_notes/5.61.0.txt +43 -0
- data/doc/release_notes/5.62.0.txt +132 -0
- data/doc/release_notes/5.63.0.txt +33 -0
- data/doc/schema_modification.rdoc +1 -1
- data/doc/security.rdoc +9 -9
- data/doc/sql.rdoc +27 -15
- data/doc/testing.rdoc +22 -11
- data/doc/transactions.rdoc +6 -6
- data/doc/virtual_rows.rdoc +2 -2
- data/lib/sequel/adapters/ado/access.rb +1 -1
- data/lib/sequel/adapters/ado.rb +17 -17
- data/lib/sequel/adapters/amalgalite.rb +3 -5
- data/lib/sequel/adapters/ibmdb.rb +2 -2
- data/lib/sequel/adapters/jdbc/derby.rb +8 -0
- data/lib/sequel/adapters/jdbc/h2.rb +60 -10
- data/lib/sequel/adapters/jdbc/hsqldb.rb +6 -0
- data/lib/sequel/adapters/jdbc/postgresql.rb +4 -4
- data/lib/sequel/adapters/jdbc.rb +16 -18
- data/lib/sequel/adapters/mysql.rb +80 -67
- data/lib/sequel/adapters/mysql2.rb +54 -49
- data/lib/sequel/adapters/odbc.rb +6 -2
- data/lib/sequel/adapters/oracle.rb +3 -3
- data/lib/sequel/adapters/postgres.rb +83 -40
- data/lib/sequel/adapters/shared/access.rb +11 -1
- data/lib/sequel/adapters/shared/db2.rb +30 -0
- data/lib/sequel/adapters/shared/mssql.rb +58 -7
- data/lib/sequel/adapters/shared/mysql.rb +40 -2
- data/lib/sequel/adapters/shared/oracle.rb +76 -0
- data/lib/sequel/adapters/shared/postgres.rb +418 -174
- data/lib/sequel/adapters/shared/sqlanywhere.rb +10 -0
- data/lib/sequel/adapters/shared/sqlite.rb +102 -11
- data/lib/sequel/adapters/sqlanywhere.rb +1 -1
- data/lib/sequel/adapters/sqlite.rb +60 -18
- data/lib/sequel/adapters/tinytds.rb +1 -1
- data/lib/sequel/adapters/utils/columns_limit_1.rb +22 -0
- data/lib/sequel/adapters/utils/mysql_mysql2.rb +1 -1
- data/lib/sequel/ast_transformer.rb +6 -0
- data/lib/sequel/connection_pool/sharded_single.rb +5 -7
- data/lib/sequel/connection_pool/sharded_threaded.rb +5 -1
- data/lib/sequel/connection_pool/single.rb +6 -8
- data/lib/sequel/connection_pool/threaded.rb +8 -8
- data/lib/sequel/connection_pool/timed_queue.rb +257 -0
- data/lib/sequel/connection_pool.rb +47 -30
- data/lib/sequel/core.rb +28 -18
- data/lib/sequel/database/connecting.rb +26 -2
- data/lib/sequel/database/misc.rb +69 -14
- data/lib/sequel/database/query.rb +38 -1
- data/lib/sequel/database/schema_generator.rb +45 -52
- data/lib/sequel/database/schema_methods.rb +17 -1
- data/lib/sequel/dataset/actions.rb +107 -13
- data/lib/sequel/dataset/features.rb +20 -0
- data/lib/sequel/dataset/misc.rb +1 -1
- data/lib/sequel/dataset/prepared_statements.rb +2 -0
- data/lib/sequel/dataset/query.rb +118 -16
- data/lib/sequel/dataset/sql.rb +177 -47
- data/lib/sequel/extensions/_model_pg_row.rb +0 -12
- data/lib/sequel/extensions/_pretty_table.rb +1 -1
- data/lib/sequel/extensions/any_not_empty.rb +1 -1
- data/lib/sequel/extensions/async_thread_pool.rb +438 -0
- data/lib/sequel/extensions/auto_literal_strings.rb +1 -1
- data/lib/sequel/extensions/blank.rb +8 -0
- data/lib/sequel/extensions/constraint_validations.rb +1 -1
- data/lib/sequel/extensions/core_refinements.rb +36 -11
- data/lib/sequel/extensions/date_arithmetic.rb +71 -31
- data/lib/sequel/extensions/date_parse_input_handler.rb +67 -0
- data/lib/sequel/extensions/datetime_parse_to_time.rb +5 -1
- data/lib/sequel/extensions/duplicate_columns_handler.rb +1 -1
- data/lib/sequel/extensions/eval_inspect.rb +2 -0
- data/lib/sequel/extensions/inflector.rb +9 -1
- data/lib/sequel/extensions/is_distinct_from.rb +141 -0
- data/lib/sequel/extensions/looser_typecasting.rb +3 -0
- data/lib/sequel/extensions/migration.rb +7 -2
- data/lib/sequel/extensions/named_timezones.rb +26 -6
- data/lib/sequel/extensions/pagination.rb +1 -1
- data/lib/sequel/extensions/pg_array.rb +23 -3
- data/lib/sequel/extensions/pg_array_ops.rb +2 -2
- data/lib/sequel/extensions/pg_auto_parameterize.rb +478 -0
- data/lib/sequel/extensions/pg_enum.rb +1 -1
- data/lib/sequel/extensions/pg_extended_date_support.rb +28 -25
- data/lib/sequel/extensions/pg_extended_integer_support.rb +116 -0
- data/lib/sequel/extensions/pg_hstore.rb +6 -1
- data/lib/sequel/extensions/pg_hstore_ops.rb +53 -3
- data/lib/sequel/extensions/pg_inet.rb +10 -11
- data/lib/sequel/extensions/pg_inet_ops.rb +1 -1
- data/lib/sequel/extensions/pg_interval.rb +45 -19
- data/lib/sequel/extensions/pg_json.rb +13 -15
- data/lib/sequel/extensions/pg_json_ops.rb +73 -2
- data/lib/sequel/extensions/pg_loose_count.rb +3 -1
- data/lib/sequel/extensions/pg_multirange.rb +367 -0
- data/lib/sequel/extensions/pg_range.rb +10 -23
- data/lib/sequel/extensions/pg_range_ops.rb +37 -9
- data/lib/sequel/extensions/pg_row.rb +19 -13
- data/lib/sequel/extensions/pg_row_ops.rb +1 -1
- data/lib/sequel/extensions/query.rb +2 -0
- data/lib/sequel/extensions/s.rb +2 -1
- data/lib/sequel/extensions/schema_dumper.rb +13 -2
- data/lib/sequel/extensions/server_block.rb +8 -12
- data/lib/sequel/extensions/sql_comments.rb +110 -3
- data/lib/sequel/extensions/sql_log_normalizer.rb +108 -0
- data/lib/sequel/extensions/sqlite_json_ops.rb +255 -0
- data/lib/sequel/extensions/string_agg.rb +1 -1
- data/lib/sequel/extensions/string_date_time.rb +19 -23
- data/lib/sequel/extensions/symbol_aref.rb +2 -0
- data/lib/sequel/model/associations.rb +325 -96
- data/lib/sequel/model/base.rb +51 -27
- data/lib/sequel/model/errors.rb +10 -1
- data/lib/sequel/model/inflections.rb +1 -1
- data/lib/sequel/model/plugins.rb +5 -0
- data/lib/sequel/plugins/association_proxies.rb +2 -0
- data/lib/sequel/plugins/async_thread_pool.rb +39 -0
- data/lib/sequel/plugins/auto_restrict_eager_graph.rb +62 -0
- data/lib/sequel/plugins/auto_validations.rb +87 -15
- data/lib/sequel/plugins/auto_validations_constraint_validations_presence_message.rb +68 -0
- data/lib/sequel/plugins/class_table_inheritance.rb +2 -2
- data/lib/sequel/plugins/column_encryption.rb +728 -0
- data/lib/sequel/plugins/composition.rb +10 -4
- data/lib/sequel/plugins/concurrent_eager_loading.rb +174 -0
- data/lib/sequel/plugins/constraint_validations.rb +2 -1
- data/lib/sequel/plugins/dataset_associations.rb +4 -1
- data/lib/sequel/plugins/dirty.rb +1 -1
- data/lib/sequel/plugins/enum.rb +124 -0
- data/lib/sequel/plugins/finder.rb +3 -1
- data/lib/sequel/plugins/insert_conflict.rb +4 -0
- data/lib/sequel/plugins/instance_specific_default.rb +1 -1
- data/lib/sequel/plugins/json_serializer.rb +39 -24
- data/lib/sequel/plugins/lazy_attributes.rb +3 -0
- data/lib/sequel/plugins/list.rb +3 -1
- data/lib/sequel/plugins/many_through_many.rb +108 -9
- data/lib/sequel/plugins/nested_attributes.rb +12 -7
- data/lib/sequel/plugins/pg_array_associations.rb +56 -38
- data/lib/sequel/plugins/pg_auto_constraint_validations.rb +3 -1
- data/lib/sequel/plugins/prepared_statements.rb +10 -1
- data/lib/sequel/plugins/primary_key_lookup_check_values.rb +154 -0
- data/lib/sequel/plugins/rcte_tree.rb +27 -19
- data/lib/sequel/plugins/require_valid_schema.rb +67 -0
- data/lib/sequel/plugins/serialization.rb +9 -3
- data/lib/sequel/plugins/serialization_modification_detection.rb +2 -1
- data/lib/sequel/plugins/single_table_inheritance.rb +8 -0
- data/lib/sequel/plugins/sql_comments.rb +189 -0
- data/lib/sequel/plugins/static_cache.rb +1 -1
- data/lib/sequel/plugins/subclasses.rb +28 -11
- data/lib/sequel/plugins/tactical_eager_loading.rb +23 -10
- data/lib/sequel/plugins/timestamps.rb +1 -1
- data/lib/sequel/plugins/unused_associations.rb +521 -0
- data/lib/sequel/plugins/update_or_create.rb +1 -1
- data/lib/sequel/plugins/validate_associated.rb +22 -12
- data/lib/sequel/plugins/validation_helpers.rb +38 -11
- data/lib/sequel/plugins/xml_serializer.rb +1 -1
- data/lib/sequel/sql.rb +1 -1
- data/lib/sequel/timezones.rb +12 -14
- data/lib/sequel/version.rb +1 -1
- metadata +97 -43
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen-string-literal: true
|
|
2
2
|
|
|
3
|
+
require_relative '../utils/columns_limit_1'
|
|
4
|
+
|
|
3
5
|
module Sequel
|
|
4
6
|
module SqlAnywhere
|
|
5
7
|
Sequel::Database.set_shared_adapter_scheme(:sqlanywhere, self)
|
|
@@ -193,6 +195,11 @@ module Sequel
|
|
|
193
195
|
end
|
|
194
196
|
end
|
|
195
197
|
|
|
198
|
+
# SQLAnywhere tinyint types are unsigned.
|
|
199
|
+
def column_schema_tinyint_type_is_unsigned?
|
|
200
|
+
true
|
|
201
|
+
end
|
|
202
|
+
|
|
196
203
|
# SqlAnywhere doesn't support CREATE TABLE AS, it only supports SELECT INTO.
|
|
197
204
|
# Emulating CREATE TABLE AS using SELECT INTO is only possible if a dataset
|
|
198
205
|
# is given as the argument, it can't work with a string, so raise an
|
|
@@ -211,6 +218,8 @@ module Sequel
|
|
|
211
218
|
def schema_column_type(db_type)
|
|
212
219
|
if convert_smallint_to_bool && db_type =~ /smallint/i
|
|
213
220
|
:boolean
|
|
221
|
+
elsif db_type =~ /unsigned (big)?int/i
|
|
222
|
+
:integer
|
|
214
223
|
else
|
|
215
224
|
super
|
|
216
225
|
end
|
|
@@ -234,6 +243,7 @@ module Sequel
|
|
|
234
243
|
module DatasetMethods
|
|
235
244
|
Dataset.def_sql_method(self, :insert, %w'insert into columns values')
|
|
236
245
|
Dataset.def_sql_method(self, :select, %w'with select distinct limit columns into from join where group having window compounds order lock')
|
|
246
|
+
include ::Sequel::Dataset::ColumnsLimit1
|
|
237
247
|
|
|
238
248
|
# Whether to convert smallint to boolean arguments for this dataset.
|
|
239
249
|
# Defaults to the IBMDB module setting.
|
|
@@ -239,8 +239,12 @@ module Sequel
|
|
|
239
239
|
super
|
|
240
240
|
end
|
|
241
241
|
when :drop_column
|
|
242
|
-
|
|
243
|
-
|
|
242
|
+
if sqlite_version >= 33500
|
|
243
|
+
super
|
|
244
|
+
else
|
|
245
|
+
ocp = lambda{|oc| oc.delete_if{|c| c.to_s == op[:name].to_s}}
|
|
246
|
+
duplicate_table(table, :old_columns_proc=>ocp){|columns| columns.delete_if{|s| s[:name].to_s == op[:name].to_s}}
|
|
247
|
+
end
|
|
244
248
|
when :rename_column
|
|
245
249
|
if sqlite_version >= 32500
|
|
246
250
|
super
|
|
@@ -316,6 +320,11 @@ module Sequel
|
|
|
316
320
|
end
|
|
317
321
|
end
|
|
318
322
|
|
|
323
|
+
# SQLite does not restrict the integer type to a specific range.
|
|
324
|
+
def column_schema_integer_min_max_values(db_type)
|
|
325
|
+
nil
|
|
326
|
+
end
|
|
327
|
+
|
|
319
328
|
# Array of PRAGMA SQL statements based on the Database options that should be applied to
|
|
320
329
|
# new connections.
|
|
321
330
|
def connection_pragmas
|
|
@@ -333,6 +342,11 @@ module Sequel
|
|
|
333
342
|
ps
|
|
334
343
|
end
|
|
335
344
|
|
|
345
|
+
# Support creating STRICT tables via :strict option
|
|
346
|
+
def create_table_sql(name, generator, options)
|
|
347
|
+
"#{super}#{' STRICT' if options[:strict]}"
|
|
348
|
+
end
|
|
349
|
+
|
|
336
350
|
# SQLite support creating temporary views.
|
|
337
351
|
def create_view_prefix_sql(name, options)
|
|
338
352
|
create_view_sql_append_columns("CREATE #{'TEMPORARY 'if options[:temp]}VIEW #{quote_schema_table(name)}", options[:columns])
|
|
@@ -343,6 +357,7 @@ module Sequel
|
|
|
343
357
|
/foreign key constraint failed\z/i => ForeignKeyConstraintViolation,
|
|
344
358
|
/\A(SQLITE ERROR 275 \(CONSTRAINT_CHECK\) : )?CHECK constraint failed/ => CheckConstraintViolation,
|
|
345
359
|
/\A(SQLITE ERROR 19 \(CONSTRAINT\) : )?constraint failed\z/ => ConstraintViolation,
|
|
360
|
+
/\Acannot store [A-Z]+ value in [A-Z]+ column / => ConstraintViolation,
|
|
346
361
|
/may not be NULL\z|NOT NULL constraint failed: .+\z/ => NotNullConstraintViolation,
|
|
347
362
|
/\ASQLITE ERROR \d+ \(\) : CHECK constraint failed: / => CheckConstraintViolation
|
|
348
363
|
}.freeze
|
|
@@ -389,7 +404,7 @@ module Sequel
|
|
|
389
404
|
old_columns = def_columns.map{|c| c[:name]}
|
|
390
405
|
opts[:old_columns_proc].call(old_columns) if opts[:old_columns_proc]
|
|
391
406
|
|
|
392
|
-
yield def_columns if
|
|
407
|
+
yield def_columns if defined?(yield)
|
|
393
408
|
|
|
394
409
|
constraints = (opts[:constraints] || []).dup
|
|
395
410
|
pks = []
|
|
@@ -424,10 +439,10 @@ module Sequel
|
|
|
424
439
|
skip_indexes = []
|
|
425
440
|
indexes(table, :only_autocreated=>true).each do |name, h|
|
|
426
441
|
skip_indexes << name
|
|
427
|
-
if h[:unique]
|
|
442
|
+
if h[:unique] && !opts[:no_unique]
|
|
428
443
|
if h[:columns].length == 1
|
|
429
444
|
unique_columns.concat(h[:columns])
|
|
430
|
-
elsif h[:columns].map(&:to_s) != pks
|
|
445
|
+
elsif h[:columns].map(&:to_s) != pks
|
|
431
446
|
constraints << {:type=>:unique, :columns=>h[:columns]}
|
|
432
447
|
end
|
|
433
448
|
end
|
|
@@ -558,10 +573,10 @@ module Sequel
|
|
|
558
573
|
EXTRACT_MAP = {:year=>"'%Y'", :month=>"'%m'", :day=>"'%d'", :hour=>"'%H'", :minute=>"'%M'", :second=>"'%f'"}.freeze
|
|
559
574
|
EXTRACT_MAP.each_value(&:freeze)
|
|
560
575
|
|
|
561
|
-
Dataset.def_sql_method(self, :delete, [['if db.sqlite_version >= 30803', %w'with delete from where'], ["else", %w'delete from where']])
|
|
562
|
-
Dataset.def_sql_method(self, :insert, [['if db.sqlite_version >= 30803', %w'with insert conflict into columns values on_conflict'], ["else", %w'insert conflict into columns values']])
|
|
576
|
+
Dataset.def_sql_method(self, :delete, [['if db.sqlite_version >= 33500', %w'with delete from where returning'], ['elsif db.sqlite_version >= 30803', %w'with delete from where'], ["else", %w'delete from where']])
|
|
577
|
+
Dataset.def_sql_method(self, :insert, [['if db.sqlite_version >= 33500', %w'with insert conflict into columns values on_conflict returning'], ['elsif db.sqlite_version >= 30803', %w'with insert conflict into columns values on_conflict'], ["else", %w'insert conflict into columns values']])
|
|
563
578
|
Dataset.def_sql_method(self, :select, [['if opts[:values]', %w'with values compounds'], ['else', %w'with select distinct columns from join where group having window compounds order limit lock']])
|
|
564
|
-
Dataset.def_sql_method(self, :update, [['if db.sqlite_version >= 30803', %w'with update table set where'], ["else", %w'update table set where']])
|
|
579
|
+
Dataset.def_sql_method(self, :update, [['if db.sqlite_version >= 33500', %w'with update table set from where returning'], ['elsif db.sqlite_version >= 33300', %w'with update table set from where'], ['elsif db.sqlite_version >= 30803', %w'with update table set where'], ["else", %w'update table set where']])
|
|
565
580
|
|
|
566
581
|
def cast_sql_append(sql, expr, type)
|
|
567
582
|
if type == Time or type == DateTime
|
|
@@ -635,8 +650,8 @@ module Sequel
|
|
|
635
650
|
# SQLite performs a TRUNCATE style DELETE if no filter is specified.
|
|
636
651
|
# Since we want to always return the count of records, add a condition
|
|
637
652
|
# that is always true and then delete.
|
|
638
|
-
def delete
|
|
639
|
-
@opts[:where] ? super : where(1=>1).delete
|
|
653
|
+
def delete(&block)
|
|
654
|
+
@opts[:where] ? super : where(1=>1).delete(&block)
|
|
640
655
|
end
|
|
641
656
|
|
|
642
657
|
# Return an array of strings specifying a query explanation for a SELECT of the
|
|
@@ -653,10 +668,25 @@ module Sequel
|
|
|
653
668
|
|
|
654
669
|
# HAVING requires GROUP BY on SQLite
|
|
655
670
|
def having(*cond)
|
|
656
|
-
raise(InvalidOperation, "Can only specify a HAVING clause on a grouped dataset")
|
|
671
|
+
raise(InvalidOperation, "Can only specify a HAVING clause on a grouped dataset") if !@opts[:group] && db.sqlite_version < 33900
|
|
657
672
|
super
|
|
658
673
|
end
|
|
659
674
|
|
|
675
|
+
# Support insert select for associations, so that the model code can use
|
|
676
|
+
# returning instead of a separate query.
|
|
677
|
+
def insert_select(*values)
|
|
678
|
+
return unless supports_insert_select?
|
|
679
|
+
# Handle case where query does not return a row
|
|
680
|
+
server?(:default).with_sql_first(insert_select_sql(*values)) || false
|
|
681
|
+
end
|
|
682
|
+
|
|
683
|
+
# The SQL to use for an insert_select, adds a RETURNING clause to the insert
|
|
684
|
+
# unless the RETURNING clause is already present.
|
|
685
|
+
def insert_select_sql(*values)
|
|
686
|
+
ds = opts[:returning] ? self : returning
|
|
687
|
+
ds.insert_sql(*values)
|
|
688
|
+
end
|
|
689
|
+
|
|
660
690
|
# SQLite uses the nonstandard ` (backtick) for quoting identifiers.
|
|
661
691
|
def quoted_identifier_append(sql, c)
|
|
662
692
|
sql << '`' << c.to_s.gsub('`', '``') << '`'
|
|
@@ -738,6 +768,13 @@ module Sequel
|
|
|
738
768
|
insert_conflict(:ignore)
|
|
739
769
|
end
|
|
740
770
|
|
|
771
|
+
# Automatically add aliases to RETURNING values to work around SQLite bug.
|
|
772
|
+
def returning(*values)
|
|
773
|
+
return super if values.empty?
|
|
774
|
+
raise Error, "RETURNING is not supported on #{db.database_type}" unless supports_returning?(:insert)
|
|
775
|
+
clone(:returning=>_returning_values(values).freeze)
|
|
776
|
+
end
|
|
777
|
+
|
|
741
778
|
# SQLite 3.8.3+ supports common table expressions.
|
|
742
779
|
def supports_cte?(type=:select)
|
|
743
780
|
db.sqlite_version >= 30803
|
|
@@ -753,6 +790,11 @@ module Sequel
|
|
|
753
790
|
false
|
|
754
791
|
end
|
|
755
792
|
|
|
793
|
+
# SQLite does not support deleting from a joined dataset
|
|
794
|
+
def supports_deleting_joins?
|
|
795
|
+
false
|
|
796
|
+
end
|
|
797
|
+
|
|
756
798
|
# SQLite does not support INTERSECT ALL or EXCEPT ALL
|
|
757
799
|
def supports_intersect_except_all?
|
|
758
800
|
false
|
|
@@ -763,11 +805,21 @@ module Sequel
|
|
|
763
805
|
false
|
|
764
806
|
end
|
|
765
807
|
|
|
808
|
+
# SQLite 3.33.0 supports modifying joined datasets
|
|
809
|
+
def supports_modifying_joins?
|
|
810
|
+
db.sqlite_version >= 33300
|
|
811
|
+
end
|
|
812
|
+
|
|
766
813
|
# SQLite does not support multiple columns for the IN/NOT IN operators
|
|
767
814
|
def supports_multiple_column_in?
|
|
768
815
|
false
|
|
769
816
|
end
|
|
770
817
|
|
|
818
|
+
# SQLite 3.35.0 supports RETURNING on INSERT/UPDATE/DELETE.
|
|
819
|
+
def supports_returning?(_)
|
|
820
|
+
db.sqlite_version >= 33500
|
|
821
|
+
end
|
|
822
|
+
|
|
771
823
|
# SQLite supports timezones in literal timestamps, since it stores them
|
|
772
824
|
# as text. But using timezones in timestamps breaks SQLite datetime
|
|
773
825
|
# functions, so we allow the user to override the default per database.
|
|
@@ -800,6 +852,21 @@ module Sequel
|
|
|
800
852
|
|
|
801
853
|
private
|
|
802
854
|
|
|
855
|
+
# Add aliases to symbols and identifiers to work around SQLite bug.
|
|
856
|
+
def _returning_values(values)
|
|
857
|
+
values.map do |v|
|
|
858
|
+
case v
|
|
859
|
+
when Symbol
|
|
860
|
+
_, c, a = split_symbol(v)
|
|
861
|
+
a ? v : Sequel.as(v, c)
|
|
862
|
+
when SQL::Identifier, SQL::QualifiedIdentifier
|
|
863
|
+
Sequel.as(v, unqualified_column_for(v))
|
|
864
|
+
else
|
|
865
|
+
v
|
|
866
|
+
end
|
|
867
|
+
end
|
|
868
|
+
end
|
|
869
|
+
|
|
803
870
|
# SQLite uses string literals instead of identifiers in AS clauses.
|
|
804
871
|
def as_sql_append(sql, aliaz, column_aliases=nil)
|
|
805
872
|
raise Error, "sqlite does not support derived column lists" if column_aliases
|
|
@@ -825,6 +892,13 @@ module Sequel
|
|
|
825
892
|
end
|
|
826
893
|
end
|
|
827
894
|
|
|
895
|
+
# Raise an InvalidOperation exception if insert is not allowed for this dataset.
|
|
896
|
+
def check_insert_allowed!
|
|
897
|
+
raise(InvalidOperation, "Grouped datasets cannot be modified") if opts[:group]
|
|
898
|
+
raise(InvalidOperation, "Joined datasets cannot be modified") if joined_dataset?
|
|
899
|
+
end
|
|
900
|
+
alias check_delete_allowed! check_insert_allowed!
|
|
901
|
+
|
|
828
902
|
# SQLite supports a maximum of 500 rows in a VALUES clause.
|
|
829
903
|
def default_import_slice
|
|
830
904
|
500
|
|
@@ -944,6 +1018,23 @@ module Sequel
|
|
|
944
1018
|
def _truncate_sql(table)
|
|
945
1019
|
"DELETE FROM #{table}"
|
|
946
1020
|
end
|
|
1021
|
+
|
|
1022
|
+
# Use FROM to specify additional tables in an update query
|
|
1023
|
+
def update_from_sql(sql)
|
|
1024
|
+
if(from = @opts[:from][1..-1]).empty?
|
|
1025
|
+
raise(Error, 'Need multiple FROM tables if updating/deleting a dataset with JOINs') if @opts[:join]
|
|
1026
|
+
else
|
|
1027
|
+
sql << ' FROM '
|
|
1028
|
+
source_list_append(sql, from)
|
|
1029
|
+
select_join_sql(sql)
|
|
1030
|
+
end
|
|
1031
|
+
end
|
|
1032
|
+
|
|
1033
|
+
# Only include the primary table in the main update clause
|
|
1034
|
+
def update_table_sql(sql)
|
|
1035
|
+
sql << ' '
|
|
1036
|
+
source_list_append(sql, @opts[:from][0..0])
|
|
1037
|
+
end
|
|
947
1038
|
end
|
|
948
1039
|
end
|
|
949
1040
|
end
|
|
@@ -98,6 +98,11 @@ module Sequel
|
|
|
98
98
|
# The conversion procs to use for this database
|
|
99
99
|
attr_reader :conversion_procs
|
|
100
100
|
|
|
101
|
+
def initialize(opts = OPTS)
|
|
102
|
+
super
|
|
103
|
+
@allow_regexp = typecast_value_boolean(opts[:setup_regexp_function])
|
|
104
|
+
end
|
|
105
|
+
|
|
101
106
|
# Connect to the database. Since SQLite is a file based database,
|
|
102
107
|
# available options are limited:
|
|
103
108
|
#
|
|
@@ -119,6 +124,12 @@ module Sequel
|
|
|
119
124
|
end
|
|
120
125
|
|
|
121
126
|
connection_pragmas.each{|s| log_connection_yield(s, db){db.execute_batch(s)}}
|
|
127
|
+
|
|
128
|
+
if typecast_value_boolean(opts[:setup_regexp_function])
|
|
129
|
+
db.create_function("regexp", 2) do |func, regexp_str, string|
|
|
130
|
+
func.result = Regexp.new(regexp_str).match(string) ? 1 : 0
|
|
131
|
+
end
|
|
132
|
+
end
|
|
122
133
|
|
|
123
134
|
class << db
|
|
124
135
|
attr_reader :prepared_statements
|
|
@@ -128,6 +139,12 @@ module Sequel
|
|
|
128
139
|
db
|
|
129
140
|
end
|
|
130
141
|
|
|
142
|
+
# Whether this Database instance is setup to allow regexp matching.
|
|
143
|
+
# True if the :setup_regexp_function option was passed when creating the Database.
|
|
144
|
+
def allow_regexp?
|
|
145
|
+
@allow_regexp
|
|
146
|
+
end
|
|
147
|
+
|
|
131
148
|
# Disconnect given connections from the database.
|
|
132
149
|
def disconnect_connection(c)
|
|
133
150
|
c.prepared_statements.each_value{|v| v.first.close}
|
|
@@ -189,26 +206,24 @@ module Sequel
|
|
|
189
206
|
# Yield an available connection. Rescue
|
|
190
207
|
# any SQLite3::Exceptions and turn them into DatabaseErrors.
|
|
191
208
|
def _execute(type, sql, opts, &block)
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
conn.changes
|
|
207
|
-
end
|
|
209
|
+
synchronize(opts[:server]) do |conn|
|
|
210
|
+
return execute_prepared_statement(conn, type, sql, opts, &block) if sql.is_a?(Symbol)
|
|
211
|
+
log_args = opts[:arguments]
|
|
212
|
+
args = {}
|
|
213
|
+
opts.fetch(:arguments, OPTS).each{|k, v| args[k] = prepared_statement_argument(v)}
|
|
214
|
+
case type
|
|
215
|
+
when :select
|
|
216
|
+
log_connection_yield(sql, conn, log_args){conn.query(sql, args, &block)}
|
|
217
|
+
when :insert
|
|
218
|
+
log_connection_yield(sql, conn, log_args){conn.execute(sql, args)}
|
|
219
|
+
conn.last_insert_row_id
|
|
220
|
+
when :update
|
|
221
|
+
log_connection_yield(sql, conn, log_args){conn.execute_batch(sql, args)}
|
|
222
|
+
conn.changes
|
|
208
223
|
end
|
|
209
|
-
rescue SQLite3::Exception => e
|
|
210
|
-
raise_error(e)
|
|
211
224
|
end
|
|
225
|
+
rescue SQLite3::Exception => e
|
|
226
|
+
raise_error(e)
|
|
212
227
|
end
|
|
213
228
|
|
|
214
229
|
# The SQLite adapter does not need the pool to convert exceptions.
|
|
@@ -323,6 +338,28 @@ module Sequel
|
|
|
323
338
|
BindArgumentMethods = prepared_statements_module(:bind, ArgumentMapper)
|
|
324
339
|
PreparedStatementMethods = prepared_statements_module(:prepare, BindArgumentMethods)
|
|
325
340
|
|
|
341
|
+
# Support regexp functions if using :setup_regexp_function Database option.
|
|
342
|
+
def complex_expression_sql_append(sql, op, args)
|
|
343
|
+
case op
|
|
344
|
+
when :~, :'!~', :'~*', :'!~*'
|
|
345
|
+
return super unless supports_regexp?
|
|
346
|
+
|
|
347
|
+
case_insensitive = [:'~*', :'!~*'].include?(op)
|
|
348
|
+
sql << 'NOT ' if [:'!~', :'!~*'].include?(op)
|
|
349
|
+
sql << '('
|
|
350
|
+
sql << 'LOWER(' if case_insensitive
|
|
351
|
+
literal_append(sql, args[0])
|
|
352
|
+
sql << ')' if case_insensitive
|
|
353
|
+
sql << ' REGEXP '
|
|
354
|
+
sql << 'LOWER(' if case_insensitive
|
|
355
|
+
literal_append(sql, args[1])
|
|
356
|
+
sql << ')' if case_insensitive
|
|
357
|
+
sql << ')'
|
|
358
|
+
else
|
|
359
|
+
super
|
|
360
|
+
end
|
|
361
|
+
end
|
|
362
|
+
|
|
326
363
|
def fetch_rows(sql)
|
|
327
364
|
execute(sql) do |result|
|
|
328
365
|
cps = db.conversion_procs
|
|
@@ -346,6 +383,11 @@ module Sequel
|
|
|
346
383
|
end
|
|
347
384
|
end
|
|
348
385
|
end
|
|
386
|
+
|
|
387
|
+
# Support regexp if using :setup_regexp_function Database option.
|
|
388
|
+
def supports_regexp?
|
|
389
|
+
db.allow_regexp?
|
|
390
|
+
end
|
|
349
391
|
|
|
350
392
|
private
|
|
351
393
|
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
module Sequel
|
|
4
|
+
class Dataset
|
|
5
|
+
module ColumnsLimit1
|
|
6
|
+
COLUMNS_CLONE_OPTIONS = {:distinct => nil, :limit => 1, :offset=>nil, :where=>nil, :having=>nil, :order=>nil, :row_proc=>nil, :graph=>nil, :eager_graph=>nil}.freeze
|
|
7
|
+
|
|
8
|
+
# Use a limit of 1 instead of a limit of 0 when
|
|
9
|
+
# getting the columns.
|
|
10
|
+
def columns!
|
|
11
|
+
ds = clone(COLUMNS_CLONE_OPTIONS)
|
|
12
|
+
ds.each{break}
|
|
13
|
+
|
|
14
|
+
if cols = ds.cache[:_columns]
|
|
15
|
+
self.columns = cols
|
|
16
|
+
else
|
|
17
|
+
[]
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -34,7 +34,7 @@ module Sequel
|
|
|
34
34
|
def execute(sql, opts=OPTS, &block)
|
|
35
35
|
if opts[:sproc]
|
|
36
36
|
call_sproc(sql, opts, &block)
|
|
37
|
-
elsif sql.is_a?(Symbol)
|
|
37
|
+
elsif sql.is_a?(Symbol) || sql.is_a?(Sequel::Dataset::ArgumentMapper)
|
|
38
38
|
execute_prepared_statement(sql, opts, &block)
|
|
39
39
|
else
|
|
40
40
|
synchronize(opts[:server]){|conn| _execute(conn, sql, opts, &block)}
|
|
@@ -80,6 +80,12 @@ module Sequel
|
|
|
80
80
|
SQL::DelayedEvaluation.new(lambda{|ds| v(o.call(ds))})
|
|
81
81
|
when SQL::Wrapper
|
|
82
82
|
SQL::Wrapper.new(v(o.value))
|
|
83
|
+
when SQL::Expression
|
|
84
|
+
if o.respond_to?(:sequel_ast_transform)
|
|
85
|
+
o.sequel_ast_transform(method(:v))
|
|
86
|
+
else
|
|
87
|
+
o
|
|
88
|
+
end
|
|
83
89
|
else
|
|
84
90
|
o
|
|
85
91
|
end
|
|
@@ -55,13 +55,11 @@ class Sequel::ShardedSingleConnectionPool < Sequel::ConnectionPool
|
|
|
55
55
|
# Yields the connection to the supplied block for the given server.
|
|
56
56
|
# This method simulates the ConnectionPool#hold API.
|
|
57
57
|
def hold(server=:default)
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
raise
|
|
64
|
-
end
|
|
58
|
+
server = pick_server(server)
|
|
59
|
+
yield(@conns[server] ||= make_new(server))
|
|
60
|
+
rescue Sequel::DatabaseDisconnectError, *@error_classes => e
|
|
61
|
+
disconnect_server(server) if disconnect_error?(e)
|
|
62
|
+
raise
|
|
65
63
|
end
|
|
66
64
|
|
|
67
65
|
# The ShardedSingleConnectionPool always has a maximum size of 1.
|
|
@@ -22,6 +22,8 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
|
|
|
22
22
|
@connections_to_disconnect = []
|
|
23
23
|
@servers = opts.fetch(:servers_hash, Hash.new(:default))
|
|
24
24
|
remove_instance_variable(:@waiter)
|
|
25
|
+
remove_instance_variable(:@allocated)
|
|
26
|
+
@allocated = {}
|
|
25
27
|
@waiters = {}
|
|
26
28
|
|
|
27
29
|
add_servers([:default])
|
|
@@ -36,7 +38,9 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
|
|
|
36
38
|
unless @servers.has_key?(server)
|
|
37
39
|
@servers[server] = server
|
|
38
40
|
@available_connections[server] = []
|
|
39
|
-
|
|
41
|
+
allocated = {}
|
|
42
|
+
allocated.compare_by_identity
|
|
43
|
+
@allocated[server] = allocated
|
|
40
44
|
@waiters[server] = ConditionVariable.new
|
|
41
45
|
end
|
|
42
46
|
end
|
|
@@ -24,15 +24,13 @@ class Sequel::SingleConnectionPool < Sequel::ConnectionPool
|
|
|
24
24
|
|
|
25
25
|
# Yield the connection to the block.
|
|
26
26
|
def hold(server=nil)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
@conn.replace([c = make_new(:default)])
|
|
30
|
-
end
|
|
31
|
-
yield c
|
|
32
|
-
rescue Sequel::DatabaseDisconnectError, *@error_classes => e
|
|
33
|
-
disconnect if disconnect_error?(e)
|
|
34
|
-
raise
|
|
27
|
+
unless c = @conn.first
|
|
28
|
+
@conn.replace([c = make_new(:default)])
|
|
35
29
|
end
|
|
30
|
+
yield c
|
|
31
|
+
rescue Sequel::DatabaseDisconnectError, *@error_classes => e
|
|
32
|
+
disconnect if disconnect_error?(e)
|
|
33
|
+
raise
|
|
36
34
|
end
|
|
37
35
|
|
|
38
36
|
# The SingleConnectionPool always has a maximum size of 1.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
# A connection pool allowing multi-threaded access to a pool of connections.
|
|
4
4
|
# This is the default connection pool used by Sequel.
|
|
5
5
|
class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
|
|
6
|
-
USE_WAITER = true
|
|
6
|
+
USE_WAITER = true # SEQUEL6: Remove
|
|
7
7
|
Sequel::Deprecation.deprecate_constant(self, :USE_WAITER)
|
|
8
8
|
|
|
9
9
|
# The maximum number of connections this pool will create (per shard/server
|
|
@@ -12,17 +12,17 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
|
|
|
12
12
|
|
|
13
13
|
# An array of connections that are available for use by the pool.
|
|
14
14
|
# The calling code should already have the mutex before calling this.
|
|
15
|
-
attr_reader :available_connections
|
|
15
|
+
attr_reader :available_connections # SEQUEL6: Remove
|
|
16
16
|
|
|
17
|
-
# A hash with thread keys and connection values for currently allocated connections.
|
|
17
|
+
# A hash with thread/fiber keys and connection values for currently allocated connections.
|
|
18
18
|
# The calling code should already have the mutex before calling this.
|
|
19
|
-
attr_reader :allocated
|
|
19
|
+
attr_reader :allocated # SEQUEL6: Remove
|
|
20
20
|
|
|
21
21
|
# The following additional options are respected:
|
|
22
22
|
# :max_connections :: The maximum number of connections the connection pool
|
|
23
23
|
# will open (default 4)
|
|
24
24
|
# :pool_timeout :: The amount of seconds to wait to acquire a connection
|
|
25
|
-
# before raising a
|
|
25
|
+
# before raising a PoolTimeout error (default 5)
|
|
26
26
|
def initialize(db, opts = OPTS)
|
|
27
27
|
super
|
|
28
28
|
@max_size = Integer(opts[:max_connections] || 4)
|
|
@@ -31,6 +31,7 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
|
|
|
31
31
|
@connection_handling = opts[:connection_handling]
|
|
32
32
|
@available_connections = []
|
|
33
33
|
@allocated = {}
|
|
34
|
+
@allocated.compare_by_identity
|
|
34
35
|
@timeout = Float(opts[:pool_timeout] || 5)
|
|
35
36
|
@waiter = ConditionVariable.new
|
|
36
37
|
end
|
|
@@ -49,8 +50,7 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
|
|
|
49
50
|
end
|
|
50
51
|
end
|
|
51
52
|
|
|
52
|
-
# Removes all connections currently available
|
|
53
|
-
# yielding each connection to the given block. This method has the effect of
|
|
53
|
+
# Removes all connections currently available. This method has the effect of
|
|
54
54
|
# disconnecting from the database, assuming that no connections are currently
|
|
55
55
|
# being used. If you want to be able to disconnect connections that are
|
|
56
56
|
# currently in use, use the ShardedThreadedConnectionPool, which can do that.
|
|
@@ -134,7 +134,7 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
|
|
|
134
134
|
# calling this.
|
|
135
135
|
#
|
|
136
136
|
# This should return a connection is one is available within the timeout,
|
|
137
|
-
# or
|
|
137
|
+
# or raise PoolTimeout if a connection could not be acquired within the timeout.
|
|
138
138
|
def acquire(thread)
|
|
139
139
|
if conn = assign_connection(thread)
|
|
140
140
|
return conn
|