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.
Files changed (187) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +308 -0
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +57 -25
  5. data/bin/sequel +11 -3
  6. data/doc/advanced_associations.rdoc +13 -13
  7. data/doc/association_basics.rdoc +89 -24
  8. data/doc/cheat_sheet.rdoc +11 -3
  9. data/doc/migration.rdoc +12 -6
  10. data/doc/model_hooks.rdoc +1 -1
  11. data/doc/object_model.rdoc +8 -8
  12. data/doc/opening_databases.rdoc +18 -11
  13. data/doc/postgresql.rdoc +16 -8
  14. data/doc/querying.rdoc +5 -3
  15. data/doc/release_notes/5.40.0.txt +40 -0
  16. data/doc/release_notes/5.41.0.txt +25 -0
  17. data/doc/release_notes/5.42.0.txt +136 -0
  18. data/doc/release_notes/5.43.0.txt +98 -0
  19. data/doc/release_notes/5.44.0.txt +32 -0
  20. data/doc/release_notes/5.45.0.txt +34 -0
  21. data/doc/release_notes/5.46.0.txt +87 -0
  22. data/doc/release_notes/5.47.0.txt +59 -0
  23. data/doc/release_notes/5.48.0.txt +14 -0
  24. data/doc/release_notes/5.49.0.txt +59 -0
  25. data/doc/release_notes/5.50.0.txt +78 -0
  26. data/doc/release_notes/5.51.0.txt +47 -0
  27. data/doc/release_notes/5.52.0.txt +87 -0
  28. data/doc/release_notes/5.53.0.txt +23 -0
  29. data/doc/release_notes/5.54.0.txt +27 -0
  30. data/doc/release_notes/5.55.0.txt +21 -0
  31. data/doc/release_notes/5.56.0.txt +51 -0
  32. data/doc/release_notes/5.57.0.txt +23 -0
  33. data/doc/release_notes/5.58.0.txt +31 -0
  34. data/doc/release_notes/5.59.0.txt +73 -0
  35. data/doc/release_notes/5.60.0.txt +22 -0
  36. data/doc/release_notes/5.61.0.txt +43 -0
  37. data/doc/release_notes/5.62.0.txt +132 -0
  38. data/doc/release_notes/5.63.0.txt +33 -0
  39. data/doc/schema_modification.rdoc +1 -1
  40. data/doc/security.rdoc +9 -9
  41. data/doc/sql.rdoc +27 -15
  42. data/doc/testing.rdoc +22 -11
  43. data/doc/transactions.rdoc +6 -6
  44. data/doc/virtual_rows.rdoc +2 -2
  45. data/lib/sequel/adapters/ado/access.rb +1 -1
  46. data/lib/sequel/adapters/ado.rb +17 -17
  47. data/lib/sequel/adapters/amalgalite.rb +3 -5
  48. data/lib/sequel/adapters/ibmdb.rb +2 -2
  49. data/lib/sequel/adapters/jdbc/derby.rb +8 -0
  50. data/lib/sequel/adapters/jdbc/h2.rb +60 -10
  51. data/lib/sequel/adapters/jdbc/hsqldb.rb +6 -0
  52. data/lib/sequel/adapters/jdbc/postgresql.rb +4 -4
  53. data/lib/sequel/adapters/jdbc.rb +16 -18
  54. data/lib/sequel/adapters/mysql.rb +80 -67
  55. data/lib/sequel/adapters/mysql2.rb +54 -49
  56. data/lib/sequel/adapters/odbc.rb +6 -2
  57. data/lib/sequel/adapters/oracle.rb +3 -3
  58. data/lib/sequel/adapters/postgres.rb +83 -40
  59. data/lib/sequel/adapters/shared/access.rb +11 -1
  60. data/lib/sequel/adapters/shared/db2.rb +30 -0
  61. data/lib/sequel/adapters/shared/mssql.rb +58 -7
  62. data/lib/sequel/adapters/shared/mysql.rb +40 -2
  63. data/lib/sequel/adapters/shared/oracle.rb +76 -0
  64. data/lib/sequel/adapters/shared/postgres.rb +418 -174
  65. data/lib/sequel/adapters/shared/sqlanywhere.rb +10 -0
  66. data/lib/sequel/adapters/shared/sqlite.rb +102 -11
  67. data/lib/sequel/adapters/sqlanywhere.rb +1 -1
  68. data/lib/sequel/adapters/sqlite.rb +60 -18
  69. data/lib/sequel/adapters/tinytds.rb +1 -1
  70. data/lib/sequel/adapters/utils/columns_limit_1.rb +22 -0
  71. data/lib/sequel/adapters/utils/mysql_mysql2.rb +1 -1
  72. data/lib/sequel/ast_transformer.rb +6 -0
  73. data/lib/sequel/connection_pool/sharded_single.rb +5 -7
  74. data/lib/sequel/connection_pool/sharded_threaded.rb +5 -1
  75. data/lib/sequel/connection_pool/single.rb +6 -8
  76. data/lib/sequel/connection_pool/threaded.rb +8 -8
  77. data/lib/sequel/connection_pool/timed_queue.rb +257 -0
  78. data/lib/sequel/connection_pool.rb +47 -30
  79. data/lib/sequel/core.rb +28 -18
  80. data/lib/sequel/database/connecting.rb +26 -2
  81. data/lib/sequel/database/misc.rb +69 -14
  82. data/lib/sequel/database/query.rb +38 -1
  83. data/lib/sequel/database/schema_generator.rb +45 -52
  84. data/lib/sequel/database/schema_methods.rb +17 -1
  85. data/lib/sequel/dataset/actions.rb +107 -13
  86. data/lib/sequel/dataset/features.rb +20 -0
  87. data/lib/sequel/dataset/misc.rb +1 -1
  88. data/lib/sequel/dataset/prepared_statements.rb +2 -0
  89. data/lib/sequel/dataset/query.rb +118 -16
  90. data/lib/sequel/dataset/sql.rb +177 -47
  91. data/lib/sequel/extensions/_model_pg_row.rb +0 -12
  92. data/lib/sequel/extensions/_pretty_table.rb +1 -1
  93. data/lib/sequel/extensions/any_not_empty.rb +1 -1
  94. data/lib/sequel/extensions/async_thread_pool.rb +438 -0
  95. data/lib/sequel/extensions/auto_literal_strings.rb +1 -1
  96. data/lib/sequel/extensions/blank.rb +8 -0
  97. data/lib/sequel/extensions/constraint_validations.rb +1 -1
  98. data/lib/sequel/extensions/core_refinements.rb +36 -11
  99. data/lib/sequel/extensions/date_arithmetic.rb +71 -31
  100. data/lib/sequel/extensions/date_parse_input_handler.rb +67 -0
  101. data/lib/sequel/extensions/datetime_parse_to_time.rb +5 -1
  102. data/lib/sequel/extensions/duplicate_columns_handler.rb +1 -1
  103. data/lib/sequel/extensions/eval_inspect.rb +2 -0
  104. data/lib/sequel/extensions/inflector.rb +9 -1
  105. data/lib/sequel/extensions/is_distinct_from.rb +141 -0
  106. data/lib/sequel/extensions/looser_typecasting.rb +3 -0
  107. data/lib/sequel/extensions/migration.rb +7 -2
  108. data/lib/sequel/extensions/named_timezones.rb +26 -6
  109. data/lib/sequel/extensions/pagination.rb +1 -1
  110. data/lib/sequel/extensions/pg_array.rb +23 -3
  111. data/lib/sequel/extensions/pg_array_ops.rb +2 -2
  112. data/lib/sequel/extensions/pg_auto_parameterize.rb +478 -0
  113. data/lib/sequel/extensions/pg_enum.rb +1 -1
  114. data/lib/sequel/extensions/pg_extended_date_support.rb +28 -25
  115. data/lib/sequel/extensions/pg_extended_integer_support.rb +116 -0
  116. data/lib/sequel/extensions/pg_hstore.rb +6 -1
  117. data/lib/sequel/extensions/pg_hstore_ops.rb +53 -3
  118. data/lib/sequel/extensions/pg_inet.rb +10 -11
  119. data/lib/sequel/extensions/pg_inet_ops.rb +1 -1
  120. data/lib/sequel/extensions/pg_interval.rb +45 -19
  121. data/lib/sequel/extensions/pg_json.rb +13 -15
  122. data/lib/sequel/extensions/pg_json_ops.rb +73 -2
  123. data/lib/sequel/extensions/pg_loose_count.rb +3 -1
  124. data/lib/sequel/extensions/pg_multirange.rb +367 -0
  125. data/lib/sequel/extensions/pg_range.rb +10 -23
  126. data/lib/sequel/extensions/pg_range_ops.rb +37 -9
  127. data/lib/sequel/extensions/pg_row.rb +19 -13
  128. data/lib/sequel/extensions/pg_row_ops.rb +1 -1
  129. data/lib/sequel/extensions/query.rb +2 -0
  130. data/lib/sequel/extensions/s.rb +2 -1
  131. data/lib/sequel/extensions/schema_dumper.rb +13 -2
  132. data/lib/sequel/extensions/server_block.rb +8 -12
  133. data/lib/sequel/extensions/sql_comments.rb +110 -3
  134. data/lib/sequel/extensions/sql_log_normalizer.rb +108 -0
  135. data/lib/sequel/extensions/sqlite_json_ops.rb +255 -0
  136. data/lib/sequel/extensions/string_agg.rb +1 -1
  137. data/lib/sequel/extensions/string_date_time.rb +19 -23
  138. data/lib/sequel/extensions/symbol_aref.rb +2 -0
  139. data/lib/sequel/model/associations.rb +325 -96
  140. data/lib/sequel/model/base.rb +51 -27
  141. data/lib/sequel/model/errors.rb +10 -1
  142. data/lib/sequel/model/inflections.rb +1 -1
  143. data/lib/sequel/model/plugins.rb +5 -0
  144. data/lib/sequel/plugins/association_proxies.rb +2 -0
  145. data/lib/sequel/plugins/async_thread_pool.rb +39 -0
  146. data/lib/sequel/plugins/auto_restrict_eager_graph.rb +62 -0
  147. data/lib/sequel/plugins/auto_validations.rb +87 -15
  148. data/lib/sequel/plugins/auto_validations_constraint_validations_presence_message.rb +68 -0
  149. data/lib/sequel/plugins/class_table_inheritance.rb +2 -2
  150. data/lib/sequel/plugins/column_encryption.rb +728 -0
  151. data/lib/sequel/plugins/composition.rb +10 -4
  152. data/lib/sequel/plugins/concurrent_eager_loading.rb +174 -0
  153. data/lib/sequel/plugins/constraint_validations.rb +2 -1
  154. data/lib/sequel/plugins/dataset_associations.rb +4 -1
  155. data/lib/sequel/plugins/dirty.rb +1 -1
  156. data/lib/sequel/plugins/enum.rb +124 -0
  157. data/lib/sequel/plugins/finder.rb +3 -1
  158. data/lib/sequel/plugins/insert_conflict.rb +4 -0
  159. data/lib/sequel/plugins/instance_specific_default.rb +1 -1
  160. data/lib/sequel/plugins/json_serializer.rb +39 -24
  161. data/lib/sequel/plugins/lazy_attributes.rb +3 -0
  162. data/lib/sequel/plugins/list.rb +3 -1
  163. data/lib/sequel/plugins/many_through_many.rb +108 -9
  164. data/lib/sequel/plugins/nested_attributes.rb +12 -7
  165. data/lib/sequel/plugins/pg_array_associations.rb +56 -38
  166. data/lib/sequel/plugins/pg_auto_constraint_validations.rb +3 -1
  167. data/lib/sequel/plugins/prepared_statements.rb +10 -1
  168. data/lib/sequel/plugins/primary_key_lookup_check_values.rb +154 -0
  169. data/lib/sequel/plugins/rcte_tree.rb +27 -19
  170. data/lib/sequel/plugins/require_valid_schema.rb +67 -0
  171. data/lib/sequel/plugins/serialization.rb +9 -3
  172. data/lib/sequel/plugins/serialization_modification_detection.rb +2 -1
  173. data/lib/sequel/plugins/single_table_inheritance.rb +8 -0
  174. data/lib/sequel/plugins/sql_comments.rb +189 -0
  175. data/lib/sequel/plugins/static_cache.rb +1 -1
  176. data/lib/sequel/plugins/subclasses.rb +28 -11
  177. data/lib/sequel/plugins/tactical_eager_loading.rb +23 -10
  178. data/lib/sequel/plugins/timestamps.rb +1 -1
  179. data/lib/sequel/plugins/unused_associations.rb +521 -0
  180. data/lib/sequel/plugins/update_or_create.rb +1 -1
  181. data/lib/sequel/plugins/validate_associated.rb +22 -12
  182. data/lib/sequel/plugins/validation_helpers.rb +38 -11
  183. data/lib/sequel/plugins/xml_serializer.rb +1 -1
  184. data/lib/sequel/sql.rb +1 -1
  185. data/lib/sequel/timezones.rb +12 -14
  186. data/lib/sequel/version.rb +1 -1
  187. 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
- ocp = lambda{|oc| oc.delete_if{|c| c.to_s == op[:name].to_s}}
243
- duplicate_table(table, :old_columns_proc=>ocp){|columns| columns.delete_if{|s| s[:name].to_s == op[:name].to_s}}
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 block_given?
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 && !opts[:no_unique]
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") unless @opts[:group]
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
@@ -120,7 +120,7 @@ module Sequel
120
120
 
121
121
  case type
122
122
  when :select
123
- yield rs if block_given?
123
+ yield rs if defined?(yield)
124
124
  when :rows
125
125
  return @api.sqlany_affected_rows(rs)
126
126
  when :insert
@@ -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
- begin
193
- synchronize(opts[:server]) do |conn|
194
- return execute_prepared_statement(conn, type, sql, opts, &block) if sql.is_a?(Symbol)
195
- log_args = opts[:arguments]
196
- args = {}
197
- opts.fetch(:arguments, OPTS).each{|k, v| args[k] = prepared_statement_argument(v)}
198
- case type
199
- when :select
200
- log_connection_yield(sql, conn, log_args){conn.query(sql, args, &block)}
201
- when :insert
202
- log_connection_yield(sql, conn, log_args){conn.execute(sql, args)}
203
- conn.last_insert_row_id
204
- when :update
205
- log_connection_yield(sql, conn, log_args){conn.execute_batch(sql, args)}
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
 
@@ -75,7 +75,7 @@ module Sequel
75
75
  return r.public_send(m) if m
76
76
  end
77
77
  end
78
- yield(r) if block_given?
78
+ yield(r) if defined?(yield)
79
79
  rescue TinyTds::Error => e
80
80
  raise_error(e, :disconnect=>!c.active?)
81
81
  ensure
@@ -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
- begin
59
- server = pick_server(server)
60
- yield(@conns[server] ||= make_new(server))
61
- rescue Sequel::DatabaseDisconnectError, *@error_classes => e
62
- disconnect_server(server) if disconnect_error?(e)
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
- @allocated[server] = {}
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
- begin
28
- unless c = @conn.first
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 PoolTimeoutError (default 5)
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, optionally
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 nil if a connection could not be acquired within the timeout.
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