activerecord6-redshift-adapter 1.1.2 → 1.1.3
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 +5 -5
- data/lib/active_record/connection_adapters/redshift/database_statements.rb +8 -2
- data/lib/active_record/connection_adapters/redshift/schema_definitions.rb +2 -2
- data/lib/active_record/connection_adapters/redshift/schema_statements.rb +4 -4
- data/lib/active_record/connection_adapters/redshift_adapter.rb +189 -94
- metadata +9 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: aed3175ea88bb9b6b163ffc7b198768b81c16330dc1d7b480d7d1a17356f6033
|
4
|
+
data.tar.gz: 66de7284e67e34a05bbd376be4cd8c3ee0a0c3b7565db16229a7c1512eb0de41
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c840dd282c228c3aab781e770ac40a8c5a2ee3ddb71c6d380f27cf6a9c411ed3ff5c659cfa6dbaa768da6db58dadbdefec8736309f4cff360a5639fcf2c83c96
|
7
|
+
data.tar.gz: bce5739dd4b207c1c92f726b80ad0a920eeb04b3f5d76800e5ff0121bd3a2c79474a967795c6ca4c7d567b6c8654dd9620188aa8397f0ee0a38886a072eb0439
|
@@ -47,9 +47,12 @@ module ActiveRecord
|
|
47
47
|
def select_value(arel, name = nil, binds = [])
|
48
48
|
# In Rails 5.2, arel_from_relation replaced binds_from_relation,
|
49
49
|
# so we see which method exists to get the variables
|
50
|
+
#
|
51
|
+
# In Rails 6.0 to_sql_and_binds began only returning sql, with
|
52
|
+
# to_sql_and_binds serving as a replacement
|
50
53
|
if respond_to?(:arel_from_relation, true)
|
51
54
|
arel = arel_from_relation(arel)
|
52
|
-
sql, binds =
|
55
|
+
sql, binds = to_sql_and_binds(arel, binds)
|
53
56
|
else
|
54
57
|
arel, binds = binds_from_relation arel, binds
|
55
58
|
sql = to_sql(arel, binds)
|
@@ -62,9 +65,12 @@ module ActiveRecord
|
|
62
65
|
def select_values(arel, name = nil)
|
63
66
|
# In Rails 5.2, arel_from_relation replaced binds_from_relation,
|
64
67
|
# so we see which method exists to get the variables
|
68
|
+
#
|
69
|
+
# In Rails 6.0 to_sql_and_binds began only returning sql, with
|
70
|
+
# to_sql_and_binds serving as a replacement
|
65
71
|
if respond_to?(:arel_from_relation, true)
|
66
72
|
arel = arel_from_relation(arel)
|
67
|
-
sql, binds =
|
73
|
+
sql, binds = to_sql_and_binds(arel, [])
|
68
74
|
else
|
69
75
|
arel, binds = binds_from_relation arel, []
|
70
76
|
sql = to_sql(arel, binds)
|
@@ -5,7 +5,7 @@ module ActiveRecord
|
|
5
5
|
private
|
6
6
|
|
7
7
|
def visit_ColumnDefinition(o)
|
8
|
-
o.sql_type = type_to_sql(o.type, o.limit, o.precision, o.scale)
|
8
|
+
o.sql_type = type_to_sql(o.type, limit: o.limit, precision: o.precision, scale: o.scale)
|
9
9
|
super
|
10
10
|
end
|
11
11
|
|
@@ -277,11 +277,11 @@ module ActiveRecord
|
|
277
277
|
def change_column(table_name, column_name, type, options = {})
|
278
278
|
clear_cache!
|
279
279
|
quoted_table_name = quote_table_name(table_name)
|
280
|
-
sql_type = type_to_sql(type, options[:limit], options[:precision], options[:scale])
|
280
|
+
sql_type = type_to_sql(type, limit: options[:limit], precision: options[:precision], scale: options[:scale])
|
281
281
|
sql = "ALTER TABLE #{quoted_table_name} ALTER COLUMN #{quote_column_name(column_name)} TYPE #{sql_type}"
|
282
282
|
sql << " USING #{options[:using]}" if options[:using]
|
283
283
|
if options[:cast_as]
|
284
|
-
sql << " USING CAST(#{quote_column_name(column_name)} AS #{type_to_sql(options[:cast_as], options[:limit], options[:precision], options[:scale])})"
|
284
|
+
sql << " USING CAST(#{quote_column_name(column_name)} AS #{type_to_sql(options[:cast_as], limit: options[:limit], precision: options[:precision], scale: options[:scale])})"
|
285
285
|
end
|
286
286
|
execute sql
|
287
287
|
|
@@ -372,7 +372,7 @@ module ActiveRecord
|
|
372
372
|
end
|
373
373
|
|
374
374
|
# Maps logical Rails types to PostgreSQL-specific data types.
|
375
|
-
def type_to_sql(type, limit
|
375
|
+
def type_to_sql(type, limit: nil, precision: nil, scale: nil, **)
|
376
376
|
case type.to_s
|
377
377
|
when 'integer'
|
378
378
|
return 'integer' unless limit
|
@@ -12,10 +12,14 @@ require 'active_record/connection_adapters/redshift/schema_statements'
|
|
12
12
|
require 'active_record/connection_adapters/redshift/type_metadata'
|
13
13
|
require 'active_record/connection_adapters/redshift/database_statements'
|
14
14
|
|
15
|
+
require 'active_record/tasks/database_tasks'
|
16
|
+
|
15
17
|
require 'pg'
|
16
18
|
|
17
19
|
require 'ipaddr'
|
18
20
|
|
21
|
+
ActiveRecord::Tasks::DatabaseTasks.register_task(/redshift/, "ActiveRecord::Tasks::PostgreSQLDatabaseTasks")
|
22
|
+
|
19
23
|
module ActiveRecord
|
20
24
|
module ConnectionHandling # :nodoc:
|
21
25
|
RS_VALID_CONN_PARAMS = [:host, :hostaddr, :port, :dbname, :user, :password, :connect_timeout,
|
@@ -78,10 +82,10 @@ module ActiveRecord
|
|
78
82
|
string: { name: "varchar" },
|
79
83
|
text: { name: "varchar" },
|
80
84
|
integer: { name: "integer" },
|
81
|
-
float: { name: "
|
85
|
+
float: { name: "decimal" },
|
82
86
|
decimal: { name: "decimal" },
|
83
87
|
datetime: { name: "timestamp" },
|
84
|
-
time: { name: "
|
88
|
+
time: { name: "timestamp" },
|
85
89
|
date: { name: "date" },
|
86
90
|
bigint: { name: "bigint" },
|
87
91
|
boolean: { name: "boolean" },
|
@@ -122,55 +126,29 @@ module ActiveRecord
|
|
122
126
|
{ concurrently: 'CONCURRENTLY' }
|
123
127
|
end
|
124
128
|
|
125
|
-
class StatementPool < ConnectionAdapters::StatementPool
|
129
|
+
class StatementPool < ConnectionAdapters::StatementPool # :nodoc:
|
126
130
|
def initialize(connection, max)
|
127
131
|
super(max)
|
128
132
|
@connection = connection
|
129
133
|
@counter = 0
|
130
|
-
@cache = Hash.new { |h,pid| h[pid] = {} }
|
131
134
|
end
|
132
135
|
|
133
|
-
def each(&block); cache.each(&block); end
|
134
|
-
def key?(key); cache.key?(key); end
|
135
|
-
def [](key); cache[key]; end
|
136
|
-
def length; cache.length; end
|
137
|
-
|
138
136
|
def next_key
|
139
137
|
"a#{@counter + 1}"
|
140
138
|
end
|
141
139
|
|
142
140
|
def []=(sql, key)
|
143
|
-
|
144
|
-
dealloc(cache.shift.last)
|
145
|
-
end
|
146
|
-
@counter += 1
|
147
|
-
cache[sql] = key
|
148
|
-
end
|
149
|
-
|
150
|
-
def clear
|
151
|
-
cache.each_value do |stmt_key|
|
152
|
-
dealloc stmt_key
|
153
|
-
end
|
154
|
-
cache.clear
|
155
|
-
end
|
156
|
-
|
157
|
-
def delete(sql_key)
|
158
|
-
dealloc cache[sql_key]
|
159
|
-
cache.delete sql_key
|
141
|
+
super.tap { @counter += 1 }
|
160
142
|
end
|
161
143
|
|
162
144
|
private
|
163
|
-
|
164
|
-
def cache
|
165
|
-
@cache[Process.pid]
|
166
|
-
end
|
167
|
-
|
168
145
|
def dealloc(key)
|
169
146
|
@connection.query "DEALLOCATE #{key}" if connection_active?
|
147
|
+
rescue PG::Error
|
170
148
|
end
|
171
149
|
|
172
150
|
def connection_active?
|
173
|
-
@connection.status == PG::
|
151
|
+
@connection.status == PG::CONNECTION_OK
|
174
152
|
rescue PG::Error
|
175
153
|
false
|
176
154
|
end
|
@@ -255,14 +233,6 @@ module ActiveRecord
|
|
255
233
|
true
|
256
234
|
end
|
257
235
|
|
258
|
-
# Enable standard-conforming strings if available.
|
259
|
-
def set_standard_conforming_strings
|
260
|
-
old, self.client_min_messages = client_min_messages, 'panic'
|
261
|
-
execute('SET standard_conforming_strings = on', 'SCHEMA') rescue nil
|
262
|
-
ensure
|
263
|
-
self.client_min_messages = old
|
264
|
-
end
|
265
|
-
|
266
236
|
def supports_ddl_transactions?
|
267
237
|
true
|
268
238
|
end
|
@@ -342,7 +312,7 @@ module ActiveRecord
|
|
342
312
|
@connection.server_version
|
343
313
|
end
|
344
314
|
|
345
|
-
def translate_exception(exception, message)
|
315
|
+
def translate_exception(exception, message:, sql:, binds:)
|
346
316
|
return exception unless exception.respond_to?(:result)
|
347
317
|
|
348
318
|
case exception.message
|
@@ -496,39 +466,68 @@ module ActiveRecord
|
|
496
466
|
ret
|
497
467
|
end
|
498
468
|
|
469
|
+
|
499
470
|
def exec_no_cache(sql, name, binds)
|
500
|
-
|
471
|
+
materialize_transactions
|
472
|
+
|
473
|
+
# make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
|
474
|
+
# made since we established the connection
|
475
|
+
update_typemap_for_default_timezone
|
476
|
+
|
477
|
+
type_casted_binds = type_casted_binds(binds)
|
478
|
+
log(sql, name, binds, type_casted_binds) do
|
479
|
+
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
480
|
+
@connection.exec_params(sql, type_casted_binds)
|
481
|
+
end
|
482
|
+
end
|
501
483
|
end
|
502
484
|
|
503
485
|
def exec_cache(sql, name, binds)
|
504
|
-
|
505
|
-
|
506
|
-
[col, type_cast(val, col)]
|
507
|
-
}
|
486
|
+
materialize_transactions
|
487
|
+
update_typemap_for_default_timezone
|
508
488
|
|
509
|
-
|
510
|
-
|
489
|
+
stmt_key = prepare_statement(sql, binds)
|
490
|
+
type_casted_binds = type_casted_binds(binds)
|
491
|
+
|
492
|
+
log(sql, name, binds, type_casted_binds, stmt_key) do
|
493
|
+
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
494
|
+
@connection.exec_prepared(stmt_key, type_casted_binds)
|
495
|
+
end
|
511
496
|
end
|
512
497
|
rescue ActiveRecord::StatementInvalid => e
|
513
|
-
|
514
|
-
|
515
|
-
#
|
516
|
-
#
|
517
|
-
|
518
|
-
|
519
|
-
begin
|
520
|
-
code = pgerror.result.result_error_field(PG::Result::PG_DIAG_SQLSTATE)
|
521
|
-
rescue
|
522
|
-
raise e
|
523
|
-
end
|
524
|
-
if FEATURE_NOT_SUPPORTED == code
|
525
|
-
@statements.delete sql_key(sql)
|
526
|
-
retry
|
498
|
+
raise unless is_cached_plan_failure?(e)
|
499
|
+
|
500
|
+
# Nothing we can do if we are in a transaction because all commands
|
501
|
+
# will raise InFailedSQLTransaction
|
502
|
+
if in_transaction?
|
503
|
+
raise ActiveRecord::PreparedStatementCacheExpired.new(e.cause.message)
|
527
504
|
else
|
528
|
-
|
505
|
+
@lock.synchronize do
|
506
|
+
# outside of transactions we can simply flush this query and retry
|
507
|
+
@statements.delete sql_key(sql)
|
508
|
+
end
|
509
|
+
retry
|
529
510
|
end
|
530
511
|
end
|
531
512
|
|
513
|
+
# Annoyingly, the code for prepared statements whose return value may
|
514
|
+
# have changed is FEATURE_NOT_SUPPORTED.
|
515
|
+
#
|
516
|
+
# This covers various different error types so we need to do additional
|
517
|
+
# work to classify the exception definitively as a
|
518
|
+
# ActiveRecord::PreparedStatementCacheExpired
|
519
|
+
#
|
520
|
+
# Check here for more details:
|
521
|
+
# https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/cache/plancache.c#l573
|
522
|
+
CACHED_PLAN_HEURISTIC = "cached plan must not change result type"
|
523
|
+
def is_cached_plan_failure?(e)
|
524
|
+
pgerror = e.cause
|
525
|
+
code = pgerror.result.result_error_field(PG::PG_DIAG_SQLSTATE)
|
526
|
+
code == FEATURE_NOT_SUPPORTED && pgerror.message.include?(CACHED_PLAN_HEURISTIC)
|
527
|
+
rescue
|
528
|
+
false
|
529
|
+
end
|
530
|
+
|
532
531
|
# Returns the statement identifier for the client side cache
|
533
532
|
# of statements
|
534
533
|
def sql_key(sql)
|
@@ -537,34 +536,31 @@ module ActiveRecord
|
|
537
536
|
|
538
537
|
# Prepare the statement if it hasn't been prepared, return
|
539
538
|
# the statement key.
|
540
|
-
def prepare_statement(sql)
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
539
|
+
def prepare_statement(sql, binds)
|
540
|
+
@lock.synchronize do
|
541
|
+
sql_key = sql_key(sql)
|
542
|
+
unless @statements.key? sql_key
|
543
|
+
nextkey = @statements.next_key
|
544
|
+
begin
|
545
|
+
@connection.prepare nextkey, sql
|
546
|
+
rescue => e
|
547
|
+
raise translate_exception_class(e, sql, binds)
|
548
|
+
end
|
549
|
+
# Clear the queue
|
550
|
+
@connection.get_last_result
|
551
|
+
@statements[sql_key] = nextkey
|
548
552
|
end
|
549
|
-
|
550
|
-
@connection.get_last_result
|
551
|
-
@statements[sql_key] = nextkey
|
553
|
+
@statements[sql_key]
|
552
554
|
end
|
553
|
-
@statements[sql_key]
|
554
555
|
end
|
555
556
|
|
556
557
|
# Connects to a PostgreSQL server and sets up the adapter depending on the
|
557
558
|
# connected server's characteristics.
|
558
559
|
def connect
|
559
|
-
@connection = PG
|
560
|
-
|
560
|
+
@connection = PG.connect(@connection_parameters)
|
561
561
|
configure_connection
|
562
|
-
|
563
|
-
|
564
|
-
raise ActiveRecord::NoDatabaseError.new(error.message, error)
|
565
|
-
else
|
566
|
-
raise
|
567
|
-
end
|
562
|
+
add_pg_encoders
|
563
|
+
add_pg_decoders
|
568
564
|
end
|
569
565
|
|
570
566
|
# Configures the encoding, verbosity, schema search path, and time zone of the connection.
|
@@ -575,17 +571,18 @@ module ActiveRecord
|
|
575
571
|
end
|
576
572
|
self.schema_search_path = @config[:schema_search_path] || @config[:schema_order]
|
577
573
|
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
elsif
|
586
|
-
|
574
|
+
variables = @config.fetch(:variables, {}).stringify_keys
|
575
|
+
|
576
|
+
# If using Active Record's time zone support configure the connection to return
|
577
|
+
# TIMESTAMP WITH ZONE types in UTC.
|
578
|
+
unless variables["timezone"]
|
579
|
+
if ActiveRecord::Base.default_timezone == :utc
|
580
|
+
variables["timezone"] = "UTC"
|
581
|
+
elsif @local_tz
|
582
|
+
variables["timezone"] = @local_tz
|
587
583
|
end
|
588
584
|
end
|
585
|
+
|
589
586
|
end
|
590
587
|
|
591
588
|
def last_insert_id_result(sequence_name) #:nodoc:
|
@@ -622,13 +619,111 @@ module ActiveRecord
|
|
622
619
|
end_sql
|
623
620
|
end
|
624
621
|
|
625
|
-
def extract_table_ref_from_insert_sql(sql)
|
622
|
+
def extract_table_ref_from_insert_sql(sql)
|
626
623
|
sql[/into\s("[A-Za-z0-9_."\[\]\s]+"|[A-Za-z0-9_."\[\]]+)\s*/im]
|
627
624
|
$1.strip if $1
|
628
625
|
end
|
629
626
|
|
627
|
+
def arel_visitor
|
628
|
+
Arel::Visitors::PostgreSQL.new(self)
|
629
|
+
end
|
630
|
+
|
631
|
+
def build_statement_pool
|
632
|
+
StatementPool.new(@connection, self.class.type_cast_config_to_integer(@config[:statement_limit]))
|
633
|
+
end
|
634
|
+
|
635
|
+
|
636
|
+
def can_perform_case_insensitive_comparison_for?(column)
|
637
|
+
@case_insensitive_cache ||= {}
|
638
|
+
@case_insensitive_cache[column.sql_type] ||= begin
|
639
|
+
sql = <<~SQL
|
640
|
+
SELECT exists(
|
641
|
+
SELECT * FROM pg_proc
|
642
|
+
WHERE proname = 'lower'
|
643
|
+
AND proargtypes = ARRAY[#{quote column.sql_type}::regtype]::oidvector
|
644
|
+
) OR exists(
|
645
|
+
SELECT * FROM pg_proc
|
646
|
+
INNER JOIN pg_cast
|
647
|
+
ON ARRAY[casttarget]::oidvector = proargtypes
|
648
|
+
WHERE proname = 'lower'
|
649
|
+
AND castsource = #{quote column.sql_type}::regtype
|
650
|
+
)
|
651
|
+
SQL
|
652
|
+
execute_and_clear(sql, "SCHEMA", []) do |result|
|
653
|
+
result.getvalue(0, 0)
|
654
|
+
end
|
655
|
+
end
|
656
|
+
end
|
657
|
+
|
658
|
+
def add_pg_encoders
|
659
|
+
map = PG::TypeMapByClass.new
|
660
|
+
map[Integer] = PG::TextEncoder::Integer.new
|
661
|
+
map[TrueClass] = PG::TextEncoder::Boolean.new
|
662
|
+
map[FalseClass] = PG::TextEncoder::Boolean.new
|
663
|
+
@connection.type_map_for_queries = map
|
664
|
+
end
|
665
|
+
|
666
|
+
def update_typemap_for_default_timezone
|
667
|
+
if @default_timezone != ActiveRecord::Base.default_timezone && @timestamp_decoder
|
668
|
+
decoder_class = ActiveRecord::Base.default_timezone == :utc ?
|
669
|
+
PG::TextDecoder::TimestampUtc :
|
670
|
+
PG::TextDecoder::TimestampWithoutTimeZone
|
671
|
+
|
672
|
+
@timestamp_decoder = decoder_class.new(@timestamp_decoder.to_h)
|
673
|
+
@connection.type_map_for_results.add_coder(@timestamp_decoder)
|
674
|
+
@default_timezone = ActiveRecord::Base.default_timezone
|
675
|
+
end
|
676
|
+
end
|
677
|
+
|
678
|
+
|
679
|
+
def add_pg_decoders
|
680
|
+
@default_timezone = nil
|
681
|
+
@timestamp_decoder = nil
|
682
|
+
|
683
|
+
coders_by_name = {
|
684
|
+
"int2" => PG::TextDecoder::Integer,
|
685
|
+
"int4" => PG::TextDecoder::Integer,
|
686
|
+
"int8" => PG::TextDecoder::Integer,
|
687
|
+
"oid" => PG::TextDecoder::Integer,
|
688
|
+
"float4" => PG::TextDecoder::Float,
|
689
|
+
"float8" => PG::TextDecoder::Float,
|
690
|
+
"bool" => PG::TextDecoder::Boolean,
|
691
|
+
}
|
692
|
+
|
693
|
+
if defined?(PG::TextDecoder::TimestampUtc)
|
694
|
+
# Use native PG encoders available since pg-1.1
|
695
|
+
coders_by_name["timestamp"] = PG::TextDecoder::TimestampUtc
|
696
|
+
coders_by_name["timestamptz"] = PG::TextDecoder::TimestampWithTimeZone
|
697
|
+
end
|
698
|
+
|
699
|
+
known_coder_types = coders_by_name.keys.map { |n| quote(n) }
|
700
|
+
query = <<~SQL % known_coder_types.join(", ")
|
701
|
+
SELECT t.oid, t.typname
|
702
|
+
FROM pg_type as t
|
703
|
+
WHERE t.typname IN (%s)
|
704
|
+
SQL
|
705
|
+
coders = execute_and_clear(query, "SCHEMA", []) do |result|
|
706
|
+
result
|
707
|
+
.map { |row| construct_coder(row, coders_by_name[row["typname"]]) }
|
708
|
+
.compact
|
709
|
+
end
|
710
|
+
|
711
|
+
map = PG::TypeMapByOid.new
|
712
|
+
coders.each { |coder| map.add_coder(coder) }
|
713
|
+
@connection.type_map_for_results = map
|
714
|
+
|
715
|
+
# extract timestamp decoder for use in update_typemap_for_default_timezone
|
716
|
+
@timestamp_decoder = coders.find { |coder| coder.name == "timestamp" }
|
717
|
+
update_typemap_for_default_timezone
|
718
|
+
end
|
719
|
+
|
720
|
+
def construct_coder(row, coder_class)
|
721
|
+
return unless coder_class
|
722
|
+
coder_class.new(oid: row["oid"].to_i, name: row["typname"])
|
723
|
+
end
|
724
|
+
|
630
725
|
def create_table_definition(*args) # :nodoc:
|
631
|
-
Redshift::TableDefinition.new(*args)
|
726
|
+
Redshift::TableDefinition.new(self, *args)
|
632
727
|
end
|
633
728
|
end
|
634
729
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord6-redshift-adapter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nancy Foen
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date:
|
14
|
+
date: 2020-08-04 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: pg
|
@@ -31,22 +31,22 @@ dependencies:
|
|
31
31
|
name: activerecord
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
33
33
|
requirements:
|
34
|
-
- - "~>"
|
35
|
-
- !ruby/object:Gem::Version
|
36
|
-
version: '6.0'
|
37
34
|
- - ">="
|
38
35
|
- !ruby/object:Gem::Version
|
39
36
|
version: 6.0.0
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '6.0'
|
40
40
|
type: :runtime
|
41
41
|
prerelease: false
|
42
42
|
version_requirements: !ruby/object:Gem::Requirement
|
43
43
|
requirements:
|
44
|
-
- - "~>"
|
45
|
-
- !ruby/object:Gem::Version
|
46
|
-
version: '6.0'
|
47
44
|
- - ">="
|
48
45
|
- !ruby/object:Gem::Version
|
49
46
|
version: 6.0.0
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '6.0'
|
50
50
|
description: Amazon Redshift _makeshift_ adapter for ActiveRecord 6.
|
51
51
|
email: fantast.d@gmail.com
|
52
52
|
executables: []
|
@@ -91,8 +91,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
91
91
|
- !ruby/object:Gem::Version
|
92
92
|
version: '0'
|
93
93
|
requirements: []
|
94
|
-
|
95
|
-
rubygems_version: 2.5.2.3
|
94
|
+
rubygems_version: 3.0.3
|
96
95
|
signing_key:
|
97
96
|
specification_version: 4
|
98
97
|
summary: Amazon Redshift adapter for ActiveRecord
|