sequel 5.60.1 → 5.61.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cd8695696d6b55edf6337870f3ff172aeb6fe2ef9ba4bbc23daae0af26908649
4
- data.tar.gz: 2483bbb3549adbcb9f179165119051b7bb234d6e714e4afa116c0ffddf379dc6
3
+ metadata.gz: f542d5f0e7cca642a8fccd52cb4099101f38dbd1617ff2437b8690766b5f2bdd
4
+ data.tar.gz: 79ff2215f1e38e523e7e64a5779bee695a939a03f046a5e2e9a5974a804a714c
5
5
  SHA512:
6
- metadata.gz: 0527cba1fcc06d8001cbd55473b3af5c23a9f5c004113fc24aa6f9e029c5ed2cf4f938bf184d79922164cdc3ea502d12860d46d64237bdbd306bf5ce50f59ffa
7
- data.tar.gz: e13c17553592773e70c0e9a6753438444a5245f3cd0664c6c5a6c0a08a271d1d92180b110c7b7e5981f7ca6dc2b18d90da3feeb05a14ae863fcfd99d5673650e
6
+ metadata.gz: 1e0bdc80d388f1bdbf39674624522f7086ca5b0904df2bb28d7b6f3c8f6057df38eca1c0854905a87d920286e578d1e0fe269deb33c3c3f1691d2113a9f23d11
7
+ data.tar.gz: 31ebb15cc504b82c5406c2f7eb6a02a99aa035e9486ecd52698403eff7bd79a99e606229dbbf392ac3fabd1b68c9a7ebc09c127dea3970e2a083c7d781159f33
data/CHANGELOG CHANGED
@@ -1,3 +1,15 @@
1
+ === 5.61.0 (2022-10-01)
2
+
3
+ * Make Database#foreign_key_list on PostgreSQL return results for partitioned tables (jeremyevans)
4
+
5
+ * Add Database#check_string_typecast_bytesize for checking bytesize of strings before typecasting (jeremyevans)
6
+
7
+ * Treat negative hexidecimal strings similar to positive hexidecimal strings when typecasting to integer (jeremyevans)
8
+
9
+ * Remove is_json and is_not_json methods from the pg_json_ops extension, as the support was removed in PostgreSQL 15 beta 4 (jeremyevans)
10
+
11
+ * Fix handling of timestamps before the date of calendar reform when using pg_extended_date_support extension on Ruby 3.2 (jeremyevans)
12
+
1
13
  === 5.60.1 (2022-09-02)
2
14
 
3
15
  * Revert conversion of respond_to? to defined?, as it breaks with unused refinements on Ruby 2 (jeremyevans) (#1919)
@@ -0,0 +1,43 @@
1
+ = Improvements
2
+
3
+ * When typecasting strings to other types, Sequel::Database will now
4
+ by default not typecast strings that are much longer than expected
5
+ for the underlying type. Depending on the underlying type, there
6
+ is a limit of either 100 or 1000 bytes on the input string. This
7
+ avoids potential performance issues when trying to convert
8
+ arbitrary sized user input to specific types.
9
+
10
+ * The respond_to? to defined? change made in 5.60.0 was reverted in
11
+ 5.60.1 as it broke cases on Ruby < 3 where the object had an unused
12
+ refinement that added the method.
13
+
14
+ * When typecasting strings to integer, strings such as -0xa are now
15
+ treated as negative hexidecimal strings, similar to how 0xa is
16
+ treated as a positive hexidecimal string.
17
+
18
+ * Database#foreign_key_list now returns results for partitioned
19
+ tables on PostgreSQL 11+.
20
+
21
+ * Timestamps before the date of calendar reform are now handled
22
+ correctly by the pg_extended_date_support extension when using
23
+ Ruby 3.2 preview 2+.
24
+
25
+ = Backwards Compatibility
26
+
27
+ * The change to not typecast strings that are too long can break
28
+ backwards compatibility for applications that expect typecasting
29
+ for input beyond Sequel's limits. You can disable the string
30
+ bytesize checking by setting:
31
+
32
+ DB.check_string_typecast_bytesize = false
33
+
34
+ or by passing the check_string_typecast_bytesize: false option when
35
+ creating the Database instance.
36
+
37
+ * Code to workaround a bug in JRuby 9.2.0.0 has been removed from the
38
+ pg_extended_date_support extension. Users of the extension should
39
+ upgrade to a newer JRuby version.
40
+
41
+ * The is_json and is_not_json methods have been removed from the
42
+ pg_json_ops extension, as the underlying support was removed in
43
+ PostgreSQL 15 beta 4.
@@ -586,7 +586,7 @@ module Sequel
586
586
  join(Sequel[:pg_namespace].as(:nsp), :oid=>Sequel[:cl2][:relnamespace]).
587
587
  order{[co[:conname], cpos]}.
588
588
  where{{
589
- cl[:relkind]=>'r',
589
+ cl[:relkind]=>%w'r p',
590
590
  co[:contype]=>'f',
591
591
  cl[:oid]=>oid,
592
592
  cpos=>rpos
@@ -91,6 +91,11 @@ module Sequel
91
91
  # The specific default size of string columns for this Sequel::Database, usually 255 by default.
92
92
  attr_accessor :default_string_column_size
93
93
 
94
+ # Whether to check the bytesize of strings before typecasting (to avoid typecasting strings that
95
+ # would be too long for the given type), true by default. Strings that are too long will raise
96
+ # a typecasting error.
97
+ attr_accessor :check_string_typecast_bytesize
98
+
94
99
  # Constructs a new instance of a database connection with the specified
95
100
  # options hash.
96
101
  #
@@ -98,6 +103,7 @@ module Sequel
98
103
  # :before_preconnect :: Callable that runs after extensions from :preconnect_extensions are loaded,
99
104
  # but before any connections are created.
100
105
  # :cache_schema :: Whether schema should be cached for this Database instance
106
+ # :check_string_typecast_bytesize :: Whether to check the bytesize of strings before typecasting.
101
107
  # :default_string_column_size :: The default size of string columns, 255 by default.
102
108
  # :extensions :: Extensions to load into this Database instance. Can be a symbol, array of symbols,
103
109
  # or string with extensions separated by columns. These extensions are loaded after
@@ -107,7 +113,7 @@ module Sequel
107
113
  # :loggers :: An array of loggers to use.
108
114
  # :log_connection_info :: Whether connection information should be logged when logging queries.
109
115
  # :log_warn_duration :: The number of elapsed seconds after which queries should be logged at warn level.
110
- # :name :: A name to use for the Database object, displayed in PoolTimeout .
116
+ # :name :: A name to use for the Database object, displayed in PoolTimeout.
111
117
  # :preconnect :: Automatically create the maximum number of connections, so that they don't
112
118
  # need to be created as needed. This is useful when connecting takes a long time
113
119
  # and you want to avoid possible latency during runtime.
@@ -116,7 +122,7 @@ module Sequel
116
122
  # :preconnect_extensions :: Similar to the :extensions option, but loads the extensions before the
117
123
  # connections are made by the :preconnect option.
118
124
  # :quote_identifiers :: Whether to quote identifiers.
119
- # :servers :: A hash specifying a server/shard specific options, keyed by shard symbol .
125
+ # :servers :: A hash specifying a server/shard specific options, keyed by shard symbol.
120
126
  # :single_threaded :: Whether to use a single-threaded connection pool.
121
127
  # :sql_log_level :: Method to use to log SQL to a logger, :info by default.
122
128
  #
@@ -132,6 +138,7 @@ module Sequel
132
138
  @opts[:adapter_class] = self.class
133
139
  @opts[:single_threaded] = @single_threaded = typecast_value_boolean(@opts.fetch(:single_threaded, Sequel.single_threaded))
134
140
  @default_string_column_size = @opts[:default_string_column_size] || DEFAULT_STRING_COLUMN_SIZE
141
+ @check_string_typecast_bytesize = typecast_value_boolean(@opts.fetch(:check_string_typecast_bytesize, true))
135
142
 
136
143
  @schemas = {}
137
144
  @prepared_statements = {}
@@ -465,6 +472,21 @@ module Sequel
465
472
  # Don't rescue other exceptions, they will be raised normally.
466
473
  end
467
474
 
475
+ # Check the bytesize of a string before conversion. There is no point
476
+ # trying to typecast strings that would be way too long.
477
+ def typecast_check_string_length(string, max_size)
478
+ if @check_string_typecast_bytesize && string.bytesize > max_size
479
+ raise InvalidValue, "string too long to typecast (bytesize: #{string.bytesize}, max: #{max_size})"
480
+ end
481
+ string
482
+ end
483
+
484
+ # Check the bytesize of the string value, if value is a string.
485
+ def typecast_check_length(value, max_size)
486
+ typecast_check_string_length(value, max_size) if String === value
487
+ value
488
+ end
489
+
468
490
  # Typecast the value to an SQL::Blob
469
491
  def typecast_value_blob(value)
470
492
  value.is_a?(Sequel::SQL::Blob) ? value : Sequel::SQL::Blob.new(value)
@@ -488,9 +510,9 @@ module Sequel
488
510
  when Date
489
511
  value
490
512
  when String
491
- Sequel.string_to_date(value)
513
+ Sequel.string_to_date(typecast_check_string_length(value, 100))
492
514
  when Hash
493
- Date.new(*[:year, :month, :day].map{|x| (value[x] || value[x.to_s]).to_i})
515
+ Date.new(*[:year, :month, :day].map{|x| typecast_check_length(value[x] || value[x.to_s], 100).to_i})
494
516
  else
495
517
  raise InvalidValue, "invalid value for Date: #{value.inspect}"
496
518
  end
@@ -498,7 +520,17 @@ module Sequel
498
520
 
499
521
  # Typecast the value to a DateTime or Time depending on Sequel.datetime_class
500
522
  def typecast_value_datetime(value)
501
- Sequel.typecast_to_application_timestamp(value)
523
+ case value
524
+ when String
525
+ Sequel.typecast_to_application_timestamp(typecast_check_string_length(value, 100))
526
+ when Hash
527
+ [:year, :month, :day, :hour, :minute, :second, :nanos, :offset].each do |x|
528
+ typecast_check_length(value[x] || value[x.to_s], 100)
529
+ end
530
+ Sequel.typecast_to_application_timestamp(value)
531
+ else
532
+ Sequel.typecast_to_application_timestamp(value)
533
+ end
502
534
  end
503
535
 
504
536
  if RUBY_VERSION >= '2.4'
@@ -531,18 +563,30 @@ module Sequel
531
563
  when Numeric
532
564
  BigDecimal(value.to_s)
533
565
  when String
534
- _typecast_value_string_to_decimal(value)
566
+ _typecast_value_string_to_decimal(typecast_check_string_length(value, 1000))
535
567
  else
536
568
  raise InvalidValue, "invalid value for BigDecimal: #{value.inspect}"
537
569
  end
538
570
  end
539
571
 
540
572
  # Typecast the value to a Float
541
- alias typecast_value_float Float
573
+ def typecast_value_float(value)
574
+ Float(typecast_check_length(value, 1000))
575
+ end
542
576
 
543
577
  # Typecast the value to an Integer
544
578
  def typecast_value_integer(value)
545
- (value.is_a?(String) && value =~ /\A0+(\d)/) ? Integer(value, 10) : Integer(value)
579
+ case value
580
+ when String
581
+ typecast_check_string_length(value, 100)
582
+ if value =~ /\A-?0+(\d)/
583
+ Integer(value, 10)
584
+ else
585
+ Integer(value)
586
+ end
587
+ else
588
+ Integer(value)
589
+ end
546
590
  end
547
591
 
548
592
  # Typecast the value to a String
@@ -565,9 +609,9 @@ module Sequel
565
609
  SQLTime.create(value.hour, value.min, value.sec, value.nsec/1000.0)
566
610
  end
567
611
  when String
568
- Sequel.string_to_time(value)
612
+ Sequel.string_to_time(typecast_check_string_length(value, 100))
569
613
  when Hash
570
- SQLTime.create(*[:hour, :minute, :second].map{|x| (value[x] || value[x.to_s]).to_i})
614
+ SQLTime.create(*[:hour, :minute, :second].map{|x| typecast_check_length(value[x] || value[x.to_s], 100).to_i})
571
615
  else
572
616
  raise Sequel::InvalidValue, "invalid value for Time: #{value.inspect}"
573
617
  end
@@ -8,6 +8,9 @@
8
8
  # :decimal :: use 0.0 for unsupported strings
9
9
  # :string :: silently allow hash and array conversion to string
10
10
  #
11
+ # This also removes bytesize checks for string inputs for float, integer
12
+ # and decimal conversions.
13
+ #
11
14
  # To load the extension into the database:
12
15
  #
13
16
  # DB.extension :looser_typecasting
@@ -29,6 +29,8 @@ module Sequel
29
29
  INFINITE_DATETIME_VALUES = ([PLUS_INFINITY, MINUS_INFINITY] + INFINITE_TIMESTAMP_STRINGS).freeze
30
30
  PLUS_DATE_INFINITY = Date::Infinity.new
31
31
  MINUS_DATE_INFINITY = -PLUS_DATE_INFINITY
32
+ RATIONAL_60 = Rational(60)
33
+ TIME_CAN_PARSE_BC = RUBY_VERSION >= '2.5'
32
34
 
33
35
  # Add dataset methods and update the conversion proces for dates and timestamps.
34
36
  def self.extended(db)
@@ -86,27 +88,18 @@ module Sequel
86
88
  if value.is_a?(String) && (m = /((?:[-+]\d\d:\d\d)(:\d\d)?)?( BC)?\z/.match(value)) && (m[2] || m[3])
87
89
  if m[3]
88
90
  value = value.sub(' BC', '').sub(' ', ' BC ')
89
- conv = defined?(JRUBY_VERSION) && JRUBY_VERSION == '9.2.0.0'
90
91
  end
91
- if m[2] || conv
92
- dt = DateTime.parse(value)
93
- if conv
94
- # :nocov:
95
- if Sequel.datetime_class == DateTime
96
- dt >>= 12
97
- else
98
- dt >>= 24
99
- end
100
- # :nocov:
101
- end
102
- unless Sequel.datetime_class == DateTime
103
- dt = dt.to_time
104
- if conv && (timezone == nil || timezone == :local) && !m[1]
105
- # :nocov:
106
- dt = Sequel.send(:convert_input_timestamp, dt.strftime("%F %T.%6N"), :local)
107
- # :nocov:
108
- end
92
+ if m[2]
93
+ dt = if Sequel.datetime_class == DateTime
94
+ DateTime.parse(value)
95
+ elsif TIME_CAN_PARSE_BC
96
+ Time.parse(value)
97
+ # :nocov:
98
+ else
99
+ DateTime.parse(value).to_time
100
+ # :nocov:
109
101
  end
102
+
110
103
  Sequel.convert_output_timestamp(dt, Sequel.application_timezone)
111
104
  else
112
105
  super(value)
@@ -223,10 +216,7 @@ module Sequel
223
216
  # Work around JRuby bug #4822 in Time#to_datetime for times before date of calendar reform
224
217
  def literal_time(time)
225
218
  if time < TIME_YEAR_1
226
- dt = DateTime.parse(super)
227
- # Work around JRuby bug #5191
228
- dt >>= 12 if JRUBY_VERSION == '9.2.0.0'
229
- literal_datetime(dt)
219
+ literal_datetime(DateTime.parse(super))
230
220
  else
231
221
  super
232
222
  end
@@ -236,7 +226,8 @@ module Sequel
236
226
  # Handle BC Time objects.
237
227
  def literal_time(time)
238
228
  if time < TIME_YEAR_1
239
- literal_datetime(time.to_datetime)
229
+ time = db.from_application_timestamp(time)
230
+ time.strftime("'#{sprintf('%04i', time.year.abs+1)}-%m-%d %H:%M:%S.%N#{format_timestamp_offset(*(time.utc_offset/RATIONAL_60).divmod(60))} BC'")
240
231
  else
241
232
  super
242
233
  end
@@ -111,7 +111,7 @@ module Sequel
111
111
  when IPAddr
112
112
  value
113
113
  when String
114
- IPAddr.new(value)
114
+ IPAddr.new(typecast_check_string_length(value, 100))
115
115
  else
116
116
  raise Sequel::InvalidValue, "invalid value for inet/cidr: #{value.inspect}"
117
117
  end
@@ -197,7 +197,7 @@ module Sequel
197
197
  when Numeric
198
198
  ActiveSupport::Duration.new(value, [[:seconds, value]])
199
199
  when String
200
- PARSER.call(value)
200
+ PARSER.call(typecast_check_string_length(value, 1000))
201
201
  else
202
202
  raise Sequel::InvalidValue, "invalid value for interval type: #{value.inspect}"
203
203
  end
@@ -123,15 +123,6 @@
123
123
  # c = Sequel.pg_jsonb_op(:c)
124
124
  # DB[:t].update(c['key1'] => 1.to_json, c['key2'] => "a".to_json)
125
125
  #
126
- # On PostgreSQL 15+, the <tt>IS [NOT] JSON</tt> operator is supported:
127
- #
128
- # j.is_json # j IS JSON
129
- # j.is_json(type: :object) # j IS JSON OBJECT
130
- # j.is_json(type: :object, unique: true) # j IS JSON OBJECT WITH UNIQUE
131
- # j.is_not_json # j IS NOT JSON
132
- # j.is_json(type: :array) # j IS NOT JSON ARRAY
133
- # j.is_json(unique: true) # j IS NOT JSON WITH UNIQUE
134
- #
135
126
  # If you are also using the pg_json extension, you should load it before
136
127
  # loading this extension. Doing so will allow you to use the #op method on
137
128
  # JSONHash, JSONHarray, JSONBHash, and JSONBArray, allowing you to perform json/jsonb operations
@@ -160,18 +151,6 @@ module Sequel
160
151
  GET_PATH = ["(".freeze, " #> ".freeze, ")".freeze].freeze
161
152
  GET_PATH_TEXT = ["(".freeze, " #>> ".freeze, ")".freeze].freeze
162
153
 
163
- IS_JSON = ["(".freeze, " IS JSON".freeze, "".freeze, ")".freeze].freeze
164
- IS_NOT_JSON = ["(".freeze, " IS NOT JSON".freeze, "".freeze, ")".freeze].freeze
165
- EMPTY_STRING = Sequel::LiteralString.new('').freeze
166
- WITH_UNIQUE = Sequel::LiteralString.new(' WITH UNIQUE').freeze
167
- IS_JSON_MAP = {
168
- nil => EMPTY_STRING,
169
- :value => Sequel::LiteralString.new(' VALUE').freeze,
170
- :scalar => Sequel::LiteralString.new(' SCALAR').freeze,
171
- :object => Sequel::LiteralString.new(' OBJECT').freeze,
172
- :array => Sequel::LiteralString.new(' ARRAY').freeze
173
- }.freeze
174
-
175
154
  # Get JSON array element or object field as json. If an array is given,
176
155
  # gets the object at the specified path.
177
156
  #
@@ -254,30 +233,6 @@ module Sequel
254
233
  end
255
234
  end
256
235
 
257
- # Return whether the json object can be parsed as JSON.
258
- #
259
- # Options:
260
- # :type :: Check whether the json object can be parsed as a specific type
261
- # of JSON (:value, :scalar, :object, :array).
262
- # :unique :: Check JSON objects for unique keys.
263
- #
264
- # json_op.is_json # json IS JSON
265
- # json_op.is_json(type: :object) # json IS JSON OBJECT
266
- # json_op.is_json(unique: true) # json IS JSON WITH UNIQUE
267
- def is_json(opts=OPTS)
268
- _is_json(IS_JSON, opts)
269
- end
270
-
271
- # Return whether the json object cannot be parsed as JSON. The opposite
272
- # of #is_json. See #is_json for options.
273
- #
274
- # json_op.is_not_json # json IS NOT JSON
275
- # json_op.is_not_json(type: :object) # json IS NOT JSON OBJECT
276
- # json_op.is_not_json(unique: true) # json IS NOT JSON WITH UNIQUE
277
- def is_not_json(opts=OPTS)
278
- _is_json(IS_NOT_JSON, opts)
279
- end
280
-
281
236
  # Returns a set of keys AS text in the json object.
282
237
  #
283
238
  # json_op.keys # json_object_keys(json)
@@ -331,13 +286,6 @@ module Sequel
331
286
 
332
287
  private
333
288
 
334
- # Internals of IS [NOT] JSON support
335
- def _is_json(lit_array, opts)
336
- raise Error, "invalid is_json :type option: #{opts[:type].inspect}" unless type = IS_JSON_MAP[opts[:type]]
337
- unique = opts[:unique] ? WITH_UNIQUE : EMPTY_STRING
338
- Sequel::SQL::BooleanExpression.new(:NOOP, Sequel::SQL::PlaceholderLiteralString.new(lit_array, [self, type, unique]))
339
- end
340
-
341
289
  # Return a placeholder literal with the given str and args, wrapped
342
290
  # in an JSONOp or JSONBOp, used by operators that return json or jsonb.
343
291
  def json_op(str, args)
@@ -282,7 +282,7 @@ module Sequel
282
282
  when Range
283
283
  PGRange.from_range(value, parser.db_type)
284
284
  when String
285
- parser.call(value)
285
+ parser.call(typecast_check_string_length(value, 100))
286
286
  else
287
287
  raise Sequel::InvalidValue, "invalid value for range type: #{value.inspect}"
288
288
  end
@@ -6,11 +6,11 @@ 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 = 60
9
+ MINOR = 61
10
10
 
11
11
  # The tiny version of Sequel. Usually 0, only bumped for bugfix
12
12
  # releases that fix regressions from previous versions.
13
- TINY = 1
13
+ TINY = 0
14
14
 
15
15
  # The version of Sequel you are using, as a string (e.g. "2.11.0")
16
16
  VERSION = [MAJOR, MINOR, TINY].join('.').freeze
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sequel
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.60.1
4
+ version: 5.61.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-09-02 00:00:00.000000000 Z
11
+ date: 2022-10-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -192,6 +192,7 @@ extra_rdoc_files:
192
192
  - doc/release_notes/5.59.0.txt
193
193
  - doc/release_notes/5.6.0.txt
194
194
  - doc/release_notes/5.60.0.txt
195
+ - doc/release_notes/5.61.0.txt
195
196
  - doc/release_notes/5.7.0.txt
196
197
  - doc/release_notes/5.8.0.txt
197
198
  - doc/release_notes/5.9.0.txt
@@ -280,6 +281,7 @@ files:
280
281
  - doc/release_notes/5.59.0.txt
281
282
  - doc/release_notes/5.6.0.txt
282
283
  - doc/release_notes/5.60.0.txt
284
+ - doc/release_notes/5.61.0.txt
283
285
  - doc/release_notes/5.7.0.txt
284
286
  - doc/release_notes/5.8.0.txt
285
287
  - doc/release_notes/5.9.0.txt