sequel 5.101.0 → 5.104.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/MIT-LICENSE +1 -1
- data/lib/sequel/adapters/jdbc/derby.rb +2 -0
- data/lib/sequel/adapters/jdbc/h2.rb +2 -2
- data/lib/sequel/adapters/postgres.rb +1 -1
- data/lib/sequel/adapters/shared/mssql.rb +3 -3
- data/lib/sequel/adapters/shared/mysql.rb +5 -4
- data/lib/sequel/adapters/shared/postgres.rb +16 -16
- data/lib/sequel/adapters/shared/sqlite.rb +3 -3
- data/lib/sequel/adapters/sqlite.rb +1 -1
- data/lib/sequel/adapters/tinytds.rb +1 -1
- data/lib/sequel/connection_pool/sharded_timed_queue.rb +36 -11
- data/lib/sequel/connection_pool/timed_queue.rb +27 -9
- data/lib/sequel/connection_pool.rb +6 -0
- data/lib/sequel/database/schema_generator.rb +36 -5
- data/lib/sequel/database/schema_methods.rb +1 -1
- data/lib/sequel/dataset/placeholder_literalizer.rb +3 -0
- data/lib/sequel/dataset/prepared_statements.rb +7 -4
- data/lib/sequel/dataset/query.rb +6 -3
- data/lib/sequel/dataset/sql.rb +6 -1
- data/lib/sequel/extensions/connection_checkout_event_callback.rb +151 -0
- data/lib/sequel/extensions/connection_expiration.rb +1 -1
- data/lib/sequel/extensions/connection_validator.rb +1 -1
- data/lib/sequel/extensions/dataset_run.rb +2 -2
- data/lib/sequel/extensions/date_arithmetic.rb +6 -6
- data/lib/sequel/extensions/lit_require_frozen.rb +131 -0
- data/lib/sequel/extensions/migration.rb +14 -17
- data/lib/sequel/extensions/pg_enum.rb +1 -1
- data/lib/sequel/model/associations.rb +180 -6
- data/lib/sequel/plugins/dataset_associations.rb +20 -1
- data/lib/sequel/plugins/dirty.rb +5 -2
- data/lib/sequel/plugins/many_through_many.rb +21 -0
- data/lib/sequel/plugins/mssql_optimistic_locking.rb +1 -1
- data/lib/sequel/plugins/pg_xmin_optimistic_locking.rb +1 -1
- data/lib/sequel/plugins/serialization.rb +10 -1
- data/lib/sequel/version.rb +1 -1
- metadata +3 -1
|
@@ -112,6 +112,8 @@ module Sequel
|
|
|
112
112
|
# the dataset unmodified if no SQL limit strategy is needed.
|
|
113
113
|
def apply_eager_graph_limit_strategy(strategy, ds)
|
|
114
114
|
case strategy
|
|
115
|
+
when :lateral_subquery
|
|
116
|
+
apply_lateral_subquery_eager_graph_limit_strategy(ds)
|
|
115
117
|
when :distinct_on
|
|
116
118
|
apply_distinct_on_eager_limit_strategy(ds.order_prepend(*self[:order]))
|
|
117
119
|
when :window_function
|
|
@@ -298,7 +300,12 @@ module Sequel
|
|
|
298
300
|
# Correlated subqueries are not supported for regular eager loading
|
|
299
301
|
strategy = :ruby if strategy == :correlated_subquery
|
|
300
302
|
strategy = nil if strategy == :ruby && assign_singular?
|
|
301
|
-
|
|
303
|
+
|
|
304
|
+
objects = if strategy == :lateral_subquery
|
|
305
|
+
apply_lateral_subquery_eager_limit_strategy(ds, ids, eager_limit).all
|
|
306
|
+
else
|
|
307
|
+
apply_eager_limit_strategy(ds, strategy, eager_limit).all
|
|
308
|
+
end
|
|
302
309
|
|
|
303
310
|
if strategy == :window_function
|
|
304
311
|
delete_rn = ds.row_number_column
|
|
@@ -320,7 +327,7 @@ module Sequel
|
|
|
320
327
|
end
|
|
321
328
|
loader.append_sql(sql, *k)
|
|
322
329
|
end
|
|
323
|
-
objects.concat(ds.with_sql(sql).to_a)
|
|
330
|
+
objects.concat(ds.with_sql(sql.freeze).to_a)
|
|
324
331
|
end
|
|
325
332
|
ds = ds.eager(cascade) if cascade
|
|
326
333
|
ds.send(:post_load, objects)
|
|
@@ -366,7 +373,12 @@ module Sequel
|
|
|
366
373
|
# filtered. Works by using a subquery to test that the objects passed
|
|
367
374
|
# also meet the association filter criteria.
|
|
368
375
|
def filter_by_associations_conditions_expression(obj)
|
|
369
|
-
ds =
|
|
376
|
+
ds = if filter_by_associations_limit_strategy == :lateral_subquery
|
|
377
|
+
apply_lateral_subquery_filter_limit_strategy(associated_eager_dataset, obj)
|
|
378
|
+
else
|
|
379
|
+
filter_by_associations_conditions_dataset.where(filter_by_associations_conditions_subquery_conditions(obj))
|
|
380
|
+
end
|
|
381
|
+
|
|
370
382
|
{filter_by_associations_conditions_key=>ds}
|
|
371
383
|
end
|
|
372
384
|
|
|
@@ -754,6 +766,61 @@ module Sequel
|
|
|
754
766
|
end
|
|
755
767
|
end
|
|
756
768
|
|
|
769
|
+
def lateral_subquery_eager_limit_strategy_lateral_dataset(ds, limit_and_offset)
|
|
770
|
+
ds.
|
|
771
|
+
where(Array(filter_by_associations_conditions_key).zip(Array(filter_by_associations_conditions_associated_keys))).
|
|
772
|
+
limit(*limit_and_offset).
|
|
773
|
+
lateral
|
|
774
|
+
end
|
|
775
|
+
|
|
776
|
+
def apply_lateral_subquery_eager_limit_strategy(ds, ids, limit_and_offset)
|
|
777
|
+
table_name = self[:model].table_name
|
|
778
|
+
associated_table_name = associated_class.table_name
|
|
779
|
+
|
|
780
|
+
associated_class.
|
|
781
|
+
from(table_name).
|
|
782
|
+
select_all(associated_table_name).
|
|
783
|
+
join(lateral_subquery_eager_limit_strategy_lateral_dataset(ds, limit_and_offset).as(associated_table_name), true).
|
|
784
|
+
order(*self[:order])
|
|
785
|
+
end
|
|
786
|
+
|
|
787
|
+
# Return an expression to filter the filter by associations dataset to only
|
|
788
|
+
# rows related to given objects.
|
|
789
|
+
def _lateral_subquery_filter_limit_strategy_conditions(obj, key, value_method, value_column)
|
|
790
|
+
value = case obj
|
|
791
|
+
when Array
|
|
792
|
+
if key.is_a?(Array)
|
|
793
|
+
key_methods = Array(value_method)
|
|
794
|
+
obj.map{|o| key_methods.map{|meth| o.send(meth)}}
|
|
795
|
+
else
|
|
796
|
+
obj.map{|o| o.send(value_method)}
|
|
797
|
+
end
|
|
798
|
+
when Sequel::Dataset
|
|
799
|
+
obj.select(*Array(qualify(associated_class.table_name, value_column)))
|
|
800
|
+
else
|
|
801
|
+
if key.is_a?(Array)
|
|
802
|
+
return Array(key).zip(Array(value_method).map{|meth| obj.send(meth)})
|
|
803
|
+
else
|
|
804
|
+
obj.send(value_method)
|
|
805
|
+
end
|
|
806
|
+
end
|
|
807
|
+
|
|
808
|
+
{key => value}
|
|
809
|
+
end
|
|
810
|
+
|
|
811
|
+
def lateral_subquery_filter_limit_strategy_lateral_dataset(ds, obj)
|
|
812
|
+
lateral_subquery_filter_limit_strategy_filter_lateral_dataset(ds.
|
|
813
|
+
select(*qualify(associated_class.table_name, associated_class.primary_key)).
|
|
814
|
+
limit(*limit_and_offset).
|
|
815
|
+
lateral)
|
|
816
|
+
end
|
|
817
|
+
|
|
818
|
+
def apply_lateral_subquery_filter_limit_strategy(ds, obj)
|
|
819
|
+
lateral_subquery_filter_limit_strategy_filter_dataset(self[:model].
|
|
820
|
+
select(*lateral_subquery_filter_limit_strategy_lateral_dataset_select).
|
|
821
|
+
join(lateral_subquery_filter_limit_strategy_lateral_dataset(ds, obj).as(associated_class.table_name), filter_by_associations_conditions_subquery_conditions(obj)), obj)
|
|
822
|
+
end
|
|
823
|
+
|
|
757
824
|
# Whether to limit the associated dataset to a single row.
|
|
758
825
|
def limit_to_single_row?
|
|
759
826
|
!returns_array?
|
|
@@ -776,7 +843,12 @@ module Sequel
|
|
|
776
843
|
end
|
|
777
844
|
end
|
|
778
845
|
|
|
779
|
-
|
|
846
|
+
strategy = eager_limit_strategy
|
|
847
|
+
if strategy == :lateral_subquery
|
|
848
|
+
apply_lateral_subquery_eager_limit_strategy(ds, arg, limit_and_offset)
|
|
849
|
+
else
|
|
850
|
+
apply_eager_limit_strategy(ds.where(predicate_key=>arg), strategy)
|
|
851
|
+
end
|
|
780
852
|
end
|
|
781
853
|
end
|
|
782
854
|
end
|
|
@@ -1018,7 +1090,7 @@ module Sequel
|
|
|
1018
1090
|
class OneToManyAssociationReflection < AssociationReflection
|
|
1019
1091
|
ASSOCIATION_TYPES[:one_to_many] = self
|
|
1020
1092
|
|
|
1021
|
-
# Support a
|
|
1093
|
+
# Support a lateral_subquery and correlated_subquery limit strategy when using eager_graph.
|
|
1022
1094
|
def apply_eager_graph_limit_strategy(strategy, ds)
|
|
1023
1095
|
case strategy
|
|
1024
1096
|
when :correlated_subquery
|
|
@@ -1118,6 +1190,54 @@ module Sequel
|
|
|
1118
1190
|
ds.where(qualify(table_alias, primary_key)=>cs)
|
|
1119
1191
|
end
|
|
1120
1192
|
|
|
1193
|
+
# Use a LATERAL subquery to limit the dataset. Note that this will not
|
|
1194
|
+
# work correctly if the associated dataset uses qualified identifers in the WHERE clause,
|
|
1195
|
+
# as they would reference the containing query instead of the subquery.
|
|
1196
|
+
#
|
|
1197
|
+
# This does not contain the conditions that are necessary to join to the
|
|
1198
|
+
# query, since the necessary qualifier is not passed as an argument.
|
|
1199
|
+
def apply_lateral_subquery_eager_graph_limit_strategy(ds)
|
|
1200
|
+
table_name = ds.first_source_alias
|
|
1201
|
+
qualifier = ds.opts[:eager_options][:implicit_qualifier]
|
|
1202
|
+
graph_conditions = self[:_graph_conditions]
|
|
1203
|
+
|
|
1204
|
+
unless Sequel.condition_specifier?(graph_conditions)
|
|
1205
|
+
raise Error, "lateral_subquery eager graph limit strategy only supported when graph conditions are a hash or array of pairs"
|
|
1206
|
+
end
|
|
1207
|
+
|
|
1208
|
+
ds.
|
|
1209
|
+
limit(*limit_and_offset).
|
|
1210
|
+
order(*self[:order]).
|
|
1211
|
+
where(graph_conditions.map{|k, v| [qualify(table_name, k), qualify(qualifier, v)]}).
|
|
1212
|
+
lateral
|
|
1213
|
+
end
|
|
1214
|
+
|
|
1215
|
+
# Avoid setting duplicate predicate condition when using the lateral subquery
|
|
1216
|
+
# eager limit strategy.
|
|
1217
|
+
def eager_loading_set_predicate_condition(ds, eo)
|
|
1218
|
+
eager_limit_strategy == :lateral_subquery ? ds : super
|
|
1219
|
+
end
|
|
1220
|
+
|
|
1221
|
+
def apply_lateral_subquery_eager_limit_strategy(ds, ids, limit_and_offset)
|
|
1222
|
+
super.where(qualify(self[:model].table_name, self[:primary_key]) => ids)
|
|
1223
|
+
end
|
|
1224
|
+
|
|
1225
|
+
def lateral_subquery_filter_limit_strategy_conditions(obj)
|
|
1226
|
+
_lateral_subquery_filter_limit_strategy_conditions(obj, filter_by_associations_conditions_key, self[:key_method], self[:key])
|
|
1227
|
+
end
|
|
1228
|
+
|
|
1229
|
+
def lateral_subquery_filter_limit_strategy_filter_lateral_dataset(ds)
|
|
1230
|
+
ds.where(Array(filter_by_associations_conditions_key).zip(Array(filter_by_associations_conditions_associated_keys)))
|
|
1231
|
+
end
|
|
1232
|
+
|
|
1233
|
+
def lateral_subquery_filter_limit_strategy_filter_dataset(ds, obj)
|
|
1234
|
+
ds.where(lateral_subquery_filter_limit_strategy_conditions(obj))
|
|
1235
|
+
end
|
|
1236
|
+
|
|
1237
|
+
def lateral_subquery_filter_limit_strategy_lateral_dataset_select
|
|
1238
|
+
qualified_primary_key
|
|
1239
|
+
end
|
|
1240
|
+
|
|
1121
1241
|
# Support correlated subquery strategy when filtering by limited associations.
|
|
1122
1242
|
def apply_filter_by_associations_limit_strategy(ds)
|
|
1123
1243
|
case filter_by_associations_limit_strategy
|
|
@@ -1432,6 +1552,52 @@ module Sequel
|
|
|
1432
1552
|
end
|
|
1433
1553
|
end
|
|
1434
1554
|
|
|
1555
|
+
def lateral_subquery_filter_limit_strategy_conditions(obj)
|
|
1556
|
+
_lateral_subquery_filter_limit_strategy_conditions(obj, lateral_subquery_filter_limit_strategy_conditions_key, right_primary_key_method, right_primary_key)
|
|
1557
|
+
end
|
|
1558
|
+
|
|
1559
|
+
def lateral_subquery_filter_limit_strategy_conditions_key
|
|
1560
|
+
self[:right_key]
|
|
1561
|
+
end
|
|
1562
|
+
|
|
1563
|
+
def lateral_subquery_filter_limit_strategy_filter_lateral_dataset(ds)
|
|
1564
|
+
ds.where(Array(filter_by_associations_conditions_key).zip(Array(filter_by_associations_conditions_associated_keys)))
|
|
1565
|
+
end
|
|
1566
|
+
|
|
1567
|
+
def lateral_subquery_filter_limit_strategy_filter_dataset(ds, obj)
|
|
1568
|
+
ds.where(filter_by_associations_conditions_key => ds.db.from(self[:join_table]).
|
|
1569
|
+
select(*self[:left_key]).
|
|
1570
|
+
where(lateral_subquery_filter_limit_strategy_conditions(obj)))
|
|
1571
|
+
end
|
|
1572
|
+
|
|
1573
|
+
def lateral_subquery_filter_limit_strategy_lateral_dataset_select
|
|
1574
|
+
qualify(self[:model].table_name, self[:left_primary_key])
|
|
1575
|
+
end
|
|
1576
|
+
|
|
1577
|
+
def lateral_subquery_eager_limit_strategy_lateral_dataset(ds, limit_and_offset)
|
|
1578
|
+
ds = super
|
|
1579
|
+
select = ds.opts[:select].dup
|
|
1580
|
+
left_key_alias = self[:left_key_alias]
|
|
1581
|
+
select.pop while (s = select.last).is_a?(Sequel::SQL::AliasedExpression) && (left_key_alias.is_a?(Array) ? left_key_alias.include?(s.alias) : s.alias == left_key_alias)
|
|
1582
|
+
ds = ds.clone(:select=>select)
|
|
1583
|
+
end
|
|
1584
|
+
|
|
1585
|
+
def apply_lateral_subquery_eager_limit_strategy(ds, ids, limit_and_offset)
|
|
1586
|
+
table_name = self[:model].table_name
|
|
1587
|
+
super.
|
|
1588
|
+
select_all(associated_class.table_name).
|
|
1589
|
+
select_append(*qualify(table_name, self[:left_primary_keys]).zip(Array(self[:left_key_alias])).map{|id, aliaz| Sequel.as(id, aliaz)}).
|
|
1590
|
+
where(qualify(table_name, self[:left_primary_key]) => ids)
|
|
1591
|
+
end
|
|
1592
|
+
|
|
1593
|
+
def apply_lateral_subquery_eager_graph_limit_strategy(ds)
|
|
1594
|
+
ds.
|
|
1595
|
+
limit(*limit_and_offset).
|
|
1596
|
+
where(qualify(join_table_alias, self[:left_keys]).zip(qualify(ds.opts[:eager_options][:implicit_qualifier], self[:left_primary_key_columns]))).
|
|
1597
|
+
order(*self[:order]).
|
|
1598
|
+
lateral
|
|
1599
|
+
end
|
|
1600
|
+
|
|
1435
1601
|
# Use the right_keys from the eager loading options if
|
|
1436
1602
|
# using a separate query per table.
|
|
1437
1603
|
def eager_loading_set_predicate_condition(ds, eo)
|
|
@@ -2413,9 +2579,14 @@ module Sequel
|
|
|
2413
2579
|
conditions = opts[:graph_conditions]
|
|
2414
2580
|
opts[:cartesian_product_number] ||= one_to_one ? 0 : 1
|
|
2415
2581
|
graph_block = opts[:graph_block]
|
|
2582
|
+
graph_conditions = opts[:_graph_conditions] = use_only_conditions ? only_conditions : cks.zip(pkcs) + conditions
|
|
2416
2583
|
opts[:eager_grapher] ||= proc do |eo|
|
|
2417
2584
|
ds = eo[:self]
|
|
2418
|
-
|
|
2585
|
+
graph_limit_strategy = eo[:limit_strategy]
|
|
2586
|
+
egds = opts.apply_eager_graph_limit_strategy(graph_limit_strategy, eager_graph_dataset(opts, eo))
|
|
2587
|
+
graph_conditions_true = true if graph_limit_strategy == :lateral_subquery
|
|
2588
|
+
|
|
2589
|
+
ds = ds.graph(egds, graph_conditions_true || graph_conditions, eo.merge(:select=>select, :join_type=>eo[:join_type]||join_type, :qualify=>:deep), &graph_block)
|
|
2419
2590
|
# We only load reciprocals for one_to_many associations, as other reciprocals don't make sense
|
|
2420
2591
|
ds.opts[:eager_graph][:reciprocals][eo[:table_alias]] = opts.reciprocal
|
|
2421
2592
|
ds
|
|
@@ -2498,6 +2669,9 @@ module Sequel
|
|
|
2498
2669
|
# Return dataset to graph into given the association reflection, applying the :callback option if set.
|
|
2499
2670
|
def eager_graph_dataset(opts, eager_options)
|
|
2500
2671
|
ds = opts.associated_class.dataset
|
|
2672
|
+
if eager_options[:limit_strategy] == :lateral_subquery
|
|
2673
|
+
ds = ds.clone(:eager_options=>eager_options)
|
|
2674
|
+
end
|
|
2501
2675
|
if opts[:graph_use_association_block] && (b = opts[:block])
|
|
2502
2676
|
ds = b.call(ds)
|
|
2503
2677
|
end
|
|
@@ -82,8 +82,27 @@ module Sequel
|
|
|
82
82
|
# database supports window functions.
|
|
83
83
|
def associated(name)
|
|
84
84
|
raise Error, "unrecognized association name: #{name.inspect}" unless r = model.association_reflection(name)
|
|
85
|
-
|
|
85
|
+
klass = r.associated_class
|
|
86
86
|
sds = opts[:limit] ? self : unordered
|
|
87
|
+
|
|
88
|
+
if r.send(:filter_by_associations_limit_strategy) == :lateral_subquery
|
|
89
|
+
ds = r.send(:associated_eager_dataset)
|
|
90
|
+
|
|
91
|
+
case r[:type]
|
|
92
|
+
when :one_to_one, :one_to_many
|
|
93
|
+
sds = sds.select(*Array(r.qualified_primary_key))
|
|
94
|
+
else
|
|
95
|
+
sds = sds.select(*r[:left_primary_keys])
|
|
96
|
+
ds = ds.select_all(klass.table_name)
|
|
97
|
+
update_select = true
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
ds = r.send(:apply_lateral_subquery_eager_limit_strategy, ds, sds, r.limit_and_offset)
|
|
101
|
+
ds = ds.clone(:select=>ds.opts[:select][0,1]) if update_select
|
|
102
|
+
return ds.clone(:eager=>nil, :eager_graph=>nil)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
ds = klass.dataset
|
|
87
106
|
ds = case r[:type]
|
|
88
107
|
when :many_to_one
|
|
89
108
|
ds.where(r.qualified_primary_key=>sds.select(*Array(r[:qualified_key])))
|
data/lib/sequel/plugins/dirty.rb
CHANGED
|
@@ -234,8 +234,11 @@ module Sequel
|
|
|
234
234
|
iv.delete(column)
|
|
235
235
|
end
|
|
236
236
|
else
|
|
237
|
-
|
|
238
|
-
|
|
237
|
+
if db_schema[column]
|
|
238
|
+
check_missing_initial_value(column)
|
|
239
|
+
iv[column] = get_column_value(column)
|
|
240
|
+
end
|
|
241
|
+
|
|
239
242
|
super
|
|
240
243
|
end
|
|
241
244
|
end
|
|
@@ -146,6 +146,27 @@ module Sequel
|
|
|
146
146
|
ds
|
|
147
147
|
end
|
|
148
148
|
|
|
149
|
+
def lateral_subquery_filter_limit_strategy_conditions_key
|
|
150
|
+
qualify(reverse_edges.first[:table], reverse_edges.first[:left])
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def lateral_subquery_filter_limit_strategy_filter_lateral_dataset(ds)
|
|
154
|
+
ds.where(Array(qualify(edges.first[:table], edges.first[:right])).zip(Array(qualify(self[:model].table_name, edges.first[:left]))))
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def lateral_subquery_filter_limit_strategy_filter_dataset(ds, obj)
|
|
158
|
+
first_edge, *remaining_edges = edges
|
|
159
|
+
filter_ds = ds.db.from(first_edge[:table]).
|
|
160
|
+
select(*qualify(first_edge[:table], first_edge[:right])).
|
|
161
|
+
where(lateral_subquery_filter_limit_strategy_conditions(obj))
|
|
162
|
+
|
|
163
|
+
remaining_edges.each do |edge|
|
|
164
|
+
filter_ds = filter_ds.join(edge[:table], Array(edge[:right]).zip(Array(edge[:left])))
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
ds.where(qualify(self[:model].table_name, self[:left_primary_key]) => filter_ds)
|
|
168
|
+
end
|
|
169
|
+
|
|
149
170
|
# Make sure to use unique table aliases when lazy loading or eager loading
|
|
150
171
|
def calculate_reverse_edge_aliases(reverse_edges)
|
|
151
172
|
aliases = [associated_class.table_name]
|
|
@@ -55,7 +55,7 @@ module Sequel
|
|
|
55
55
|
def _update_without_checking(columns)
|
|
56
56
|
ds = _update_dataset
|
|
57
57
|
lc = model.lock_column
|
|
58
|
-
rows = ds.clone(ds.send(:default_server_opts, :sql=>ds.output(nil, [Sequel[:inserted][lc]]).update_sql(columns))).all
|
|
58
|
+
rows = ds.clone(ds.send(:default_server_opts, :sql=>ds.output(nil, [Sequel[:inserted][lc]]).update_sql(columns).freeze)).all
|
|
59
59
|
values[lc] = rows.first[lc] unless rows.empty?
|
|
60
60
|
rows.length
|
|
61
61
|
end
|
|
@@ -99,7 +99,7 @@ module Sequel
|
|
|
99
99
|
# Add an RETURNING clause to fetch the updated xmin when updating the row.
|
|
100
100
|
def _update_without_checking(columns)
|
|
101
101
|
ds = _update_dataset
|
|
102
|
-
rows = ds.clone(ds.send(:default_server_opts, :sql=>ds.returning(:xmin).update_sql(columns))).all
|
|
102
|
+
rows = ds.clone(ds.send(:default_server_opts, :sql=>ds.returning(:xmin).update_sql(columns).freeze)).all
|
|
103
103
|
values[:xmin] = rows.first[:xmin] unless rows.empty?
|
|
104
104
|
rows.length
|
|
105
105
|
end
|
|
@@ -30,6 +30,15 @@ module Sequel
|
|
|
30
30
|
# Otherwise, it is possible that the default column accessors will take
|
|
31
31
|
# precedence.
|
|
32
32
|
#
|
|
33
|
+
# Note that use of an unsafe serialization method can result in an attack vector
|
|
34
|
+
# (potentially allowing remote code execution) if an attacker has the ability to
|
|
35
|
+
# store data directly in the underlying column. This would affect the marshal
|
|
36
|
+
# serialization format, and on older versions of Ruby, potentially the yaml and
|
|
37
|
+
# json serialization formats as well. It can also affect custom formats. You
|
|
38
|
+
# should ensure that attackers do not have access to store data directly in the
|
|
39
|
+
# underlying column when using this plugin (especially when using an unsafe
|
|
40
|
+
# serialization method).
|
|
41
|
+
#
|
|
33
42
|
# == Example
|
|
34
43
|
#
|
|
35
44
|
# # Require json if you plan to use it, as the plugin doesn't require it for you.
|
|
@@ -97,7 +106,7 @@ module Sequel
|
|
|
97
106
|
register_format(:marshal, lambda{|v| [Marshal.dump(v)].pack('m')},
|
|
98
107
|
lambda do |v|
|
|
99
108
|
# Handle unpacked marshalled data for backwards compat
|
|
100
|
-
v = v.unpack('m')[0] unless v
|
|
109
|
+
v = v.unpack('m')[0] unless v.start_with?("\x04\x08")
|
|
101
110
|
Marshal.load(v)
|
|
102
111
|
end)
|
|
103
112
|
register_format(:yaml, :to_yaml.to_proc, lambda{|s| YAML.load(s)})
|
data/lib/sequel/version.rb
CHANGED
|
@@ -6,7 +6,7 @@ module Sequel
|
|
|
6
6
|
|
|
7
7
|
# The minor version of Sequel. Bumped for every non-patch level
|
|
8
8
|
# release, generally around once a month.
|
|
9
|
-
MINOR =
|
|
9
|
+
MINOR = 104
|
|
10
10
|
|
|
11
11
|
# The tiny version of Sequel. Usually 0, only bumped for bugfix
|
|
12
12
|
# releases that fix regressions from previous versions.
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sequel
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.
|
|
4
|
+
version: 5.104.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jeremy Evans
|
|
@@ -212,6 +212,7 @@ files:
|
|
|
212
212
|
- lib/sequel/extensions/blank.rb
|
|
213
213
|
- lib/sequel/extensions/caller_logging.rb
|
|
214
214
|
- lib/sequel/extensions/columns_introspection.rb
|
|
215
|
+
- lib/sequel/extensions/connection_checkout_event_callback.rb
|
|
215
216
|
- lib/sequel/extensions/connection_expiration.rb
|
|
216
217
|
- lib/sequel/extensions/connection_validator.rb
|
|
217
218
|
- lib/sequel/extensions/constant_sql_override.rb
|
|
@@ -240,6 +241,7 @@ files:
|
|
|
240
241
|
- lib/sequel/extensions/inflector.rb
|
|
241
242
|
- lib/sequel/extensions/integer64.rb
|
|
242
243
|
- lib/sequel/extensions/is_distinct_from.rb
|
|
244
|
+
- lib/sequel/extensions/lit_require_frozen.rb
|
|
243
245
|
- lib/sequel/extensions/looser_typecasting.rb
|
|
244
246
|
- lib/sequel/extensions/migration.rb
|
|
245
247
|
- lib/sequel/extensions/mssql_emulate_lateral_with_apply.rb
|