activerecord-jdbc-alt-adapter 60.3.0-java → 61.0.0-java
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/.travis.yml +11 -11
- data/Gemfile +1 -1
- data/README.md +16 -12
- data/activerecord-jdbc-adapter.gemspec +2 -2
- data/activerecord-jdbc-alt-adapter.gemspec +5 -5
- data/lib/arel/visitors/postgresql_jdbc.rb +1 -1
- data/lib/arel/visitors/sqlserver.rb +16 -0
- data/lib/arjdbc/abstract/core.rb +1 -0
- data/lib/arjdbc/abstract/database_statements.rb +4 -0
- data/lib/arjdbc/abstract/transaction_support.rb +20 -7
- data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
- data/lib/arjdbc/mssql/adapter.rb +3 -1
- data/lib/arjdbc/mssql/column.rb +14 -0
- data/lib/arjdbc/mssql/connection_methods.rb +0 -3
- data/lib/arjdbc/mssql/database_limits.rb +7 -0
- data/lib/arjdbc/mssql/extensions/attribute_methods.rb +1 -1
- data/lib/arjdbc/mssql/schema_creation.rb +2 -2
- data/lib/arjdbc/mssql/schema_statements.rb +29 -1
- data/lib/arjdbc/mssql.rb +1 -1
- data/lib/arjdbc/mysql/adapter.rb +14 -5
- data/lib/arjdbc/mysql/connection_methods.rb +5 -1
- data/lib/arjdbc/postgresql/adapter.rb +85 -73
- data/lib/arjdbc/postgresql/column.rb +1 -1
- data/lib/arjdbc/postgresql/oid_types.rb +4 -3
- data/lib/arjdbc/sqlite3/adapter.rb +95 -58
- data/lib/arjdbc/sqlite3/connection_methods.rb +11 -1
- data/lib/arjdbc/tasks/databases.rake +15 -10
- data/lib/arjdbc/tasks/mssql_database_tasks.rb +88 -31
- data/lib/arjdbc/version.rb +3 -1
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +106 -68
- data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +82 -36
- data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +3 -4
- metadata +8 -7
@@ -1,18 +1,29 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'active_record/tasks/database_tasks'
|
4
4
|
|
5
5
|
module ArJdbc
|
6
|
-
module Tasks
|
7
|
-
class MSSQLDatabaseTasks
|
6
|
+
module Tasks # :nodoc:
|
7
|
+
class MSSQLDatabaseTasks # :nodoc:
|
8
|
+
delegate :connection, to: ActiveRecord::Base
|
9
|
+
delegate :establish_connection, to: ActiveRecord::Base
|
8
10
|
delegate :clear_active_connections!, to: ActiveRecord::Base
|
9
11
|
|
12
|
+
def self.using_database_configurations?
|
13
|
+
true
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(db_config)
|
17
|
+
@db_config = db_config
|
18
|
+
@configuration_hash = db_config.configuration_hash
|
19
|
+
end
|
20
|
+
|
10
21
|
def create
|
11
22
|
establish_master_connection
|
12
|
-
connection.create_database(
|
13
|
-
establish_connection
|
14
|
-
rescue ActiveRecord::StatementInvalid =>
|
15
|
-
case
|
23
|
+
connection.create_database(db_config.database, creation_options)
|
24
|
+
establish_connection(db_config)
|
25
|
+
rescue ActiveRecord::StatementInvalid => e
|
26
|
+
case e.message
|
16
27
|
when /database .* already exists/i
|
17
28
|
raise ActiveRecord::Tasks::DatabaseAlreadyExists
|
18
29
|
else
|
@@ -22,7 +33,15 @@ module ArJdbc
|
|
22
33
|
|
23
34
|
def drop
|
24
35
|
establish_master_connection
|
25
|
-
connection.drop_database
|
36
|
+
connection.drop_database(db_config.database)
|
37
|
+
end
|
38
|
+
|
39
|
+
def charset
|
40
|
+
connection.charset
|
41
|
+
end
|
42
|
+
|
43
|
+
def collation
|
44
|
+
connection.collation
|
26
45
|
end
|
27
46
|
|
28
47
|
def purge
|
@@ -31,40 +50,78 @@ module ArJdbc
|
|
31
50
|
create
|
32
51
|
end
|
33
52
|
|
53
|
+
def structure_dump(filename, _extra_flags)
|
54
|
+
args = prepare_command_options
|
55
|
+
|
56
|
+
args.concat(["-f #{filename}"])
|
34
57
|
|
35
|
-
|
36
|
-
config = config_from_url_if_needed
|
37
|
-
`smoscript -s #{config['host']} -d #{config['database']} -u #{config['username']} -p #{config['password']} -f #{filename} -A -U`
|
58
|
+
run_cmd('mssql-scripter', args, 'dumping')
|
38
59
|
end
|
39
60
|
|
40
|
-
def structure_load(filename)
|
41
|
-
|
42
|
-
|
61
|
+
def structure_load(filename, _extra_flags)
|
62
|
+
args = prepare_command_options
|
63
|
+
|
64
|
+
args.concat(["-i #{filename}"])
|
65
|
+
|
66
|
+
run_cmd('mssql-cli', args, 'loading')
|
43
67
|
end
|
44
68
|
|
45
69
|
private
|
46
70
|
|
71
|
+
attr_reader :db_config, :configuration_hash
|
72
|
+
|
73
|
+
def creation_options
|
74
|
+
{}.tap do |options|
|
75
|
+
options[:collation] = configuration_hash[:collation] if configuration_hash.include?(:collation)
|
76
|
+
|
77
|
+
# azure creation options
|
78
|
+
options[:azure_maxsize] = configuration_hash[:azure_maxsize] if configuration_hash.include?(:azure_maxsize)
|
79
|
+
options[:azure_edition] = configuration_hash[:azure_edition] if configuration_hash.include?(:azure_edition)
|
80
|
+
|
81
|
+
if configuration_hash.include?(:azure_service_objective)
|
82
|
+
options[:azure_service_objective] = configuration_hash[:azure_service_objective]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
47
87
|
def establish_master_connection
|
48
|
-
establish_connection
|
88
|
+
establish_connection(configuration_hash.merge(database: 'master'))
|
49
89
|
end
|
50
90
|
|
51
|
-
def
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
91
|
+
def prepare_command_options
|
92
|
+
{
|
93
|
+
server: '-S',
|
94
|
+
database: '-d',
|
95
|
+
username: '-U',
|
96
|
+
password: '-P'
|
97
|
+
}.map { |option, arg| "#{arg} #{config_for_cli[option]}" }
|
57
98
|
end
|
58
99
|
|
59
|
-
def
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
100
|
+
def config_for_cli
|
101
|
+
{}.tap do |options|
|
102
|
+
if configuration_hash[:host].present? && configuration_hash[:port].present?
|
103
|
+
options[:server] = "#{configuration_hash[:host]},#{configuration_hash[:port]}"
|
104
|
+
elsif configuration_hash[:host].present?
|
105
|
+
options[:server] = configuration_hash[:host]
|
106
|
+
end
|
107
|
+
|
108
|
+
options[:database] = configuration_hash[:database] if configuration_hash[:database].present?
|
109
|
+
options[:username] = configuration_hash[:username] if configuration_hash[:username].present?
|
110
|
+
options[:password] = configuration_hash[:password] if configuration_hash[:password].present?
|
64
111
|
end
|
65
|
-
dup
|
66
112
|
end
|
67
113
|
|
114
|
+
def run_cmd(cmd, args, action)
|
115
|
+
fail run_cmd_error(cmd, args, action) unless Kernel.system(cmd, *args)
|
116
|
+
end
|
117
|
+
|
118
|
+
def run_cmd_error(cmd, args, action)
|
119
|
+
msg = +"failed to execute:\n"
|
120
|
+
msg << "#{cmd} #{args.join(' ')}\n\n"
|
121
|
+
msg << "Failed #{action} structure, please check the output above for any errors"
|
122
|
+
msg << " and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n"
|
123
|
+
msg
|
124
|
+
end
|
68
125
|
end
|
69
126
|
|
70
127
|
module DatabaseTasksMSSQL
|
@@ -74,8 +131,8 @@ module ArJdbc
|
|
74
131
|
|
75
132
|
def check_protected_environments!
|
76
133
|
super
|
77
|
-
rescue ActiveRecord::JDBCError =>
|
78
|
-
case
|
134
|
+
rescue ActiveRecord::JDBCError => e
|
135
|
+
case e.message
|
79
136
|
when /cannot open database .* requested by the login/i
|
80
137
|
else
|
81
138
|
raise
|
@@ -85,6 +142,6 @@ module ArJdbc
|
|
85
142
|
end
|
86
143
|
end
|
87
144
|
|
88
|
-
ActiveRecord::Tasks::DatabaseTasks.send
|
145
|
+
ActiveRecord::Tasks::DatabaseTasks.send(:include, DatabaseTasksMSSQL)
|
89
146
|
end
|
90
147
|
end
|
data/lib/arjdbc/version.rb
CHANGED
@@ -86,6 +86,7 @@ import org.jruby.anno.JRubyMethod;
|
|
86
86
|
import org.jruby.exceptions.RaiseException;
|
87
87
|
import org.jruby.ext.bigdecimal.RubyBigDecimal;
|
88
88
|
import org.jruby.ext.date.RubyDate;
|
89
|
+
import org.jruby.ext.date.RubyDateTime;
|
89
90
|
import org.jruby.javasupport.JavaEmbedUtils;
|
90
91
|
import org.jruby.javasupport.JavaUtil;
|
91
92
|
import org.jruby.runtime.Block;
|
@@ -124,6 +125,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
124
125
|
private IRubyObject config;
|
125
126
|
private IRubyObject adapter; // the AbstractAdapter instance we belong to
|
126
127
|
private volatile boolean connected = true;
|
128
|
+
private RubyClass attributeClass;
|
127
129
|
|
128
130
|
private boolean lazy = false; // final once set on initialize
|
129
131
|
private boolean jndi; // final once set on initialize
|
@@ -132,6 +134,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
132
134
|
|
133
135
|
protected RubyJdbcConnection(Ruby runtime, RubyClass metaClass) {
|
134
136
|
super(runtime, metaClass);
|
137
|
+
attributeClass = runtime.getModule("ActiveModel").getClass("Attribute");
|
135
138
|
}
|
136
139
|
|
137
140
|
private static final ObjectAllocator ALLOCATOR = new ObjectAllocator() {
|
@@ -359,7 +362,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
359
362
|
if ( ! connection.getAutoCommit() ) {
|
360
363
|
try {
|
361
364
|
connection.commit();
|
362
|
-
resetSavepoints(context); // if any
|
365
|
+
resetSavepoints(context, connection); // if any
|
363
366
|
return context.runtime.newBoolean(true);
|
364
367
|
}
|
365
368
|
finally {
|
@@ -380,7 +383,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
380
383
|
if ( ! connection.getAutoCommit() ) {
|
381
384
|
try {
|
382
385
|
connection.rollback();
|
383
|
-
resetSavepoints(context); // if any
|
386
|
+
resetSavepoints(context, connection); // if any
|
384
387
|
return context.tru;
|
385
388
|
} finally {
|
386
389
|
connection.setAutoCommit(true);
|
@@ -516,7 +519,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
516
519
|
return null;
|
517
520
|
}
|
518
521
|
|
519
|
-
protected boolean resetSavepoints(final ThreadContext context) {
|
522
|
+
protected boolean resetSavepoints(final ThreadContext context, final Connection connection) throws SQLException {
|
520
523
|
if ( hasInternalVariable("savepoints") ) {
|
521
524
|
removeInternalVariable("savepoints");
|
522
525
|
return true;
|
@@ -610,11 +613,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
610
613
|
return convertJavaToRuby( connection.unwrap(Connection.class) );
|
611
614
|
}
|
612
615
|
}
|
613
|
-
catch (AbstractMethodError e) {
|
614
|
-
debugStackTrace(context, e);
|
615
|
-
warn(context, "driver/pool connection does not support unwrapping: " + e);
|
616
|
-
}
|
617
|
-
catch (SQLException e) {
|
616
|
+
catch (AbstractMethodError | SQLException e) {
|
618
617
|
debugStackTrace(context, e);
|
619
618
|
warn(context, "driver/pool connection does not support unwrapping: " + e);
|
620
619
|
}
|
@@ -860,27 +859,25 @@ public class RubyJdbcConnection extends RubyObject {
|
|
860
859
|
*/
|
861
860
|
@JRubyMethod(name = "execute_insert_pk", required = 2)
|
862
861
|
public IRubyObject execute_insert_pk(final ThreadContext context, final IRubyObject sql, final IRubyObject pk) {
|
863
|
-
return withConnection(context,
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
try {
|
868
|
-
|
869
|
-
statement = createStatement(context, connection);
|
862
|
+
return withConnection(context, connection -> {
|
863
|
+
Statement statement = null;
|
864
|
+
final String query = sqlString(sql);
|
865
|
+
try {
|
870
866
|
|
871
|
-
|
872
|
-
statement.executeUpdate(query, Statement.RETURN_GENERATED_KEYS);
|
873
|
-
} else {
|
874
|
-
statement.executeUpdate(query, createStatementPk(pk));
|
875
|
-
}
|
867
|
+
statement = createStatement(context, connection);
|
876
868
|
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
} finally {
|
882
|
-
close(statement);
|
869
|
+
if (pk == context.nil || pk == context.fals || !supportsGeneratedKeys(connection)) {
|
870
|
+
statement.executeUpdate(query, Statement.RETURN_GENERATED_KEYS);
|
871
|
+
} else {
|
872
|
+
statement.executeUpdate(query, createStatementPk(pk));
|
883
873
|
}
|
874
|
+
|
875
|
+
return mapGeneratedKeys(context, connection, statement);
|
876
|
+
} catch (final SQLException e) {
|
877
|
+
debugErrorSQL(context, query);
|
878
|
+
throw e;
|
879
|
+
} finally {
|
880
|
+
close(statement);
|
884
881
|
}
|
885
882
|
});
|
886
883
|
}
|
@@ -903,26 +900,24 @@ public class RubyJdbcConnection extends RubyObject {
|
|
903
900
|
@JRubyMethod(name = "execute_insert_pk", required = 3)
|
904
901
|
public IRubyObject execute_insert_pk(final ThreadContext context, final IRubyObject sql, final IRubyObject binds,
|
905
902
|
final IRubyObject pk) {
|
906
|
-
return withConnection(context,
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
statement = connection.prepareStatement(query, createStatementPk(pk));
|
915
|
-
}
|
916
|
-
|
917
|
-
setStatementParameters(context, connection, statement, (RubyArray) binds);
|
918
|
-
statement.executeUpdate();
|
919
|
-
return mapGeneratedKeys(context, connection, statement);
|
920
|
-
} catch (final SQLException e) {
|
921
|
-
debugErrorSQL(context, query);
|
922
|
-
throw e;
|
923
|
-
} finally {
|
924
|
-
close(statement);
|
903
|
+
return withConnection(context, connection -> {
|
904
|
+
PreparedStatement statement = null;
|
905
|
+
final String query = sqlString(sql);
|
906
|
+
try {
|
907
|
+
if (pk == context.nil || pk == context.fals || !supportsGeneratedKeys(connection)) {
|
908
|
+
statement = connection.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
|
909
|
+
} else {
|
910
|
+
statement = connection.prepareStatement(query, createStatementPk(pk));
|
925
911
|
}
|
912
|
+
|
913
|
+
setStatementParameters(context, connection, statement, (RubyArray) binds);
|
914
|
+
statement.executeUpdate();
|
915
|
+
return mapGeneratedKeys(context, connection, statement);
|
916
|
+
} catch (final SQLException e) {
|
917
|
+
debugErrorSQL(context, query);
|
918
|
+
throw e;
|
919
|
+
} finally {
|
920
|
+
close(statement);
|
926
921
|
}
|
927
922
|
});
|
928
923
|
}
|
@@ -1012,12 +1007,12 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1012
1007
|
binds = null;
|
1013
1008
|
} else { // (sql, binds)
|
1014
1009
|
maxRows = 0;
|
1015
|
-
binds = (RubyArray) TypeConverter.checkArrayType(args[1]);
|
1010
|
+
binds = (RubyArray) TypeConverter.checkArrayType(context, args[1]);
|
1016
1011
|
}
|
1017
1012
|
break;
|
1018
1013
|
case 3: // (sql, max_rows, binds)
|
1019
1014
|
maxRows = RubyNumeric.fix2int(args[1]);
|
1020
|
-
binds = (RubyArray) TypeConverter.checkArrayType(args[2]);
|
1015
|
+
binds = (RubyArray) TypeConverter.checkArrayType(context, args[2]);
|
1021
1016
|
break;
|
1022
1017
|
default: // (sql) 1-arg
|
1023
1018
|
maxRows = 0;
|
@@ -1106,6 +1101,28 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1106
1101
|
});
|
1107
1102
|
}
|
1108
1103
|
|
1104
|
+
@JRubyMethod(required = 1)
|
1105
|
+
public IRubyObject get_first_value(final ThreadContext context, final IRubyObject sql) {
|
1106
|
+
return withConnection(context, connection -> {
|
1107
|
+
Statement statement = null;
|
1108
|
+
final String query = sqlString(sql);
|
1109
|
+
try {
|
1110
|
+
statement = createStatement(context, connection);
|
1111
|
+
statement.execute(query);
|
1112
|
+
ResultSet rs = statement.getResultSet();
|
1113
|
+
if (rs == null || !rs.next()) return context.nil;
|
1114
|
+
|
1115
|
+
return jdbcToRuby(context, context.getRuntime(), 1, rs.getMetaData().getColumnType(1), rs);
|
1116
|
+
|
1117
|
+
} catch (final SQLException e) {
|
1118
|
+
debugErrorSQL(context, query);
|
1119
|
+
throw e;
|
1120
|
+
} finally {
|
1121
|
+
close(statement);
|
1122
|
+
}
|
1123
|
+
});
|
1124
|
+
}
|
1125
|
+
|
1109
1126
|
/**
|
1110
1127
|
* Prepares a query, returns a wrapped PreparedStatement. This takes care of exception wrapping
|
1111
1128
|
* @param context which context this method is executing on.
|
@@ -2402,9 +2419,16 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2402
2419
|
final Connection connection, final PreparedStatement statement,
|
2403
2420
|
final int index, IRubyObject attribute) throws SQLException {
|
2404
2421
|
|
2405
|
-
|
2406
|
-
final int type
|
2407
|
-
|
2422
|
+
final IRubyObject value;
|
2423
|
+
final int type;
|
2424
|
+
|
2425
|
+
if (attributeClass.isInstance(attribute)) {
|
2426
|
+
type = jdbcTypeForAttribute(context, attribute);
|
2427
|
+
value = valueForDatabase(context, attribute);
|
2428
|
+
} else {
|
2429
|
+
type = jdbcTypeForPrimitiveAttribute(context, attribute);
|
2430
|
+
value = attribute;
|
2431
|
+
}
|
2408
2432
|
|
2409
2433
|
// All the set methods were calling this first so save a method call in the nil case
|
2410
2434
|
if ( value == context.nil ) {
|
@@ -2520,6 +2544,34 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2520
2544
|
return Types.OTHER; // -1 as well as 0 are used in Types
|
2521
2545
|
}
|
2522
2546
|
|
2547
|
+
protected String internedTypeForPrimitive(final ThreadContext context, final IRubyObject value) throws SQLException {
|
2548
|
+
if (value instanceof RubyString) {
|
2549
|
+
return "string";
|
2550
|
+
}
|
2551
|
+
if (value instanceof RubyInteger) {
|
2552
|
+
return "integer";
|
2553
|
+
}
|
2554
|
+
if (value instanceof RubyNumeric) {
|
2555
|
+
return "float";
|
2556
|
+
}
|
2557
|
+
if (value instanceof RubyTime || value instanceof RubyDateTime) {
|
2558
|
+
return "timestamp";
|
2559
|
+
}
|
2560
|
+
if (value instanceof RubyDate) {
|
2561
|
+
return "date";
|
2562
|
+
}
|
2563
|
+
if (value instanceof RubyBoolean) {
|
2564
|
+
return "boolean";
|
2565
|
+
}
|
2566
|
+
return "string";
|
2567
|
+
}
|
2568
|
+
|
2569
|
+
protected Integer jdbcTypeForPrimitiveAttribute(final ThreadContext context,
|
2570
|
+
final IRubyObject attribute) throws SQLException {
|
2571
|
+
final String internedType = internedTypeForPrimitive(context, attribute);
|
2572
|
+
return jdbcTypeFor(internedType);
|
2573
|
+
}
|
2574
|
+
|
2523
2575
|
protected Integer jdbcTypeFor(final String type) {
|
2524
2576
|
return JDBC_TYPE_FOR.get(type);
|
2525
2577
|
}
|
@@ -2531,7 +2583,9 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2531
2583
|
}
|
2532
2584
|
|
2533
2585
|
protected static IRubyObject attributeSQLType(final ThreadContext context, final IRubyObject attribute) {
|
2534
|
-
|
2586
|
+
final IRubyObject type = attributeType(context, attribute);
|
2587
|
+
if (type != null) return type.callMethod(context, "type");
|
2588
|
+
return context.nil;
|
2535
2589
|
}
|
2536
2590
|
|
2537
2591
|
private final CachingCallSite value_site = new FunctionalCachingCallSite("value"); // AR::Attribute#value
|
@@ -2546,23 +2600,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2546
2600
|
|
2547
2601
|
final IRubyObject value = value_site.call(context, attribute, attribute);
|
2548
2602
|
|
2549
|
-
|
2550
|
-
return "integer";
|
2551
|
-
}
|
2552
|
-
|
2553
|
-
if (value instanceof RubyNumeric) {
|
2554
|
-
return "float";
|
2555
|
-
}
|
2556
|
-
|
2557
|
-
if (value instanceof RubyTime) {
|
2558
|
-
return "timestamp";
|
2559
|
-
}
|
2560
|
-
|
2561
|
-
if (value instanceof RubyBoolean) {
|
2562
|
-
return "boolean";
|
2563
|
-
}
|
2564
|
-
|
2565
|
-
return "string";
|
2603
|
+
return internedTypeForPrimitive(context, value);
|
2566
2604
|
}
|
2567
2605
|
|
2568
2606
|
// to be overriden in child class for database specific types
|
@@ -197,9 +197,9 @@ public class PostgreSQLRubyJdbcConnection extends arjdbc.jdbc.RubyJdbcConnection
|
|
197
197
|
RubyClass arrayClass = oidArray(context);
|
198
198
|
RubyBasicObject attributeType = (RubyBasicObject) attributeType(context, attribute);
|
199
199
|
// The type or its delegate is an OID::Array
|
200
|
-
if (arrayClass.isInstance(attributeType) ||
|
200
|
+
if (attributeType != null && (arrayClass.isInstance(attributeType) ||
|
201
201
|
(attributeType.hasInstanceVariable("@delegate_dc_obj") &&
|
202
|
-
arrayClass.isInstance(attributeType.getInstanceVariable("@delegate_dc_obj")))) {
|
202
|
+
arrayClass.isInstance(attributeType.getInstanceVariable("@delegate_dc_obj"))))) {
|
203
203
|
return "array";
|
204
204
|
}
|
205
205
|
|
@@ -387,20 +387,7 @@ public class PostgreSQLRubyJdbcConnection extends arjdbc.jdbc.RubyJdbcConnection
|
|
387
387
|
RubyDate rubyDate = (RubyDate) value;
|
388
388
|
DateTime dt = rubyDate.getDateTime();
|
389
389
|
// pgjdbc needs adjustment for default JVM timezone
|
390
|
-
|
391
|
-
// If the date is a day when Daylight savings starts (2am changed to 3am),
|
392
|
-
// And we are in a positive GMT timezone (Australia/Melbourne)
|
393
|
-
// Then removing milliseconds equal to the TimeZone (+11 GMT),
|
394
|
-
// will result in the date being the previous day 23:00, because of the missing hour.
|
395
|
-
// So we check if the date after the shift is outside of daylight time and remove an hours worth of milliseconds.
|
396
|
-
final long dateMillis = dt.getMillis();
|
397
|
-
long offset = TZ_DEFAULT.getOffset(dt.getMillis());
|
398
|
-
if (TZ_DEFAULT.inDaylightTime(new Date(dt.getMillis())) && !TZ_DEFAULT.inDaylightTime(new Date(dateMillis - offset))) {
|
399
|
-
offset -= 3600000; // 1 hour
|
400
|
-
}
|
401
|
-
Date utcShiftedDate = new Date(dateMillis - offset);
|
402
|
-
|
403
|
-
statement.setDate(index, utcShiftedDate);
|
390
|
+
statement.setDate(index, new Date(dt.getMillis() - TZ_DEFAULT.getOffset(dt.getMillis())));
|
404
391
|
return;
|
405
392
|
}
|
406
393
|
|
@@ -449,7 +436,7 @@ public class PostgreSQLRubyJdbcConnection extends arjdbc.jdbc.RubyJdbcConnection
|
|
449
436
|
break;
|
450
437
|
|
451
438
|
case "interval":
|
452
|
-
statement.setObject(index,
|
439
|
+
statement.setObject(index, stringToPGInterval(value.toString()));
|
453
440
|
break;
|
454
441
|
|
455
442
|
case "json":
|
@@ -506,6 +493,74 @@ public class PostgreSQLRubyJdbcConnection extends arjdbc.jdbc.RubyJdbcConnection
|
|
506
493
|
}
|
507
494
|
}
|
508
495
|
|
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
|
+
|
509
564
|
protected IRubyObject jdbcToRuby(ThreadContext context, Ruby runtime, int column, int type, ResultSet resultSet) throws SQLException {
|
510
565
|
return typeMap != null ?
|
511
566
|
convertWithTypeMap(context, runtime, column, type, resultSet) :
|
@@ -887,34 +942,25 @@ public class PostgreSQLRubyJdbcConnection extends arjdbc.jdbc.RubyJdbcConnection
|
|
887
942
|
private static String formatInterval(final Object object) {
|
888
943
|
final PGInterval interval = (PGInterval) object;
|
889
944
|
final StringBuilder str = new StringBuilder(32);
|
945
|
+
str.append("P");
|
890
946
|
|
891
947
|
final int years = interval.getYears();
|
892
|
-
if (years != 0) str.append(years).append("
|
948
|
+
if (years != 0) str.append(years).append("Y");
|
893
949
|
|
894
950
|
final int months = interval.getMonths();
|
895
|
-
if (months != 0) str.append(months).append("
|
951
|
+
if (months != 0) str.append(months).append("M");
|
896
952
|
|
897
953
|
final int days = interval.getDays();
|
898
|
-
if (days != 0) str.append(days).append("
|
954
|
+
if (days != 0) str.append(days).append("D");
|
899
955
|
|
900
956
|
final int hours = interval.getHours();
|
901
957
|
final int mins = interval.getMinutes();
|
902
|
-
final
|
903
|
-
if (hours != 0 || mins != 0 || secs != 0) {
|
904
|
-
|
905
|
-
|
906
|
-
str.append(
|
907
|
-
|
908
|
-
if (mins < 10) str.append('0');
|
909
|
-
|
910
|
-
str.append(mins).append(':');
|
911
|
-
|
912
|
-
if (secs < 10) str.append('0');
|
913
|
-
|
914
|
-
str.append(secs);
|
915
|
-
|
916
|
-
} else if (str.length() > 1) {
|
917
|
-
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");
|
918
964
|
}
|
919
965
|
|
920
966
|
return str.toString();
|
@@ -370,10 +370,9 @@ public class SQLite3RubyJdbcConnection extends RubyJdbcConnection {
|
|
370
370
|
}
|
371
371
|
|
372
372
|
@Override
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
);
|
373
|
+
protected boolean resetSavepoints(final ThreadContext context, final Connection connection) throws SQLException {
|
374
|
+
connection.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
|
375
|
+
return super.resetSavepoints(context, connection);
|
377
376
|
}
|
378
377
|
|
379
378
|
@Override
|