sequel 5.45.0 → 5.77.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 (218) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +434 -0
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +59 -27
  5. data/bin/sequel +11 -3
  6. data/doc/advanced_associations.rdoc +16 -14
  7. data/doc/association_basics.rdoc +119 -24
  8. data/doc/cheat_sheet.rdoc +11 -3
  9. data/doc/mass_assignment.rdoc +1 -1
  10. data/doc/migration.rdoc +27 -6
  11. data/doc/model_hooks.rdoc +1 -1
  12. data/doc/object_model.rdoc +8 -8
  13. data/doc/opening_databases.rdoc +28 -12
  14. data/doc/postgresql.rdoc +16 -8
  15. data/doc/querying.rdoc +5 -3
  16. data/doc/release_notes/5.46.0.txt +87 -0
  17. data/doc/release_notes/5.47.0.txt +59 -0
  18. data/doc/release_notes/5.48.0.txt +14 -0
  19. data/doc/release_notes/5.49.0.txt +59 -0
  20. data/doc/release_notes/5.50.0.txt +78 -0
  21. data/doc/release_notes/5.51.0.txt +47 -0
  22. data/doc/release_notes/5.52.0.txt +87 -0
  23. data/doc/release_notes/5.53.0.txt +23 -0
  24. data/doc/release_notes/5.54.0.txt +27 -0
  25. data/doc/release_notes/5.55.0.txt +21 -0
  26. data/doc/release_notes/5.56.0.txt +51 -0
  27. data/doc/release_notes/5.57.0.txt +23 -0
  28. data/doc/release_notes/5.58.0.txt +31 -0
  29. data/doc/release_notes/5.59.0.txt +73 -0
  30. data/doc/release_notes/5.60.0.txt +22 -0
  31. data/doc/release_notes/5.61.0.txt +43 -0
  32. data/doc/release_notes/5.62.0.txt +132 -0
  33. data/doc/release_notes/5.63.0.txt +33 -0
  34. data/doc/release_notes/5.64.0.txt +50 -0
  35. data/doc/release_notes/5.65.0.txt +21 -0
  36. data/doc/release_notes/5.66.0.txt +24 -0
  37. data/doc/release_notes/5.67.0.txt +32 -0
  38. data/doc/release_notes/5.68.0.txt +61 -0
  39. data/doc/release_notes/5.69.0.txt +26 -0
  40. data/doc/release_notes/5.70.0.txt +35 -0
  41. data/doc/release_notes/5.71.0.txt +21 -0
  42. data/doc/release_notes/5.72.0.txt +33 -0
  43. data/doc/release_notes/5.73.0.txt +66 -0
  44. data/doc/release_notes/5.74.0.txt +45 -0
  45. data/doc/release_notes/5.75.0.txt +35 -0
  46. data/doc/release_notes/5.76.0.txt +86 -0
  47. data/doc/release_notes/5.77.0.txt +63 -0
  48. data/doc/schema_modification.rdoc +1 -1
  49. data/doc/security.rdoc +9 -9
  50. data/doc/sharding.rdoc +3 -1
  51. data/doc/sql.rdoc +27 -15
  52. data/doc/testing.rdoc +23 -13
  53. data/doc/transactions.rdoc +6 -6
  54. data/doc/virtual_rows.rdoc +1 -1
  55. data/lib/sequel/adapters/ado/access.rb +1 -1
  56. data/lib/sequel/adapters/ado.rb +1 -1
  57. data/lib/sequel/adapters/amalgalite.rb +3 -5
  58. data/lib/sequel/adapters/ibmdb.rb +3 -3
  59. data/lib/sequel/adapters/jdbc/derby.rb +8 -0
  60. data/lib/sequel/adapters/jdbc/h2.rb +63 -10
  61. data/lib/sequel/adapters/jdbc/hsqldb.rb +8 -0
  62. data/lib/sequel/adapters/jdbc/postgresql.rb +7 -4
  63. data/lib/sequel/adapters/jdbc/sqlanywhere.rb +15 -0
  64. data/lib/sequel/adapters/jdbc/sqlserver.rb +4 -0
  65. data/lib/sequel/adapters/jdbc.rb +24 -22
  66. data/lib/sequel/adapters/mysql.rb +92 -67
  67. data/lib/sequel/adapters/mysql2.rb +56 -51
  68. data/lib/sequel/adapters/odbc/mssql.rb +1 -1
  69. data/lib/sequel/adapters/odbc.rb +1 -1
  70. data/lib/sequel/adapters/oracle.rb +4 -3
  71. data/lib/sequel/adapters/postgres.rb +89 -45
  72. data/lib/sequel/adapters/shared/access.rb +11 -1
  73. data/lib/sequel/adapters/shared/db2.rb +42 -0
  74. data/lib/sequel/adapters/shared/mssql.rb +91 -10
  75. data/lib/sequel/adapters/shared/mysql.rb +78 -3
  76. data/lib/sequel/adapters/shared/oracle.rb +86 -7
  77. data/lib/sequel/adapters/shared/postgres.rb +576 -171
  78. data/lib/sequel/adapters/shared/sqlanywhere.rb +21 -5
  79. data/lib/sequel/adapters/shared/sqlite.rb +92 -8
  80. data/lib/sequel/adapters/sqlanywhere.rb +1 -1
  81. data/lib/sequel/adapters/sqlite.rb +99 -18
  82. data/lib/sequel/adapters/tinytds.rb +1 -1
  83. data/lib/sequel/adapters/trilogy.rb +117 -0
  84. data/lib/sequel/adapters/utils/columns_limit_1.rb +22 -0
  85. data/lib/sequel/adapters/utils/mysql_mysql2.rb +1 -1
  86. data/lib/sequel/ast_transformer.rb +6 -0
  87. data/lib/sequel/connection_pool/sharded_single.rb +5 -7
  88. data/lib/sequel/connection_pool/sharded_threaded.rb +16 -11
  89. data/lib/sequel/connection_pool/sharded_timed_queue.rb +374 -0
  90. data/lib/sequel/connection_pool/single.rb +6 -8
  91. data/lib/sequel/connection_pool/threaded.rb +14 -8
  92. data/lib/sequel/connection_pool/timed_queue.rb +270 -0
  93. data/lib/sequel/connection_pool.rb +57 -31
  94. data/lib/sequel/core.rb +17 -18
  95. data/lib/sequel/database/connecting.rb +27 -3
  96. data/lib/sequel/database/dataset.rb +16 -6
  97. data/lib/sequel/database/misc.rb +70 -14
  98. data/lib/sequel/database/query.rb +73 -2
  99. data/lib/sequel/database/schema_generator.rb +11 -6
  100. data/lib/sequel/database/schema_methods.rb +23 -4
  101. data/lib/sequel/database/transactions.rb +6 -0
  102. data/lib/sequel/dataset/actions.rb +111 -15
  103. data/lib/sequel/dataset/deprecated_singleton_class_methods.rb +42 -0
  104. data/lib/sequel/dataset/features.rb +20 -1
  105. data/lib/sequel/dataset/misc.rb +12 -2
  106. data/lib/sequel/dataset/placeholder_literalizer.rb +20 -9
  107. data/lib/sequel/dataset/query.rb +170 -41
  108. data/lib/sequel/dataset/sql.rb +190 -71
  109. data/lib/sequel/dataset.rb +4 -0
  110. data/lib/sequel/extensions/_model_pg_row.rb +0 -12
  111. data/lib/sequel/extensions/_pretty_table.rb +1 -1
  112. data/lib/sequel/extensions/any_not_empty.rb +2 -2
  113. data/lib/sequel/extensions/async_thread_pool.rb +14 -13
  114. data/lib/sequel/extensions/auto_cast_date_and_time.rb +94 -0
  115. data/lib/sequel/extensions/auto_literal_strings.rb +1 -1
  116. data/lib/sequel/extensions/connection_expiration.rb +15 -9
  117. data/lib/sequel/extensions/connection_validator.rb +16 -11
  118. data/lib/sequel/extensions/constraint_validations.rb +1 -1
  119. data/lib/sequel/extensions/core_refinements.rb +36 -11
  120. data/lib/sequel/extensions/date_arithmetic.rb +36 -8
  121. data/lib/sequel/extensions/date_parse_input_handler.rb +67 -0
  122. data/lib/sequel/extensions/datetime_parse_to_time.rb +5 -1
  123. data/lib/sequel/extensions/duplicate_columns_handler.rb +11 -10
  124. data/lib/sequel/extensions/index_caching.rb +5 -1
  125. data/lib/sequel/extensions/inflector.rb +1 -1
  126. data/lib/sequel/extensions/is_distinct_from.rb +141 -0
  127. data/lib/sequel/extensions/looser_typecasting.rb +3 -0
  128. data/lib/sequel/extensions/migration.rb +57 -15
  129. data/lib/sequel/extensions/named_timezones.rb +22 -6
  130. data/lib/sequel/extensions/pagination.rb +1 -1
  131. data/lib/sequel/extensions/pg_array.rb +33 -4
  132. data/lib/sequel/extensions/pg_array_ops.rb +2 -2
  133. data/lib/sequel/extensions/pg_auto_parameterize.rb +509 -0
  134. data/lib/sequel/extensions/pg_auto_parameterize_in_array.rb +110 -0
  135. data/lib/sequel/extensions/pg_enum.rb +1 -2
  136. data/lib/sequel/extensions/pg_extended_date_support.rb +39 -28
  137. data/lib/sequel/extensions/pg_extended_integer_support.rb +116 -0
  138. data/lib/sequel/extensions/pg_hstore.rb +6 -1
  139. data/lib/sequel/extensions/pg_hstore_ops.rb +53 -3
  140. data/lib/sequel/extensions/pg_inet.rb +10 -11
  141. data/lib/sequel/extensions/pg_inet_ops.rb +1 -1
  142. data/lib/sequel/extensions/pg_interval.rb +11 -11
  143. data/lib/sequel/extensions/pg_json.rb +13 -15
  144. data/lib/sequel/extensions/pg_json_ops.rb +125 -2
  145. data/lib/sequel/extensions/pg_multirange.rb +367 -0
  146. data/lib/sequel/extensions/pg_range.rb +13 -26
  147. data/lib/sequel/extensions/pg_range_ops.rb +37 -9
  148. data/lib/sequel/extensions/pg_row.rb +20 -19
  149. data/lib/sequel/extensions/pg_row_ops.rb +1 -1
  150. data/lib/sequel/extensions/pg_timestamptz.rb +27 -3
  151. data/lib/sequel/extensions/round_timestamps.rb +1 -1
  152. data/lib/sequel/extensions/s.rb +2 -1
  153. data/lib/sequel/extensions/schema_caching.rb +1 -1
  154. data/lib/sequel/extensions/schema_dumper.rb +45 -11
  155. data/lib/sequel/extensions/server_block.rb +10 -13
  156. data/lib/sequel/extensions/set_literalizer.rb +58 -0
  157. data/lib/sequel/extensions/sql_comments.rb +110 -3
  158. data/lib/sequel/extensions/sql_log_normalizer.rb +108 -0
  159. data/lib/sequel/extensions/sqlite_json_ops.rb +255 -0
  160. data/lib/sequel/extensions/string_agg.rb +1 -1
  161. data/lib/sequel/extensions/string_date_time.rb +19 -23
  162. data/lib/sequel/extensions/symbol_aref.rb +2 -0
  163. data/lib/sequel/extensions/transaction_connection_validator.rb +78 -0
  164. data/lib/sequel/model/associations.rb +286 -92
  165. data/lib/sequel/model/base.rb +53 -33
  166. data/lib/sequel/model/dataset_module.rb +3 -0
  167. data/lib/sequel/model/errors.rb +10 -1
  168. data/lib/sequel/model/exceptions.rb +15 -3
  169. data/lib/sequel/model/inflections.rb +1 -1
  170. data/lib/sequel/plugins/auto_restrict_eager_graph.rb +62 -0
  171. data/lib/sequel/plugins/auto_validations.rb +74 -16
  172. data/lib/sequel/plugins/class_table_inheritance.rb +2 -2
  173. data/lib/sequel/plugins/column_encryption.rb +29 -8
  174. data/lib/sequel/plugins/composition.rb +3 -2
  175. data/lib/sequel/plugins/concurrent_eager_loading.rb +4 -4
  176. data/lib/sequel/plugins/constraint_validations.rb +8 -5
  177. data/lib/sequel/plugins/defaults_setter.rb +16 -0
  178. data/lib/sequel/plugins/dirty.rb +1 -1
  179. data/lib/sequel/plugins/enum.rb +124 -0
  180. data/lib/sequel/plugins/finder.rb +4 -2
  181. data/lib/sequel/plugins/insert_conflict.rb +4 -0
  182. data/lib/sequel/plugins/instance_specific_default.rb +1 -1
  183. data/lib/sequel/plugins/json_serializer.rb +2 -2
  184. data/lib/sequel/plugins/lazy_attributes.rb +3 -0
  185. data/lib/sequel/plugins/list.rb +8 -3
  186. data/lib/sequel/plugins/many_through_many.rb +109 -10
  187. data/lib/sequel/plugins/mssql_optimistic_locking.rb +8 -38
  188. data/lib/sequel/plugins/nested_attributes.rb +4 -4
  189. data/lib/sequel/plugins/optimistic_locking.rb +9 -42
  190. data/lib/sequel/plugins/optimistic_locking_base.rb +55 -0
  191. data/lib/sequel/plugins/paged_operations.rb +181 -0
  192. data/lib/sequel/plugins/pg_array_associations.rb +46 -34
  193. data/lib/sequel/plugins/pg_auto_constraint_validations.rb +9 -3
  194. data/lib/sequel/plugins/pg_xmin_optimistic_locking.rb +109 -0
  195. data/lib/sequel/plugins/prepared_statements.rb +12 -2
  196. data/lib/sequel/plugins/prepared_statements_safe.rb +2 -1
  197. data/lib/sequel/plugins/primary_key_lookup_check_values.rb +154 -0
  198. data/lib/sequel/plugins/rcte_tree.rb +7 -4
  199. data/lib/sequel/plugins/require_valid_schema.rb +67 -0
  200. data/lib/sequel/plugins/serialization.rb +1 -0
  201. data/lib/sequel/plugins/serialization_modification_detection.rb +1 -0
  202. data/lib/sequel/plugins/single_table_inheritance.rb +8 -0
  203. data/lib/sequel/plugins/sql_comments.rb +189 -0
  204. data/lib/sequel/plugins/static_cache.rb +39 -1
  205. data/lib/sequel/plugins/static_cache_cache.rb +5 -1
  206. data/lib/sequel/plugins/subclasses.rb +28 -11
  207. data/lib/sequel/plugins/tactical_eager_loading.rb +23 -10
  208. data/lib/sequel/plugins/timestamps.rb +1 -1
  209. data/lib/sequel/plugins/unused_associations.rb +521 -0
  210. data/lib/sequel/plugins/update_or_create.rb +1 -1
  211. data/lib/sequel/plugins/validate_associated.rb +22 -12
  212. data/lib/sequel/plugins/validation_helpers.rb +41 -11
  213. data/lib/sequel/plugins/validation_helpers_generic_type_messages.rb +73 -0
  214. data/lib/sequel/plugins/xml_serializer.rb +1 -1
  215. data/lib/sequel/sql.rb +1 -1
  216. data/lib/sequel/timezones.rb +12 -14
  217. data/lib/sequel/version.rb +1 -1
  218. metadata +109 -19
@@ -24,29 +24,7 @@ module Sequel
24
24
 
25
25
  check_insert_allowed!
26
26
 
27
- columns = []
28
-
29
- case values.size
30
- when 0
31
- return insert_sql(OPTS)
32
- when 1
33
- case vals = values[0]
34
- when Hash
35
- values = []
36
- vals.each do |k,v|
37
- columns << k
38
- values << v
39
- end
40
- when Dataset, Array, LiteralString
41
- values = vals
42
- end
43
- when 2
44
- if (v0 = values[0]).is_a?(Array) && ((v1 = values[1]).is_a?(Array) || v1.is_a?(Dataset) || v1.is_a?(LiteralString))
45
- columns, values = v0, v1
46
- raise(Error, "Different number of values and columns given to insert_sql") if values.is_a?(Array) and columns.length != values.length
47
- end
48
- end
49
-
27
+ columns, values = _parse_insert_sql_args(values)
50
28
  if values.is_a?(Array) && values.empty? && !insert_supports_empty_values?
51
29
  columns, values = insert_empty_columns_values
52
30
  elsif values.is_a?(Dataset) && hoist_cte?(values) && supports_cte?(:insert)
@@ -104,7 +82,7 @@ module Sequel
104
82
  when DateTime
105
83
  literal_datetime_append(sql, v)
106
84
  when Date
107
- sql << literal_date(v)
85
+ literal_date_append(sql, v)
108
86
  when Dataset
109
87
  literal_dataset_append(sql, v)
110
88
  else
@@ -112,6 +90,58 @@ module Sequel
112
90
  end
113
91
  end
114
92
 
93
+ # The SQL to use for the MERGE statement.
94
+ def merge_sql
95
+ raise Error, "This database doesn't support MERGE" unless supports_merge?
96
+ if sql = opts[:sql]
97
+ return static_sql(sql)
98
+ end
99
+ if sql = cache_get(:_merge_sql)
100
+ return sql
101
+ end
102
+ source, join_condition = @opts[:merge_using]
103
+ raise Error, "No USING clause for MERGE" unless source
104
+ sql = @opts[:append_sql] || sql_string_origin
105
+
106
+ select_with_sql(sql)
107
+ sql << "MERGE INTO "
108
+ source_list_append(sql, @opts[:from])
109
+ sql << " USING "
110
+ identifier_append(sql, source)
111
+ sql << " ON "
112
+ literal_append(sql, join_condition)
113
+ _merge_when_sql(sql)
114
+ cache_set(:_merge_sql, sql) if cache_sql?
115
+ sql
116
+ end
117
+
118
+ # Literalize a date or time value, as a SQL string value with no
119
+ # typecasting. If +raw+ is true, remove the surrounding single
120
+ # quotes. This is designed for usage by bound argument code that
121
+ # can work even if the auto_cast_date_and_time extension is
122
+ # used (either manually or implicitly in the related adapter).
123
+ def literal_date_or_time(dt, raw=false)
124
+ value = case dt
125
+ when SQLTime
126
+ literal_sqltime(dt)
127
+ when Time
128
+ literal_time(dt)
129
+ when DateTime
130
+ literal_datetime(dt)
131
+ when Date
132
+ literal_date(dt)
133
+ else
134
+ raise TypeError, "unsupported type: #{dt.inspect}"
135
+ end
136
+
137
+ if raw
138
+ value.sub!(/\A'/, '')
139
+ value.sub!(/'\z/, '')
140
+ end
141
+
142
+ value
143
+ end
144
+
115
145
  # Returns an array of insert statements for inserting multiple records.
116
146
  # This method is used by +multi_insert+ to format insert statements and
117
147
  # expects a keys array and and an array of value arrays.
@@ -559,11 +589,9 @@ module Sequel
559
589
  # Append literalization of JOIN USING clause to SQL string.
560
590
  def join_using_clause_sql_append(sql, jc)
561
591
  join_clause_sql_append(sql, jc)
562
- sql << ' USING ('
563
- column_list_append(sql, jc.using)
564
- sql << ')'
592
+ join_using_clause_using_sql_append(sql, jc.using)
565
593
  end
566
-
594
+
567
595
  # Append literalization of negative boolean constant to SQL string.
568
596
  def negative_boolean_constant_sql_append(sql, constant)
569
597
  sql << 'NOT '
@@ -852,6 +880,83 @@ module Sequel
852
880
 
853
881
  private
854
882
 
883
+ # Append the INSERT sql used in a MERGE
884
+ def _merge_insert_sql(sql, data)
885
+ sql << " THEN INSERT"
886
+ columns, values = _parse_insert_sql_args(data[:values])
887
+ _insert_columns_sql(sql, columns)
888
+ _insert_values_sql(sql, values)
889
+ end
890
+
891
+ def _merge_update_sql(sql, data)
892
+ sql << " THEN UPDATE SET "
893
+ update_sql_values_hash(sql, data[:values])
894
+ end
895
+
896
+ def _merge_delete_sql(sql, data)
897
+ sql << " THEN DELETE"
898
+ end
899
+
900
+ # Mapping of merge types to related SQL
901
+ MERGE_TYPE_SQL = {
902
+ :insert => ' WHEN NOT MATCHED',
903
+ :delete => ' WHEN MATCHED',
904
+ :update => ' WHEN MATCHED',
905
+ :matched => ' WHEN MATCHED',
906
+ :not_matched => ' WHEN NOT MATCHED',
907
+ }.freeze
908
+ private_constant :MERGE_TYPE_SQL
909
+
910
+ # Add the WHEN clauses to the MERGE SQL
911
+ def _merge_when_sql(sql)
912
+ raise Error, "no WHEN [NOT] MATCHED clauses provided for MERGE" unless merge_when = @opts[:merge_when]
913
+ merge_when.each do |data|
914
+ type = data[:type]
915
+ sql << MERGE_TYPE_SQL[type]
916
+ _merge_when_conditions_sql(sql, data)
917
+ send(:"_merge_#{type}_sql", sql, data)
918
+ end
919
+ end
920
+
921
+ # Append MERGE WHEN conditions, if there are conditions provided.
922
+ def _merge_when_conditions_sql(sql, data)
923
+ if data.has_key?(:conditions)
924
+ sql << " AND "
925
+ literal_append(sql, data[:conditions])
926
+ end
927
+ end
928
+
929
+ # Parse the values passed to insert_sql, returning columns and values
930
+ # to use for the INSERT. Returned columns is always an array, but can be empty
931
+ # for an INSERT without explicit column references. Returned values can be an
932
+ # array, dataset, or literal string.
933
+ def _parse_insert_sql_args(values)
934
+ columns = []
935
+
936
+ case values.size
937
+ when 0
938
+ values = []
939
+ when 1
940
+ case vals = values[0]
941
+ when Hash
942
+ values = []
943
+ vals.each do |k,v|
944
+ columns << k
945
+ values << v
946
+ end
947
+ when Dataset, Array, LiteralString
948
+ values = vals
949
+ end
950
+ when 2
951
+ if (v0 = values[0]).is_a?(Array) && ((v1 = values[1]).is_a?(Array) || v1.is_a?(Dataset) || v1.is_a?(LiteralString))
952
+ columns, values = v0, v1
953
+ raise(Error, "Different number of values and columns given to insert_sql") if values.is_a?(Array) and columns.length != values.length
954
+ end
955
+ end
956
+
957
+ [columns, values]
958
+ end
959
+
855
960
  # Formats the truncate statement. Assumes the table given has already been
856
961
  # literalized.
857
962
  def _truncate_sql(table)
@@ -896,9 +1001,15 @@ module Sequel
896
1001
  # Clone of this dataset usable in aggregate operations. Does
897
1002
  # a from_self if dataset contains any parameters that would
898
1003
  # affect normal aggregation, or just removes an existing
899
- # order if not.
1004
+ # order if not. Also removes the row_proc, which isn't needed
1005
+ # for aggregate calculations.
900
1006
  def aggregate_dataset
901
- options_overlap(COUNT_FROM_SELF_OPTS) ? from_self : unordered
1007
+ (aggreate_dataset_use_from_self? ? from_self : unordered).naked
1008
+ end
1009
+
1010
+ # Whether to use from_self for an aggregate dataset.
1011
+ def aggreate_dataset_use_from_self?
1012
+ options_overlap(COUNT_FROM_SELF_OPTS)
902
1013
  end
903
1014
 
904
1015
  # Append aliasing expression to SQL string.
@@ -1020,9 +1131,14 @@ module Sequel
1020
1131
  :"t#{number}"
1021
1132
  end
1022
1133
 
1023
- # The strftime format to use when literalizing the time.
1134
+ # The strftime format to use when literalizing time (Sequel::SQLTime) values.
1135
+ def default_time_format
1136
+ "'%H:%M:%S.%6N'"
1137
+ end
1138
+
1139
+ # The strftime format to use when literalizing timestamp (Time/DateTime) values.
1024
1140
  def default_timestamp_format
1025
- requires_sql_standard_datetimes? ? "TIMESTAMP '%Y-%m-%d %H:%M:%S%N%z'" : "'%Y-%m-%d %H:%M:%S%N%z'"
1141
+ "'%Y-%m-%d %H:%M:%S.%6N'"
1026
1142
  end
1027
1143
 
1028
1144
  def delete_delete_sql(sql)
@@ -1085,43 +1201,23 @@ module Sequel
1085
1201
  {1 => ((op == :IN) ? 0 : 1)}
1086
1202
  end
1087
1203
 
1088
- # Format the timestamp based on the default_timestamp_format, with a couple
1089
- # of modifiers. First, allow %N to be used for fractions seconds (if the
1090
- # database supports them), and override %z to always use a numeric offset
1091
- # of hours and minutes.
1204
+ # Format the timestamp based on the default_timestamp_format.
1092
1205
  def format_timestamp(v)
1093
- v2 = db.from_application_timestamp(v)
1094
- fmt = default_timestamp_format.gsub(/%[Nz]/) do |m|
1095
- if m == '%N'
1096
- # Ruby 1.9 supports %N in timestamp formats, but Sequel has supported %N
1097
- # for longer in a different way, where the . is already appended and only 6
1098
- # decimal places are used by default.
1099
- format_timestamp_usec(v.is_a?(DateTime) ? v.sec_fraction*(1000000) : v.usec) if supports_timestamp_usecs?
1100
- else
1101
- if supports_timestamp_timezones?
1102
- # Would like to just use %z format, but it doesn't appear to work on Windows
1103
- # Instead, the offset fragment is constructed manually
1104
- minutes = (v2.is_a?(DateTime) ? v2.offset * 1440 : v2.utc_offset/60).to_i
1105
- format_timestamp_offset(*minutes.divmod(60))
1106
- end
1107
- end
1108
- end
1109
- v2.strftime(fmt)
1206
+ db.from_application_timestamp(v).strftime(default_timestamp_format)
1110
1207
  end
1111
1208
 
1112
- # Return the SQL timestamp fragment to use for the timezone offset.
1113
- def format_timestamp_offset(hour, minute)
1114
- sprintf("%+03i%02i", hour, minute)
1115
- end
1209
+ # :nocov:
1116
1210
 
1117
1211
  # Return the SQL timestamp fragment to use for the fractional time part.
1118
1212
  # Should start with the decimal point. Uses 6 decimal places by default.
1119
1213
  def format_timestamp_usec(usec, ts=timestamp_precision)
1214
+ # SEQUEL6: Remove
1120
1215
  unless ts == 6
1121
1216
  usec = usec/(10 ** (6 - ts))
1122
1217
  end
1123
1218
  sprintf(".%0#{ts}d", usec)
1124
1219
  end
1220
+ # :nocov:
1125
1221
 
1126
1222
  # Append literalization of identifier to SQL string, considering regular strings
1127
1223
  # as SQL identifiers instead of SQL strings.
@@ -1166,7 +1262,10 @@ module Sequel
1166
1262
  end
1167
1263
 
1168
1264
  def insert_columns_sql(sql)
1169
- columns = opts[:columns]
1265
+ _insert_columns_sql(sql, opts[:columns])
1266
+ end
1267
+
1268
+ def _insert_columns_sql(sql, columns)
1170
1269
  if columns && !columns.empty?
1171
1270
  sql << ' ('
1172
1271
  identifier_list_append(sql, columns)
@@ -1185,7 +1284,11 @@ module Sequel
1185
1284
  end
1186
1285
 
1187
1286
  def insert_values_sql(sql)
1188
- case values = opts[:values]
1287
+ _insert_values_sql(sql, opts[:values])
1288
+ end
1289
+
1290
+ def _insert_values_sql(sql, values)
1291
+ case values
1189
1292
  when Array
1190
1293
  if values.empty?
1191
1294
  sql << " DEFAULT VALUES"
@@ -1218,6 +1321,13 @@ module Sequel
1218
1321
  "#{join_type.to_s.gsub('_', ' ').upcase} JOIN"
1219
1322
  end
1220
1323
 
1324
+ # Append USING clause for JOIN USING
1325
+ def join_using_clause_using_sql_append(sql, using_columns)
1326
+ sql << ' USING ('
1327
+ column_list_append(sql, using_columns)
1328
+ sql << ')'
1329
+ end
1330
+
1221
1331
  # Append a literalization of the array to SQL string.
1222
1332
  # Treats as an expression if an array of all two pairs, or as a SQL array otherwise.
1223
1333
  def literal_array_append(sql, v)
@@ -1249,11 +1359,12 @@ module Sequel
1249
1359
 
1250
1360
  # SQL fragment for Date, using the ISO8601 format.
1251
1361
  def literal_date(v)
1252
- if requires_sql_standard_datetimes?
1253
- v.strftime("DATE '%Y-%m-%d'")
1254
- else
1255
- v.strftime("'%Y-%m-%d'")
1256
- end
1362
+ v.strftime("'%Y-%m-%d'")
1363
+ end
1364
+
1365
+ # Append literalization of date to SQL string.
1366
+ def literal_date_append(sql, v)
1367
+ sql << literal_date(v)
1257
1368
  end
1258
1369
 
1259
1370
  # SQL fragment for DateTime
@@ -1316,7 +1427,7 @@ module Sequel
1316
1427
 
1317
1428
  # SQL fragment for Sequel::SQLTime, containing just the time part
1318
1429
  def literal_sqltime(v)
1319
- v.strftime("'%H:%M:%S#{format_timestamp_usec(v.usec, sqltime_precision) if supports_timestamp_usecs?}'")
1430
+ v.strftime(default_time_format)
1320
1431
  end
1321
1432
 
1322
1433
  # Append literalization of Sequel::SQLTime to SQL string.
@@ -1538,15 +1649,14 @@ module Sequel
1538
1649
 
1539
1650
  def select_with_sql(sql)
1540
1651
  return unless supports_cte?
1541
- ws = opts[:with]
1542
- return if !ws || ws.empty?
1652
+ ctes = opts[:with]
1653
+ return if !ctes || ctes.empty?
1543
1654
  sql << select_with_sql_base
1544
1655
  c = false
1545
1656
  comma = ', '
1546
- ws.each do |w|
1657
+ ctes.each do |cte|
1547
1658
  sql << comma if c
1548
- select_with_sql_prefix(sql, w)
1549
- literal_dataset_append(sql, w[:dataset])
1659
+ select_with_sql_cte(sql, cte)
1550
1660
  c ||= true
1551
1661
  end
1552
1662
  sql << ' '
@@ -1559,6 +1669,11 @@ module Sequel
1559
1669
  "WITH "
1560
1670
  end
1561
1671
 
1672
+ def select_with_sql_cte(sql, cte)
1673
+ select_with_sql_prefix(sql, cte)
1674
+ literal_dataset_append(sql, cte[:dataset])
1675
+ end
1676
+
1562
1677
  def select_with_sql_prefix(sql, w)
1563
1678
  quote_identifier_append(sql, w[:name])
1564
1679
  if args = w[:args]
@@ -1628,7 +1743,7 @@ module Sequel
1628
1743
  # Append literalization of the subselect to SQL string.
1629
1744
  def subselect_sql_append(sql, ds)
1630
1745
  sds = subselect_sql_dataset(sql, ds)
1631
- sds.sql
1746
+ subselect_sql_append_sql(sql, sds)
1632
1747
  unless sds.send(:cache_sql?)
1633
1748
  # If subquery dataset does not allow caching SQL,
1634
1749
  # then this dataset should not allow caching SQL.
@@ -1640,6 +1755,10 @@ module Sequel
1640
1755
  ds.clone(:append_sql=>sql)
1641
1756
  end
1642
1757
 
1758
+ def subselect_sql_append_sql(sql, ds)
1759
+ ds.sql
1760
+ end
1761
+
1643
1762
  # The number of decimal digits of precision to use in timestamps.
1644
1763
  def timestamp_precision
1645
1764
  supports_timestamp_usecs? ? 6 : 0
@@ -53,4 +53,8 @@ module Sequel
53
53
  require_relative "dataset/sql"
54
54
  require_relative "dataset/placeholder_literalizer"
55
55
  require_relative "dataset/dataset_module"
56
+
57
+ # :nocov:
58
+ require_relative "dataset/deprecated_singleton_class_methods" if Dataset::TRUE_FREEZE
59
+ # :nocov:
56
60
  end
@@ -23,18 +23,6 @@ module Sequel
23
23
  super
24
24
  end
25
25
  end
26
-
27
- private
28
-
29
- # Handle Sequel::Model instances in bound variable arrays.
30
- def bound_variable_array(arg)
31
- case arg
32
- when Sequel::Model
33
- "\"(#{arg.values.values_at(*arg.columns).map{|v| bound_variable_array(v)}.join(',').gsub(/("|\\)/, '\\\\\1')})\""
34
- else
35
- super
36
- end
37
- end
38
26
  end
39
27
  end
40
28
  end
@@ -39,7 +39,7 @@ module Sequel
39
39
 
40
40
  # Hash of the maximum size of the value for each column
41
41
  def self.column_sizes(records, columns) # :nodoc:
42
- sizes = Hash.new {0}
42
+ sizes = Hash.new(0)
43
43
  columns.each do |c|
44
44
  sizes[c] = c.to_s.size
45
45
  end
@@ -32,8 +32,8 @@
32
32
  module Sequel
33
33
  module AnyNotEmpty
34
34
  # If a block is not given, return whether the dataset is not empty.
35
- def any?
36
- if block_given?
35
+ def any?(*a)
36
+ if !a.empty? || defined?(yield)
37
37
  super
38
38
  else
39
39
  !empty?
@@ -5,9 +5,9 @@
5
5
  # code
6
6
  #
7
7
  # DB.extension :async_thread_pool
8
- # foos = DB[:foos].async.where{:name=>'A'..'M'}.all
8
+ # foos = DB[:foos].async.where(name: 'A'..'M').all
9
9
  # bar_names = DB[:bar].async.select_order_map(:name)
10
- # baz_1 = DB[:bazes].async.first(:id=>1)
10
+ # baz_1 = DB[:bazes].async.first(id: 1)
11
11
  #
12
12
  # All 3 queries will be run in separate threads. +foos+, +bar_names+
13
13
  # and +baz_1+ will be proxy objects. Calling a method on the proxy
@@ -15,9 +15,9 @@
15
15
  # of calling that method on the result of the query method. For example,
16
16
  # if you run:
17
17
  #
18
- # foos = DB[:foos].async.where{:name=>'A'..'M'}.all
18
+ # foos = DB[:foos].async.where(name: 'A'..'M').all
19
19
  # bar_names = DB[:bars].async.select_order_map(:name)
20
- # baz_1 = DB[:bazes].async.first(:id=>1)
20
+ # baz_1 = DB[:bazes].async.first(id: 1)
21
21
  # sleep(1)
22
22
  # foos.size
23
23
  # bar_names.first
@@ -26,9 +26,9 @@
26
26
  # These three queries will generally be run concurrently in separate
27
27
  # threads. If you instead run:
28
28
  #
29
- # DB[:foos].async.where{:name=>'A'..'M'}.all.size
29
+ # DB[:foos].async.where(name: 'A'..'M').all.size
30
30
  # DB[:bars].async.select_order_map(:name).first
31
- # DB[:bazes].async.first(:id=>1).name
31
+ # DB[:bazes].async.first(id: 1).name
32
32
  #
33
33
  # Then will run each query sequentially, since you need the result of
34
34
  # one query before running the next query. The queries will still be
@@ -37,11 +37,11 @@
37
37
  # What is run in the separate thread is the entire method call that
38
38
  # returns results. So with the original example:
39
39
  #
40
- # foos = DB[:foos].async.where{:name=>'A'..'M'}.all
40
+ # foos = DB[:foos].async.where(name: 'A'..'M').all
41
41
  # bar_names = DB[:bars].async.select_order_map(:name)
42
- # baz_1 = DB[:bazes].async.first(:id=>1)
42
+ # baz_1 = DB[:bazes].async.first(id: 1)
43
43
  #
44
- # The +all+, <tt>select_order_map(:name)</tt>, and <tt>first(:id=>1)</tt>
44
+ # The +all+, <tt>select_order_map(:name)</tt>, and <tt>first(id: 1)</tt>
45
45
  # calls are run in separate threads. If a block is passed to a method
46
46
  # such as +all+ or +each+, the block is also run in that thread. If you
47
47
  # have code such as:
@@ -156,10 +156,10 @@
156
156
  # so that the query will run in the current thread instead of waiting
157
157
  # for an async thread to become available. With the following code:
158
158
  #
159
- # foos = DB[:foos].async.where{:name=>'A'..'M'}.all
159
+ # foos = DB[:foos].async.where(name: 'A'..'M').all
160
160
  # bar_names = DB[:bar].async.select_order_map(:name)
161
161
  # if foos.length > 4
162
- # baz_1 = DB[:bazes].async.first(:id=>1)
162
+ # baz_1 = DB[:bazes].async.first(id: 1)
163
163
  # end
164
164
  #
165
165
  # Whether you need the +baz_1+ variable depends on the value of foos.
@@ -338,8 +338,9 @@ module Sequel
338
338
  module DatabaseMethods
339
339
  def self.extended(db)
340
340
  db.instance_exec do
341
- unless pool.pool_type == :threaded || pool.pool_type == :sharded_threaded
342
- raise Error, "can only load async_thread_pool extension if using threaded or sharded_threaded connection pool"
341
+ case pool.pool_type
342
+ when :single, :sharded_single
343
+ raise Error, "cannot load async_thread_pool extension if using single or sharded_single connection pool"
343
344
  end
344
345
 
345
346
  num_async_threads = opts[:num_async_threads] ? typecast_value_integer(opts[:num_async_threads]) : (Integer(opts[:max_connections] || 4))
@@ -0,0 +1,94 @@
1
+ # frozen-string-literal: true
2
+ #
3
+ # The auto_cast_date_and_time extension uses SQL standard type casting
4
+ # when literalizing date, time, and timestamp values:
5
+ #
6
+ # DB.literal(Time.now)
7
+ # # => "TIMESTAMP '...'"
8
+ #
9
+ # DB.literal(Date.today)
10
+ # # => "DATE '...'"
11
+ #
12
+ # DB.literal(Sequel::SQLTime.create(10, 20, 30))
13
+ # # => "TIME '10:20:30.000000'"
14
+ #
15
+ # The default behavior of Sequel on adapters that do not require the
16
+ # SQL standard behavior is to format the date or time value without:
17
+ # casting
18
+ #
19
+ # DB.literal(Sequel::SQLTime.create(10, 20, 30))
20
+ # # => "'10:20:30.000000'"
21
+ #
22
+ # However, then the database cannot determine the type of the string,
23
+ # and must perform some implicit casting. If implicit casting cannot
24
+ # be used, it will probably treat the value as a string:
25
+ #
26
+ # DB.get(Time.now).class
27
+ # # Without auto_cast_date_and_time: String
28
+ # # With auto_cast_date_and_time: Time
29
+ #
30
+ # Note that not all databases support this extension. PostgreSQL and
31
+ # MySQL support it, but SQLite and Microsoft SQL Server do not.
32
+ #
33
+ # You can load this extension into specific datasets:
34
+ #
35
+ # ds = DB[:table]
36
+ # ds = ds.extension(:auto_cast_date_and_time)
37
+ #
38
+ # Or you can load it into all of a database's datasets, which
39
+ # is probably the desired behavior if you are using this extension:
40
+ #
41
+ # DB.extension(:auto_cast_date_and_time)
42
+ #
43
+ # Related module: Sequel::AutoCastDateAndTime
44
+
45
+ #
46
+ module Sequel
47
+ module AutoCastDateAndTime
48
+ # :nocov:
49
+
50
+ # Mark the datasets as requiring sql standard date times. This is only needed
51
+ # for backwards compatibility.
52
+ def requires_sql_standard_datetimes?
53
+ # SEQUEL6: Remove
54
+ true
55
+ end
56
+ # :nocov:
57
+
58
+ private
59
+
60
+ # Explicitly cast SQLTime objects to TIME.
61
+ def literal_sqltime_append(sql, v)
62
+ sql << "TIME "
63
+ super
64
+ end
65
+
66
+ # Explicitly cast Time objects to TIMESTAMP.
67
+ def literal_time_append(sql, v)
68
+ sql << literal_datetime_timestamp_cast
69
+ super
70
+ end
71
+
72
+ # Explicitly cast DateTime objects to TIMESTAMP.
73
+ def literal_datetime_append(sql, v)
74
+ sql << literal_datetime_timestamp_cast
75
+ super
76
+ end
77
+
78
+ # Explicitly cast Date objects to DATE.
79
+ def literal_date_append(sql, v)
80
+ sql << "DATE "
81
+ super
82
+ end
83
+
84
+ # The default cast string to use for Time/DateTime objects.
85
+ # Respects existing method if already defined.
86
+ def literal_datetime_timestamp_cast
87
+ return super if defined?(super)
88
+ 'TIMESTAMP '
89
+ end
90
+ end
91
+
92
+ Dataset.register_extension(:auto_cast_date_and_time, AutoCastDateAndTime)
93
+ end
94
+
@@ -22,7 +22,7 @@
22
22
  #
23
23
  # Named placeholders can also be used with a hash:
24
24
  #
25
- # ds.where("name > :a", :a=>"A")
25
+ # ds.where("name > :a", a: "A")
26
26
  # # SELECT * FROM table WHERE (name > 'A')
27
27
  #
28
28
  # This extension also allows the use of a plain string passed to Dataset#update:
@@ -15,16 +15,16 @@
15
15
  #
16
16
  # DB.pool.connection_expiration_timeout = 3600 # 1 hour
17
17
  #
18
- # Note that this extension only affects the default threaded
19
- # and the sharded threaded connection pool. The single
20
- # threaded and sharded single threaded connection pools are
21
- # not affected. As the only reason to use the single threaded
18
+ # Note that this extension does not work with the single
19
+ # threaded and sharded single threaded connection pools.
20
+ # As the only reason to use the single threaded
22
21
  # pools is for speed, and this extension makes the connection
23
22
  # pool slower, there's not much point in modifying this
24
23
  # extension to work with the single threaded pools. The
25
- # threaded pools work fine even in single threaded code, so if
26
- # you are currently using a single threaded pool and want to
27
- # use this extension, switch to using a threaded pool.
24
+ # non-single threaded pools work fine even in single threaded
25
+ # code, so if you are currently using a single threaded pool
26
+ # and want to use this extension, switch to using another
27
+ # pool.
28
28
  #
29
29
  # Related module: Sequel::ConnectionExpiration
30
30
 
@@ -45,6 +45,11 @@ module Sequel
45
45
 
46
46
  # Initialize the data structures used by this extension.
47
47
  def self.extended(pool)
48
+ case pool.pool_type
49
+ when :single, :sharded_single
50
+ raise Error, "cannot load connection_expiration extension if using single or sharded_single connection pool"
51
+ end
52
+
48
53
  pool.instance_exec do
49
54
  sync do
50
55
  @connection_expiration_timestamps ||= {}
@@ -79,8 +84,9 @@ module Sequel
79
84
  (cet = sync{@connection_expiration_timestamps[conn]}) &&
80
85
  Sequel.elapsed_seconds_since(cet[0]) > cet[1]
81
86
 
82
- if pool_type == :sharded_threaded
83
- sync{allocated(a.last).delete(Sequel.current)}
87
+ case pool_type
88
+ when :sharded_threaded, :sharded_timed_queue
89
+ sync{@allocated[a.last].delete(Sequel.current)}
84
90
  else
85
91
  sync{@allocated.delete(Sequel.current)}
86
92
  end