Skip to content

Commit 713dcfa

Browse files
authored
Merge pull request #1075 from dr-itz/rails61-dev
Rails 6.1 fixes
2 parents 0a3e5f4 + 2fda2e0 commit 713dcfa

34 files changed

+282
-72
lines changed

lib/arjdbc/abstract/core.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ def translate_exception(exception, message:, sql:, binds:)
5656
case exception
5757
when SystemExit, SignalException, NoMemoryError then exception
5858
when ActiveModel::RangeError, TypeError, RuntimeError then exception
59+
when ActiveRecord::ConnectionNotEstablished then exception
5960
else super
6061
end
6162
end

lib/arjdbc/postgresql/adapter.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ def configure_connection
8787
execute("SET time zone '#{tz}'", 'SCHEMA')
8888
end unless redshift?
8989

90+
# Set interval output format to ISO 8601 for ease of parsing by ActiveSupport::Duration.parse
91+
execute("SET intervalstyle = iso_8601", "SCHEMA")
92+
9093
# SET statements from :variables config hash
9194
# http://www.postgresql.org/docs/8.3/static/sql-set.html
9295
(config[:variables] || {}).map do |k, v|

lib/arjdbc/postgresql/oid_types.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,9 +155,9 @@ def initialize_type_map(m = type_map)
155155
m.register_type 'polygon', OID::SpecializedString.new(:polygon)
156156
m.register_type 'circle', OID::SpecializedString.new(:circle)
157157

158-
m.register_type 'interval' do |_, _, sql_type|
158+
m.register_type 'interval' do |*args, sql_type|
159159
precision = extract_precision(sql_type)
160-
OID::SpecializedString.new(:interval, precision: precision)
160+
OID::Interval.new(precision: precision)
161161
end
162162

163163
register_class_with_precision m, 'time', Type::Time
@@ -244,6 +244,7 @@ def load_additional_types(type_map, oid = nil) # :nodoc:
244244
ActiveRecord::Type.register(:enum, OID::Enum, adapter: :postgresql)
245245
ActiveRecord::Type.register(:hstore, OID::Hstore, adapter: :postgresql)
246246
ActiveRecord::Type.register(:inet, OID::Inet, adapter: :postgresql)
247+
ActiveRecord::Type.register(:interval, OID::Interval, adapter: :postgresql)
247248
ActiveRecord::Type.register(:json, Type::Json, adapter: :postgresql)
248249
ActiveRecord::Type.register(:jsonb, OID::Jsonb, adapter: :postgresql)
249250
ActiveRecord::Type.register(:money, OID::Money, adapter: :postgresql)

lib/arjdbc/sqlite3/adapter.rb

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -373,11 +373,6 @@ def bind_params_length
373373
999
374374
end
375375

376-
def initialize_type_map(m = type_map)
377-
super
378-
register_class_with_limit m, %r(int)i, SQLite3Integer
379-
end
380-
381376
def table_structure(table_name)
382377
structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})", "SCHEMA")
383378
raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
@@ -573,18 +568,6 @@ def configure_connection
573568
execute("PRAGMA foreign_keys = ON", "SCHEMA")
574569
end
575570

576-
# DIFFERENCE: FQN
577-
class SQLite3Integer < ::ActiveRecord::Type::Integer # :nodoc:
578-
private
579-
def _limit
580-
# INTEGER storage class can be stored 8 bytes value.
581-
# See https://www.sqlite.org/datatype3.html#storage_classes_and_datatypes
582-
limit || 8
583-
end
584-
end
585-
586-
# DIFFERENCE: FQN
587-
::ActiveRecord::Type.register(:integer, SQLite3Integer, adapter: :sqlite3)
588571
end
589572
# DIFFERENCE: A registration here is moved down to concrete class so we are not registering part of an adapter.
590573
end
@@ -743,5 +726,23 @@ def combine_multi_statements(total_sql)
743726
total_sql
744727
end
745728
end
729+
730+
def initialize_type_map(m = type_map)
731+
super
732+
register_class_with_limit m, %r(int)i, SQLite3Integer
733+
end
734+
735+
# DIFFERENCE: FQN
736+
class SQLite3Integer < ::ActiveRecord::Type::Integer # :nodoc:
737+
private
738+
def _limit
739+
# INTEGER storage class can be stored 8 bytes value.
740+
# See https://www.sqlite.org/datatype3.html#storage_classes_and_datatypes
741+
limit || 8
742+
end
743+
end
744+
745+
# DIFFERENCE: FQN
746+
::ActiveRecord::Type.register(:integer, SQLite3Integer, adapter: :sqlite3)
746747
end
747748
end

src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java

Lines changed: 79 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,7 @@ protected void setObjectParameter(final ThreadContext context,
436436
break;
437437

438438
case "interval":
439-
statement.setObject(index, new PGInterval(value.toString()));
439+
statement.setObject(index, stringToPGInterval(value.toString()));
440440
break;
441441

442442
case "json":
@@ -493,6 +493,74 @@ protected void setObjectParameter(final ThreadContext context,
493493
}
494494
}
495495

496+
private int lookAhead(String value, int position, String find) {
497+
char [] tokens = find.toCharArray();
498+
int found = -1;
499+
500+
for ( int i = 0; i < tokens.length; i++ ) {
501+
found = value.indexOf(tokens[i], position);
502+
if ( found > 0 ) {
503+
return found;
504+
}
505+
}
506+
return found;
507+
}
508+
509+
private Object stringToPGInterval(String value) throws SQLException {
510+
if (!value.startsWith("P")) return new PGInterval(value);
511+
512+
PGInterval interval = new PGInterval();
513+
514+
/* this is copied from pgjdbc with fixes for Rails */
515+
int number = 0;
516+
String dateValue;
517+
String timeValue = null;
518+
519+
int hasTime = value.indexOf('T');
520+
if ( hasTime > 0 ) {
521+
/* skip over the P */
522+
dateValue = value.substring(1,hasTime);
523+
timeValue = value.substring(hasTime + 1);
524+
} else {
525+
/* skip over the P */
526+
dateValue = value.substring(1);
527+
}
528+
529+
for ( int i = 0; i < dateValue.length(); i++ ) {
530+
int lookAhead = lookAhead(dateValue, i, "YMD");
531+
if (lookAhead > 0) {
532+
char type = dateValue.charAt(lookAhead);
533+
number = Integer.parseInt(dateValue.substring(i, lookAhead));
534+
if (type == 'Y') {
535+
interval.setYears(number);
536+
} else if (type == 'M') {
537+
interval.setMonths(number);
538+
} else if (type == 'D') {
539+
interval.setDays(number);
540+
}
541+
i = lookAhead;
542+
}
543+
}
544+
if ( timeValue != null ) {
545+
for (int i = 0; i < timeValue.length(); i++) {
546+
int lookAhead = lookAhead(timeValue, i, "HMS");
547+
if (lookAhead > 0) {
548+
char type = timeValue.charAt(lookAhead);
549+
String part = timeValue.substring(i, lookAhead);
550+
if (timeValue.charAt(lookAhead) == 'H') {
551+
interval.setHours(Integer.parseInt(part));
552+
} else if (timeValue.charAt(lookAhead) == 'M') {
553+
interval.setMinutes(Integer.parseInt(part));
554+
} else if (timeValue.charAt(lookAhead) == 'S') {
555+
interval.setSeconds(Double.parseDouble(part));
556+
}
557+
i = lookAhead;
558+
}
559+
}
560+
}
561+
return interval;
562+
}
563+
496564
protected IRubyObject jdbcToRuby(ThreadContext context, Ruby runtime, int column, int type, ResultSet resultSet) throws SQLException {
497565
return typeMap != null ?
498566
convertWithTypeMap(context, runtime, column, type, resultSet) :
@@ -874,34 +942,25 @@ private IRubyObject parseInfinity(final Ruby runtime, final String value) {
874942
private static String formatInterval(final Object object) {
875943
final PGInterval interval = (PGInterval) object;
876944
final StringBuilder str = new StringBuilder(32);
945+
str.append("P");
877946

878947
final int years = interval.getYears();
879-
if (years != 0) str.append(years).append(" years ");
948+
if (years != 0) str.append(years).append("Y");
880949

881950
final int months = interval.getMonths();
882-
if (months != 0) str.append(months).append(" months ");
951+
if (months != 0) str.append(months).append("M");
883952

884953
final int days = interval.getDays();
885-
if (days != 0) str.append(days).append(" days ");
954+
if (days != 0) str.append(days).append("D");
886955

887956
final int hours = interval.getHours();
888957
final int mins = interval.getMinutes();
889-
final int secs = (int) interval.getSeconds();
890-
if (hours != 0 || mins != 0 || secs != 0) { // xx:yy:zz if not all 00
891-
if (hours < 10) str.append('0');
892-
893-
str.append(hours).append(':');
894-
895-
if (mins < 10) str.append('0');
896-
897-
str.append(mins).append(':');
898-
899-
if (secs < 10) str.append('0');
900-
901-
str.append(secs);
902-
903-
} else if (str.length() > 1) {
904-
str.deleteCharAt(str.length() - 1); // " " at the end
958+
final double secs = interval.getSeconds();
959+
if (hours != 0 || mins != 0 || secs != 0) {
960+
str.append("T");
961+
if (hours != 0) str.append(hours).append("H");
962+
if (mins != 0) str.append(mins).append("M");
963+
if (secs != 0) str.append(secs).append("S");
905964
}
906965

907966
return str.toString();

test/db/mysql/simple_test.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,7 @@ def test_jdbc_error
445445
def test_execute_after_disconnect
446446
connection.disconnect!
447447

448-
assert_raise(ActiveRecord::StatementInvalid) do
448+
assert_raise(ActiveRecord::ConnectionNotEstablished) do
449449
connection.execute('SELECT 1')
450450
end
451451

test/db/postgresql/rake_test.rb

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ def do_teardown
5151

5252
test 'rake db:structure:dump and db:structure:load' do
5353
omit('pg_dump not available') unless self.class.which('pg_dump')
54+
55+
initial_format = ActiveRecord::Base.schema_format
56+
ActiveRecord::Base.schema_format = :sql
5457
# Rake::Task["db:create"].invoke
5558
create_rake_test_database do |connection|
5659
create_schema_migrations_table(connection)
@@ -60,7 +63,7 @@ def do_teardown
6063
structure_sql = File.join('db', structure_sql_filename)
6164
begin
6265
Dir.mkdir 'db' # db/structure.sql
63-
Rake::Task["db:structure:dump"].invoke
66+
Rake::Task["db:schema:dump"].invoke
6467

6568
assert File.exists?(structure_sql)
6669
assert_match(/CREATE TABLE .*?.?users/, File.read(structure_sql))
@@ -73,7 +76,7 @@ def do_teardown
7376
# environment and load_config tasks don't run to set up the
7477
# connection because they were already ran when dumping the structure
7578
with_connection db_config.merge(database: db_name) do |_connection|
76-
Rake::Task["db:structure:load"].invoke
79+
Rake::Task["db:schema:load"].invoke
7780
end
7881

7982
with_connection db_config.merge(database: db_name) do |connection|
@@ -82,6 +85,7 @@ def do_teardown
8285
ensure
8386
File.delete(structure_sql) if File.exists?(structure_sql)
8487
Dir.rmdir 'db'
88+
ActiveRecord::Base.schema_format = initial_format
8589
end
8690
end
8791

test/db/postgresql/types_test.rb

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -300,8 +300,8 @@ def test_data_type_of_number_types
300300
end
301301

302302
def test_data_type_of_time_types
303-
assert_instance_of OID::SpecializedString, PostgresqlTime.type_for_attribute('time_interval')
304-
assert_instance_of OID::SpecializedString, PostgresqlTime.type_for_attribute('scaled_time_interval')
303+
assert_instance_of OID::Interval, PostgresqlTime.type_for_attribute('time_interval')
304+
assert_instance_of OID::Interval, PostgresqlTime.type_for_attribute('scaled_time_interval')
305305
end
306306

307307
def test_data_type_of_network_address_types
@@ -554,8 +554,8 @@ def test_number_values
554554

555555
def test_time_values
556556
# omit_unless ar_version('4.0')
557-
assert_equal '-1 years -2 days', @first_time.time_interval
558-
assert_equal '-21 days', @first_time.scaled_time_interval
557+
assert_equal '-1 years and -2 days', @first_time.time_interval.inspect
558+
assert_equal '-21 days', @first_time.scaled_time_interval.inspect
559559
end
560560

561561
def test_network_address_values_ipaddr
@@ -644,10 +644,10 @@ def test_update_number
644644
end
645645

646646
def test_update_time
647-
@first_time.time_interval = '2 years 3 minutes'
647+
@first_time.time_interval = 'P2YT3M'
648648
@first_time.save!
649649
@first_time.reload
650-
assert_equal '2 years 00:03:00', @first_time.time_interval
650+
assert_equal '2 years and 3 minutes', @first_time.time_interval.inspect
651651
end
652652

653653
def test_update_network_address

test/rails/byebug.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# empty placeholder for byebug:
2+
# Rails started to include byebug in tests, but that one doesn't support
3+
# JRuby. Since it's only required and nothing more, providing an empty
4+
# file on the include path is enough to get things going again.

test/rails/excludes/mysql2/ActiveRecord/ConnectionAdapters/ConnectionHandlerTest.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@
1313
exclude :test_establish_connection_using_top_level_key_in_two_level_config, 'tries to load SQLite3 driver'
1414
exclude :test_symbolized_configurations_assignment, 'tries to load SQLite3 driver'
1515
exclude :test_establish_connection_with_primary_works_without_deprecation, 'tries to load SQLite3 driver'
16+
exclude :test_retrieve_connection_shows_primary_deprecation_warning_when_established_on_active_record_base, 'tries to load SQLite3 driver'

0 commit comments

Comments
 (0)