Skip to content

Commit 9b94706

Browse files
authored
Merge pull request #1068 from dr-itz/rails61-dev
Rails 6.1 fixes
2 parents 512433c + 327c7d6 commit 9b94706

File tree

17 files changed

+190
-121
lines changed

17 files changed

+190
-121
lines changed

.travis.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ before_script:
3737
mysql -e "grant all privileges on activerecord_unittest.* to rails@localhost;" && \
3838
mysql -e "grant all privileges on activerecord_unittest2.* to rails@localhost;" && \
3939
mysql -e "grant all privileges on inexistent_activerecord_unittest.* to rails@localhost;" && \
40-
mysql -e "CREATE DATABASE activerecord_unittest DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;" && \
41-
mysql -e "CREATE DATABASE activerecord_unittest2 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;" \
40+
mysql -e "CREATE DATABASE activerecord_unittest DEFAULT CHARACTER SET utf8mb4;" && \
41+
mysql -e "CREATE DATABASE activerecord_unittest2 DEFAULT CHARACTER SET utf8mb4;" \
4242
|| true
4343
- |
4444
[ "$DB" == "postgresql" ] && [ "$TEST_PREFIX" == "rails:" ] && \

lib/arel/visitors/postgresql_jdbc.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22

33
class Arel::Visitors::PostgreSQL
44
# AREL converts bind argument markers "?" to "$n" for PG, but JDBC wants "?".
5-
remove_method :visit_Arel_Nodes_BindParam if ArJdbc::AR42
5+
remove_method :bind_block
66
end

lib/arjdbc/abstract/database_statements.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ def exec_insert(sql, name = nil, binds = NO_BINDS, pk = nil, sequence_name = nil
1515
end
1616

1717
materialize_transactions
18+
mark_transaction_written_if_write(sql)
1819

1920
binds = convert_legacy_binds_to_attributes(binds) if binds.first.is_a?(Array)
2021

@@ -35,6 +36,7 @@ def exec_query(sql, name = nil, binds = NO_BINDS, prepare: false)
3536
end
3637

3738
materialize_transactions
39+
mark_transaction_written_if_write(sql)
3840

3941
binds = convert_legacy_binds_to_attributes(binds) if binds.first.is_a?(Array)
4042

@@ -55,6 +57,7 @@ def exec_update(sql, name = nil, binds = NO_BINDS)
5557
end
5658

5759
materialize_transactions
60+
mark_transaction_written_if_write(sql)
5861

5962
binds = convert_legacy_binds_to_attributes(binds) if binds.first.is_a?(Array)
6063

@@ -72,6 +75,7 @@ def execute(sql, name = nil)
7275
end
7376

7477
materialize_transactions
78+
mark_transaction_written_if_write(sql)
7579

7680
log(sql, name) { @connection.execute(sql) }
7781
end

lib/arjdbc/abstract/transaction_support.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,16 @@ def release_savepoint(name = current_savepoint_name)
7979
end
8080
end
8181
end
82+
83+
# patch to avoid the usage of WeakMap
84+
require 'active_record/connection_adapters/abstract/transaction'
85+
module ActiveRecord
86+
module ConnectionAdapters
87+
class Transaction
88+
def add_record(record, ensure_finalize = true)
89+
@records ||= []
90+
@records << record
91+
end
92+
end
93+
end
94+
end

lib/arjdbc/postgresql/adapter.rb

Lines changed: 78 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -48,46 +48,6 @@ def adapter_name
4848
ADAPTER_NAME
4949
end
5050

51-
def get_database_version # :nodoc:
52-
begin
53-
version = @connection.database_product
54-
if match = version.match(/([\d\.]*\d).*?/)
55-
version = match[1].split('.').map(&:to_i)
56-
# PostgreSQL version representation does not have more than 4 digits
57-
# From version 10 onwards, PG has changed its versioning policy to
58-
# limit it to only 2 digits. i.e. in 10.x, 10 being the major
59-
# version and x representing the patch release
60-
# Refer to:
61-
# https://www.postgresql.org/support/versioning/
62-
# https://www.postgresql.org/docs/10/static/libpq-status.html -> PQserverVersion()
63-
# for more info
64-
65-
if version.size >= 3
66-
(version[0] * 100 + version[1]) * 100 + version[2]
67-
elsif version.size == 2
68-
if version[0] >= 10
69-
version[0] * 100 * 100 + version[1]
70-
else
71-
(version[0] * 100 + version[1]) * 100
72-
end
73-
elsif version.size == 1
74-
version[0] * 100 * 100
75-
else
76-
0
77-
end
78-
else
79-
0
80-
end
81-
end
82-
end
83-
84-
def check_version # :nodoc:
85-
if database_version < 90300
86-
raise "Your version of PostgreSQL (#{database_version}) is too old. Active Record supports PostgreSQL >= 9.3."
87-
end
88-
end
89-
90-
9151
def redshift?
9252
# SELECT version() :
9353
# PostgreSQL 8.0.2 on i686-pc-linux-gnu, compiled by GCC gcc (GCC) 3.4.2 20041017 (Red Hat 3.4.2-6.fc3), Redshift 1.0.647
@@ -209,14 +169,14 @@ def supports_index_sort_order?
209169
true
210170
end
211171

212-
def supports_partial_index?
213-
true
214-
end
215-
216172
def supports_partitioned_indexes?
217173
database_version >= 110_000
218174
end
219175

176+
def supports_partial_index?
177+
true
178+
end
179+
220180
def supports_expression_index?
221181
true
222182
end
@@ -229,6 +189,10 @@ def supports_foreign_keys?
229189
true
230190
end
231191

192+
def supports_check_constraints?
193+
true
194+
end
195+
232196
def supports_validate_constraints?
233197
true
234198
end
@@ -292,7 +256,7 @@ def supports_materialized_views?
292256
database_version >= 90300
293257
end
294258

295-
def supports_foreign_tables? # we don't really support this yet, its a reminder :)
259+
def supports_foreign_tables?
296260
database_version >= 90300
297261
end
298262

@@ -315,11 +279,6 @@ def supports_lazy_transactions?
315279
true
316280
end
317281

318-
# From AR 5.1 postgres_adapter.rb
319-
def default_index_type?(index) # :nodoc:
320-
index.using == :btree || super
321-
end
322-
323282
def get_advisory_lock(lock_id) # :nodoc:
324283
unless lock_id.is_a?(Integer) && lock_id.bit_length <= 63
325284
raise(ArgumentError, "PostgreSQL requires advisory lock ids to be a signed 64 bit integer")
@@ -373,6 +332,65 @@ def use_insert_returning?
373332
@use_insert_returning
374333
end
375334

335+
def get_database_version # :nodoc:
336+
begin
337+
version = @connection.database_product
338+
if match = version.match(/([\d\.]*\d).*?/)
339+
version = match[1].split('.').map(&:to_i)
340+
# PostgreSQL version representation does not have more than 4 digits
341+
# From version 10 onwards, PG has changed its versioning policy to
342+
# limit it to only 2 digits. i.e. in 10.x, 10 being the major
343+
# version and x representing the patch release
344+
# Refer to:
345+
# https://www.postgresql.org/support/versioning/
346+
# https://www.postgresql.org/docs/10/static/libpq-status.html -> PQserverVersion()
347+
# for more info
348+
349+
if version.size >= 3
350+
(version[0] * 100 + version[1]) * 100 + version[2]
351+
elsif version.size == 2
352+
if version[0] >= 10
353+
version[0] * 100 * 100 + version[1]
354+
else
355+
(version[0] * 100 + version[1]) * 100
356+
end
357+
elsif version.size == 1
358+
version[0] * 100 * 100
359+
else
360+
0
361+
end
362+
else
363+
0
364+
end
365+
end
366+
end
367+
368+
def default_index_type?(index) # :nodoc:
369+
index.using == :btree || super
370+
end
371+
372+
def build_insert_sql(insert) # :nodoc:
373+
sql = +"INSERT #{insert.into} #{insert.values_list}"
374+
375+
if insert.skip_duplicates?
376+
sql << " ON CONFLICT #{insert.conflict_target} DO NOTHING"
377+
elsif insert.update_duplicates?
378+
sql << " ON CONFLICT #{insert.conflict_target} DO UPDATE SET "
379+
sql << insert.touch_model_timestamps_unless { |column| "#{insert.model.quoted_table_name}.#{column} IS NOT DISTINCT FROM excluded.#{column}" }
380+
sql << insert.updatable_columns.map { |column| "#{column}=excluded.#{column}" }.join(",")
381+
end
382+
383+
sql << " RETURNING #{insert.returning}" if insert.returning
384+
sql
385+
end
386+
387+
def check_version # :nodoc:
388+
if database_version < 90300
389+
raise "Your version of PostgreSQL (#{database_version}) is too old. Active Record supports PostgreSQL >= 9.3."
390+
end
391+
end
392+
393+
376394
def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil)
377395
val = super
378396
if !use_insert_returning? && pk
@@ -434,21 +452,6 @@ def last_insert_id_result(sequence_name)
434452
exec_query("SELECT currval('#{sequence_name}')", 'SQL')
435453
end
436454

437-
def build_insert_sql(insert) # :nodoc:
438-
sql = +"INSERT #{insert.into} #{insert.values_list}"
439-
440-
if insert.skip_duplicates?
441-
sql << " ON CONFLICT #{insert.conflict_target} DO NOTHING"
442-
elsif insert.update_duplicates?
443-
sql << " ON CONFLICT #{insert.conflict_target} DO UPDATE SET "
444-
sql << insert.touch_model_timestamps_unless { |column| "#{insert.model.quoted_table_name}.#{column} IS NOT DISTINCT FROM excluded.#{column}" }
445-
sql << insert.updatable_columns.map { |column| "#{column}=excluded.#{column}" }.join(",")
446-
end
447-
448-
sql << " RETURNING #{insert.returning}" if insert.returning
449-
sql
450-
end
451-
452455
def build_truncate_statements(table_names)
453456
["TRUNCATE TABLE #{table_names.map(&method(:quote_table_name)).join(", ")}"]
454457
end
@@ -537,6 +540,16 @@ def column_name_for_operation(operation, node)
537540

538541
# Returns the list of a table's column names, data types, and default values.
539542
#
543+
# The underlying query is roughly:
544+
# SELECT column.name, column.type, default.value, column.comment
545+
# FROM column LEFT JOIN default
546+
# ON column.table_id = default.table_id
547+
# AND column.num = default.column_num
548+
# WHERE column.table_id = get_table_id('table_name')
549+
# AND column.num > 0
550+
# AND NOT column.is_dropped
551+
# ORDER BY column.num
552+
#
540553
# If the table name is not prefixed with a schema, the database will
541554
# take the first match from the schema search path.
542555
#

lib/arjdbc/postgresql/oid_types.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ def initialize_type_map(m = type_map)
145145
m.register_type 'uuid', OID::Uuid.new
146146
m.register_type 'xml', OID::Xml.new
147147
m.register_type 'tsvector', OID::SpecializedString.new(:tsvector)
148-
m.register_type 'macaddr', OID::SpecializedString.new(:macaddr)
148+
m.register_type 'macaddr', OID::Macaddr.new
149149
m.register_type 'citext', OID::SpecializedString.new(:citext)
150150
m.register_type 'ltree', OID::SpecializedString.new(:ltree)
151151
m.register_type 'line', OID::SpecializedString.new(:line)

lib/arjdbc/sqlite3/adapter.rb

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ def supports_foreign_keys?
116116
true
117117
end
118118

119+
def supports_check_constraints?
120+
true
121+
end
122+
119123
def supports_views?
120124
true
121125
end
@@ -145,13 +149,6 @@ def supports_index_sort_order?
145149
true
146150
end
147151

148-
# Returns 62. SQLite supports index names up to 64
149-
# characters. The rest is used by Rails internally to perform
150-
# temporary rename operations
151-
def allowed_index_name_length
152-
index_name_length - 2
153-
end
154-
155152
def native_database_types #:nodoc:
156153
NATIVE_DATABASE_TYPES
157154
end
@@ -236,8 +233,11 @@ def primary_keys(table_name) # :nodoc:
236233
pks.sort_by { |f| f["pk"] }.map { |f| f["name"] }
237234
end
238235

239-
def remove_index(table_name, column_name, options = {}) #:nodoc:
236+
def remove_index(table_name, column_name = nil, **options) # :nodoc:
237+
return if options[:if_exists] && !index_exists?(table_name, column_name, **options)
238+
240239
index_name = index_name_for_remove(table_name, column_name, options)
240+
241241
exec_query "DROP INDEX #{quote_column_name(index_name)}"
242242
end
243243

@@ -288,16 +288,11 @@ def change_column_null(table_name, column_name, null, default = nil) #:nodoc:
288288
end
289289
end
290290

291-
def change_column(table_name, column_name, type, options = {}) #:nodoc:
291+
def change_column(table_name, column_name, type, **options) #:nodoc:
292292
alter_table(table_name) do |definition|
293293
definition[column_name].instance_eval do
294294
self.type = type
295-
self.limit = options[:limit] if options.include?(:limit)
296-
self.default = options[:default] if options.include?(:default)
297-
self.null = options[:null] if options.include?(:null)
298-
self.precision = options[:precision] if options.include?(:precision)
299-
self.scale = options[:scale] if options.include?(:scale)
300-
self.collation = options[:collation] if options.include?(:collation)
295+
self.options.merge!(options)
301296
end
302297
end
303298
end
@@ -397,7 +392,12 @@ def invalid_alter_table_type?(type, options)
397392
options[:null] == false && options[:default].nil?
398393
end
399394

400-
def alter_table(table_name, foreign_keys = foreign_keys(table_name), **options)
395+
def alter_table(
396+
table_name,
397+
foreign_keys = foreign_keys(table_name),
398+
check_constraints = check_constraints(table_name),
399+
**options
400+
)
401401
altered_table_name = "a#{table_name}"
402402

403403
caller = lambda do |definition|
@@ -410,6 +410,10 @@ def alter_table(table_name, foreign_keys = foreign_keys(table_name), **options)
410410
definition.foreign_key(to_table, **fk.options)
411411
end
412412

413+
check_constraints.each do |chk|
414+
definition.check_constraint(chk.expression, **chk.options)
415+
end
416+
413417
yield definition if block_given?
414418
end
415419

@@ -462,7 +466,7 @@ def copy_table_indexes(from, to, rename = {})
462466
name = index.name
463467
# indexes sqlite creates for internal use start with `sqlite_` and
464468
# don't need to be copied
465-
next if name.starts_with?("sqlite_")
469+
next if name.start_with?("sqlite_")
466470
if to == "a#{from}"
467471
name = "t#{name}"
468472
elsif from == "a#{to}"
@@ -479,10 +483,10 @@ def copy_table_indexes(from, to, rename = {})
479483

480484
unless columns.empty?
481485
# index name can't be the same
482-
opts = { name: name.gsub(/(^|_)(#{from})_/, "\\1#{to}_"), internal: true }
483-
opts[:unique] = true if index.unique
484-
opts[:where] = index.where if index.where
485-
add_index(to, columns, opts)
486+
options = { name: name.gsub(/(^|_)(#{from})_/, "\\1#{to}_"), internal: true }
487+
options[:unique] = true if index.unique
488+
options[:where] = index.where if index.where
489+
add_index(to, columns, **options)
486490
end
487491
end
488492
end
@@ -547,7 +551,7 @@ def table_structure_with_collation(table_name, basic_structure)
547551
collation_hash[$1] = $2 if COLLATE_REGEX =~ column_string
548552
end
549553

550-
basic_structure.map! do |column|
554+
basic_structure.map do |column|
551555
column_name = column["name"]
552556

553557
if collation_hash.has_key? column_name

0 commit comments

Comments
 (0)