activerecord-jdbc-alt-adapter 70.2.0-java → 71.0.0.alpha2-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/.github/workflows/main.yml +141 -24
- data/.github/workflows/ruby.yml +12 -12
- data/.gitignore +7 -3
- data/.solargraph.yml +15 -0
- data/Gemfile +17 -4
- data/README.md +7 -3
- data/RUNNING_TESTS.md +36 -0
- data/activerecord-jdbc-adapter.gemspec +2 -2
- data/activerecord-jdbc-alt-adapter.gemspec +1 -1
- data/lib/arjdbc/abstract/connection_management.rb +26 -10
- data/lib/arjdbc/abstract/core.rb +5 -12
- data/lib/arjdbc/abstract/database_statements.rb +35 -25
- data/lib/arjdbc/abstract/statement_cache.rb +2 -7
- data/lib/arjdbc/abstract/transaction_support.rb +37 -22
- data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
- data/lib/arjdbc/jdbc/column.rb +0 -34
- data/lib/arjdbc/jdbc/connection_methods.rb +1 -1
- data/lib/arjdbc/mssql/adapter.rb +101 -79
- data/lib/arjdbc/mssql/column.rb +1 -0
- data/lib/arjdbc/mssql/connection_methods.rb +7 -55
- data/lib/arjdbc/mssql/database_statements.rb +182 -71
- data/lib/arjdbc/mssql/explain_support.rb +8 -5
- data/lib/arjdbc/mssql/schema_creation.rb +1 -1
- data/lib/arjdbc/mssql/schema_definitions.rb +10 -0
- data/lib/arjdbc/mssql/schema_statements.rb +25 -14
- data/lib/arjdbc/mssql/server_version.rb +56 -0
- data/lib/arjdbc/mssql/utils.rb +23 -9
- data/lib/arjdbc/mysql/adapter.rb +104 -27
- data/lib/arjdbc/postgresql/adapter.rb +71 -44
- data/lib/arjdbc/postgresql/oid_types.rb +8 -27
- data/lib/arjdbc/postgresql/schema_statements.rb +57 -0
- data/lib/arjdbc/sqlite3/adapter.rb +205 -147
- data/lib/arjdbc/sqlite3/column.rb +103 -0
- data/lib/arjdbc/sqlite3/connection_methods.rb +7 -2
- data/lib/arjdbc/tasks/mssql_database_tasks.rb +9 -5
- data/lib/arjdbc/version.rb +1 -1
- data/rakelib/02-test.rake +1 -1
- data/rakelib/rails.rake +2 -0
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +3 -1
- data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +11 -0
- data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +2 -1
- metadata +10 -12
- data/lib/arel/visitors/sql_server/ng42.rb +0 -294
- data/lib/arel/visitors/sql_server.rb +0 -124
- data/lib/arjdbc/mssql/limit_helpers.rb +0 -231
- data/lib/arjdbc/mssql/lock_methods.rb +0 -77
- data/lib/arjdbc/mssql/old_adapter.rb +0 -804
- data/lib/arjdbc/mssql/old_column.rb +0 -200
data/lib/arjdbc/mysql/adapter.rb
CHANGED
@@ -23,7 +23,7 @@ module ActiveRecord
|
|
23
23
|
class Mysql2Adapter < AbstractMysqlAdapter
|
24
24
|
ADAPTER_NAME = 'Mysql2'
|
25
25
|
|
26
|
-
include Jdbc::ConnectionPoolCallbacks
|
26
|
+
# include Jdbc::ConnectionPoolCallbacks
|
27
27
|
|
28
28
|
include ArJdbc::Abstract::ConnectionManagement
|
29
29
|
include ArJdbc::Abstract::DatabaseStatements
|
@@ -33,11 +33,47 @@ module ActiveRecord
|
|
33
33
|
|
34
34
|
include ArJdbc::MySQL
|
35
35
|
|
36
|
-
|
37
|
-
|
38
|
-
|
36
|
+
class << self
|
37
|
+
def jdbc_connection_class
|
38
|
+
::ActiveRecord::ConnectionAdapters::MySQLJdbcConnection
|
39
|
+
end
|
40
|
+
|
41
|
+
def new_client(conn_params, adapter_instance)
|
42
|
+
jdbc_connection_class.new(conn_params, adapter_instance)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
def initialize_type_map(m)
|
47
|
+
super
|
48
|
+
|
49
|
+
m.register_type(%r(char)i) do |sql_type|
|
50
|
+
limit = extract_limit(sql_type)
|
51
|
+
Type.lookup(:string, adapter: :mysql2, limit: limit)
|
52
|
+
end
|
53
|
+
|
54
|
+
m.register_type %r(^enum)i, Type.lookup(:string, adapter: :mysql2)
|
55
|
+
m.register_type %r(^set)i, Type.lookup(:string, adapter: :mysql2)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# NOTE: redefines constant defined in abstract class however this time
|
60
|
+
# will use methods defined in the mysql abstract class and map properly
|
61
|
+
# mysql types.
|
62
|
+
TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) }
|
63
|
+
|
64
|
+
def initialize(...)
|
65
|
+
super
|
39
66
|
|
40
|
-
|
67
|
+
@config[:flags] ||= 0
|
68
|
+
|
69
|
+
# JDBC mysql appears to use found rows by default: https://dev.mysql.com/doc/connector-j/en/connector-j-connp-props-connection.html
|
70
|
+
# if @config[:flags].kind_of? Array
|
71
|
+
# @config[:flags].push "FOUND_ROWS"
|
72
|
+
# else
|
73
|
+
# @config[:flags] |= ::Mysql2::Client::FOUND_ROWS
|
74
|
+
# end
|
75
|
+
|
76
|
+
@connection_parameters ||= @config
|
41
77
|
end
|
42
78
|
|
43
79
|
def self.database_exists?(config)
|
@@ -49,13 +85,6 @@ module ActiveRecord
|
|
49
85
|
conn.disconnect! if conn
|
50
86
|
end
|
51
87
|
|
52
|
-
def check_version
|
53
|
-
# for JNDI, don't check version as the whole connection should be lazy
|
54
|
-
return if ::ActiveRecord::ConnectionAdapters::JdbcConnection.jndi_config?(config)
|
55
|
-
|
56
|
-
super
|
57
|
-
end
|
58
|
-
|
59
88
|
def supports_json?
|
60
89
|
!mariadb? && database_version >= '5.7.8'
|
61
90
|
end
|
@@ -96,20 +125,25 @@ module ActiveRecord
|
|
96
125
|
!READ_QUERY.match?(sql)
|
97
126
|
end
|
98
127
|
|
99
|
-
def explain(arel, binds = [])
|
100
|
-
sql = "
|
101
|
-
start =
|
102
|
-
result =
|
103
|
-
elapsed =
|
128
|
+
def explain(arel, binds = [], options = [])
|
129
|
+
sql = build_explain_clause(options) + " " + to_sql(arel, binds)
|
130
|
+
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
131
|
+
result = internal_exec_query(sql, "EXPLAIN", binds)
|
132
|
+
elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
|
104
133
|
|
105
134
|
MySQL::ExplainPrettyPrinter.new.pp(result, elapsed)
|
106
135
|
end
|
107
136
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
#
|
112
|
-
|
137
|
+
def build_explain_clause(options = [])
|
138
|
+
return "EXPLAIN" if options.empty?
|
139
|
+
|
140
|
+
explain_clause = "EXPLAIN #{options.join(" ").upcase}"
|
141
|
+
|
142
|
+
if analyze_without_explain? && explain_clause.include?("ANALYZE")
|
143
|
+
explain_clause.sub("EXPLAIN ", "")
|
144
|
+
else
|
145
|
+
explain_clause
|
146
|
+
end
|
113
147
|
end
|
114
148
|
|
115
149
|
def each_hash(result) # :nodoc:
|
@@ -164,11 +198,47 @@ module ActiveRecord
|
|
164
198
|
# CONNECTION MANAGEMENT ====================================
|
165
199
|
#++
|
166
200
|
|
201
|
+
def active?
|
202
|
+
!(@raw_connection.nil? || @raw_connection.closed?) && @lock.synchronize { @raw_connection&.ping } || false
|
203
|
+
end
|
204
|
+
|
167
205
|
alias :reset! :reconnect!
|
168
206
|
|
207
|
+
# Disconnects from the database if already connected.
|
208
|
+
# Otherwise, this method does nothing.
|
209
|
+
def disconnect!
|
210
|
+
@lock.synchronize do
|
211
|
+
super
|
212
|
+
@raw_connection&.close
|
213
|
+
@raw_connection = nil
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def discard! # :nodoc:
|
218
|
+
@lock.synchronize do
|
219
|
+
super
|
220
|
+
@raw_connection&.automatic_close = false
|
221
|
+
@raw_connection = nil
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
169
225
|
#
|
170
226
|
|
171
227
|
private
|
228
|
+
# https://mariadb.com/kb/en/analyze-statement/
|
229
|
+
def analyze_without_explain?
|
230
|
+
mariadb? && database_version >= "10.1.0"
|
231
|
+
end
|
232
|
+
|
233
|
+
def text_type?(type)
|
234
|
+
TYPE_MAP.lookup(type).is_a?(Type::String) || TYPE_MAP.lookup(type).is_a?(Type::Text)
|
235
|
+
end
|
236
|
+
|
237
|
+
def configure_connection
|
238
|
+
# @raw_connection.query_options[:as] = :array
|
239
|
+
# @raw_connection.query_options[:database_timezone] = default_timezone
|
240
|
+
super
|
241
|
+
end
|
172
242
|
|
173
243
|
# e.g. "5.7.20-0ubuntu0.16.04.1"
|
174
244
|
def full_version
|
@@ -176,17 +246,24 @@ module ActiveRecord
|
|
176
246
|
end
|
177
247
|
|
178
248
|
def get_full_version
|
179
|
-
@full_version ||=
|
180
|
-
end
|
181
|
-
|
182
|
-
def jdbc_connection_class(spec)
|
183
|
-
::ActiveRecord::ConnectionAdapters::MySQLJdbcConnection
|
249
|
+
@full_version ||= any_raw_connection.full_version
|
184
250
|
end
|
185
251
|
|
186
252
|
def jdbc_column_class
|
187
253
|
::ActiveRecord::ConnectionAdapters::MySQL::Column
|
188
254
|
end
|
189
255
|
|
256
|
+
def translate_exception(exception, message:, sql:, binds:)
|
257
|
+
case message
|
258
|
+
when /Table .* doesn't exist/i
|
259
|
+
StatementInvalid.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
260
|
+
when /BLOB, TEXT, GEOMETRY or JSON column .* can't have a default value/i
|
261
|
+
StatementInvalid.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
262
|
+
else
|
263
|
+
super
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
190
267
|
# defined in MySQL::DatabaseStatements which is not included
|
191
268
|
def default_insert_value(column)
|
192
269
|
super unless column.auto_increment?
|
@@ -13,6 +13,7 @@ require 'active_record/connection_adapters/postgresql/schema_dumper'
|
|
13
13
|
require 'active_record/connection_adapters/postgresql/schema_statements'
|
14
14
|
require 'active_record/connection_adapters/postgresql/type_metadata'
|
15
15
|
require 'active_record/connection_adapters/postgresql/utils'
|
16
|
+
|
16
17
|
require 'arjdbc/abstract/core'
|
17
18
|
require 'arjdbc/abstract/connection_management'
|
18
19
|
require 'arjdbc/abstract/database_statements'
|
@@ -21,6 +22,8 @@ require 'arjdbc/abstract/transaction_support'
|
|
21
22
|
require 'arjdbc/postgresql/base/array_decoder'
|
22
23
|
require 'arjdbc/postgresql/base/array_encoder'
|
23
24
|
require 'arjdbc/postgresql/name'
|
25
|
+
require 'arjdbc/postgresql/schema_statements'
|
26
|
+
|
24
27
|
require 'active_model'
|
25
28
|
|
26
29
|
module ArJdbc
|
@@ -35,11 +38,6 @@ module ArJdbc
|
|
35
38
|
# @private
|
36
39
|
Type = ::ActiveRecord::Type
|
37
40
|
|
38
|
-
# @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_connection_class
|
39
|
-
def self.jdbc_connection_class
|
40
|
-
::ActiveRecord::ConnectionAdapters::PostgreSQLJdbcConnection
|
41
|
-
end
|
42
|
-
|
43
41
|
# @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_column_class
|
44
42
|
def jdbc_column_class; ::ActiveRecord::ConnectionAdapters::PostgreSQLColumn end
|
45
43
|
|
@@ -52,8 +50,8 @@ module ArJdbc
|
|
52
50
|
def redshift?
|
53
51
|
# SELECT version() :
|
54
52
|
# 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
|
55
|
-
if (
|
56
|
-
redshift = !! (
|
53
|
+
if (redshift = @config[:redshift]).nil?
|
54
|
+
redshift = !! (valid_raw_connection.database_product || '').index('Redshift')
|
57
55
|
end
|
58
56
|
redshift
|
59
57
|
end
|
@@ -73,8 +71,8 @@ module ArJdbc
|
|
73
71
|
# see http://jdbc.postgresql.org/documentation/91/connect.html
|
74
72
|
# self.set_client_encoding(encoding)
|
75
73
|
#end
|
76
|
-
self.client_min_messages = config[:min_messages] || 'warning'
|
77
|
-
self.schema_search_path = config[:schema_search_path] || config[:schema_order]
|
74
|
+
self.client_min_messages = @config[:min_messages] || 'warning'
|
75
|
+
self.schema_search_path = @config[:schema_search_path] || @config[:schema_order]
|
78
76
|
|
79
77
|
# Use standard-conforming strings if available so we don't have to do the E'...' dance.
|
80
78
|
set_standard_conforming_strings
|
@@ -93,7 +91,7 @@ module ArJdbc
|
|
93
91
|
|
94
92
|
# SET statements from :variables config hash
|
95
93
|
# http://www.postgresql.org/docs/8.3/static/sql-set.html
|
96
|
-
(config[:variables] || {}).map do |k, v|
|
94
|
+
(@config[:variables] || {}).map do |k, v|
|
97
95
|
if v == ':default' || v == :default
|
98
96
|
# Sets the value to the global or compile default
|
99
97
|
execute("SET SESSION #{k} TO DEFAULT", 'SCHEMA')
|
@@ -101,6 +99,8 @@ module ArJdbc
|
|
101
99
|
execute("SET SESSION #{k} TO #{quote(v)}", 'SCHEMA')
|
102
100
|
end
|
103
101
|
end
|
102
|
+
|
103
|
+
reload_type_map
|
104
104
|
end
|
105
105
|
|
106
106
|
# @private
|
@@ -127,7 +127,7 @@ module ArJdbc
|
|
127
127
|
inet: { name: 'inet' },
|
128
128
|
int4range: { name: 'int4range' },
|
129
129
|
int8range: { name: 'int8range' },
|
130
|
-
integer: { name: 'integer' },
|
130
|
+
integer: { name: 'integer', limit: 4 },
|
131
131
|
interval: { name: 'interval' },
|
132
132
|
json: { name: 'json' },
|
133
133
|
jsonb: { name: 'jsonb' },
|
@@ -232,6 +232,10 @@ module ArJdbc
|
|
232
232
|
alias supports_insert_on_duplicate_update? supports_insert_on_conflict?
|
233
233
|
alias supports_insert_conflict_target? supports_insert_on_conflict?
|
234
234
|
|
235
|
+
def supports_identity_columns? # :nodoc:
|
236
|
+
database_version >= 10_00_00 # >= 10.0
|
237
|
+
end
|
238
|
+
|
235
239
|
def index_algorithms
|
236
240
|
{ concurrently: 'CONCURRENTLY' }
|
237
241
|
end
|
@@ -297,14 +301,21 @@ module ArJdbc
|
|
297
301
|
query_value("SELECT pg_advisory_unlock(#{lock_id})")
|
298
302
|
end
|
299
303
|
|
300
|
-
def enable_extension(name)
|
301
|
-
|
302
|
-
|
303
|
-
}
|
304
|
+
def enable_extension(name, **)
|
305
|
+
schema, name = name.to_s.split(".").values_at(-2, -1)
|
306
|
+
sql = +"CREATE EXTENSION IF NOT EXISTS \"#{name}\""
|
307
|
+
sql << " SCHEMA #{schema}" if schema
|
308
|
+
|
309
|
+
internal_exec_query(sql).tap { reload_type_map }
|
304
310
|
end
|
305
311
|
|
306
|
-
|
307
|
-
|
312
|
+
# Removes an extension from the database.
|
313
|
+
#
|
314
|
+
# [<tt>:force</tt>]
|
315
|
+
# Set to +:cascade+ to drop dependent objects as well.
|
316
|
+
# Defaults to false.
|
317
|
+
def disable_extension(name, force: false)
|
318
|
+
internal_exec_query("DROP EXTENSION IF EXISTS \"#{name}\"#{' CASCADE' if force == :cascade}").tap {
|
308
319
|
reload_type_map
|
309
320
|
}
|
310
321
|
end
|
@@ -318,7 +329,7 @@ module ArJdbc
|
|
318
329
|
end
|
319
330
|
|
320
331
|
def extensions
|
321
|
-
|
332
|
+
internal_exec_query("SELECT extname FROM pg_extension", "SCHEMA", allow_retry: true, materialize_transactions: false).cast_values
|
322
333
|
end
|
323
334
|
|
324
335
|
# Returns a list of defined enum types, and their values.
|
@@ -370,7 +381,7 @@ module ArJdbc
|
|
370
381
|
|
371
382
|
def get_database_version # :nodoc:
|
372
383
|
begin
|
373
|
-
version =
|
384
|
+
version = valid_raw_connection.database_product
|
374
385
|
if match = version.match(/([\d\.]*\d).*?/)
|
375
386
|
version = match[1].split('.').map(&:to_i)
|
376
387
|
# PostgreSQL version representation does not have more than 4 digits
|
@@ -426,8 +437,7 @@ module ArJdbc
|
|
426
437
|
end
|
427
438
|
end
|
428
439
|
|
429
|
-
|
430
|
-
def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil)
|
440
|
+
def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil, returning: nil) # :nodoc:
|
431
441
|
val = super
|
432
442
|
if !use_insert_returning? && pk
|
433
443
|
unless sequence_name
|
@@ -464,18 +474,23 @@ module ArJdbc
|
|
464
474
|
# since apparently calling close on the statement object
|
465
475
|
# doesn't always free the server resources and calling
|
466
476
|
# 'DISCARD ALL' fails if we are inside a transaction
|
467
|
-
def clear_cache!
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
end
|
477
|
+
# def clear_cache!
|
478
|
+
# super
|
479
|
+
# # Make sure all query plans are *really* gone
|
480
|
+
# @connection.execute 'DEALLOCATE ALL' if active?
|
481
|
+
# end
|
472
482
|
|
473
483
|
def reset!
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
484
|
+
@lock.synchronize do
|
485
|
+
return connect! unless @raw_connection
|
486
|
+
|
487
|
+
# Have to deal with rollbacks differently than the AR adapter
|
488
|
+
@raw_connection.rollback
|
489
|
+
|
490
|
+
@raw_connection.execute("DISCARD ALL")
|
491
|
+
|
492
|
+
super
|
493
|
+
end
|
479
494
|
end
|
480
495
|
|
481
496
|
def default_sequence_name(table_name, pk = "id") #:nodoc:
|
@@ -660,6 +675,8 @@ module ArJdbc
|
|
660
675
|
::ActiveRecord::LockWaitTimeout.new(message, sql: sql, binds: binds)
|
661
676
|
when /canceling statement/ # This needs to come after lock timeout because the lock timeout message also contains "canceling statement"
|
662
677
|
::ActiveRecord::QueryCanceled.new(message, sql: sql, binds: binds)
|
678
|
+
when /relation "animals" does not exist/i
|
679
|
+
::ActiveRecord::StatementInvalid.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
663
680
|
else
|
664
681
|
super
|
665
682
|
end
|
@@ -742,7 +759,7 @@ module ActiveRecord::ConnectionAdapters
|
|
742
759
|
include ActiveRecord::ConnectionAdapters::PostgreSQL::SchemaStatements
|
743
760
|
include ActiveRecord::ConnectionAdapters::PostgreSQL::Quoting
|
744
761
|
|
745
|
-
include Jdbc::ConnectionPoolCallbacks
|
762
|
+
# include Jdbc::ConnectionPoolCallbacks
|
746
763
|
|
747
764
|
include ArJdbc::Abstract::Core
|
748
765
|
include ArJdbc::Abstract::ConnectionManagement
|
@@ -753,6 +770,7 @@ module ActiveRecord::ConnectionAdapters
|
|
753
770
|
|
754
771
|
require 'arjdbc/postgresql/oid_types'
|
755
772
|
include ::ArJdbc::PostgreSQL::OIDTypes
|
773
|
+
include ::ArJdbc::PostgreSQL::SchemaStatements
|
756
774
|
|
757
775
|
include ::ArJdbc::PostgreSQL::ColumnHelpers
|
758
776
|
|
@@ -761,16 +779,27 @@ module ActiveRecord::ConnectionAdapters
|
|
761
779
|
# AR expects OID to be available on the adapter
|
762
780
|
OID = ActiveRecord::ConnectionAdapters::PostgreSQL::OID
|
763
781
|
|
764
|
-
|
782
|
+
class << self
|
783
|
+
def jdbc_connection_class
|
784
|
+
::ActiveRecord::ConnectionAdapters::PostgreSQLJdbcConnection
|
785
|
+
end
|
786
|
+
|
787
|
+
def new_client(conn_params, adapter_instance)
|
788
|
+
jdbc_connection_class.new(conn_params, adapter_instance)
|
789
|
+
end
|
790
|
+
end
|
791
|
+
|
792
|
+
def initialize(...)
|
793
|
+
super
|
794
|
+
|
795
|
+
conn_params = @config.compact
|
796
|
+
|
797
|
+
@connection_parameters = conn_params
|
798
|
+
|
765
799
|
# @local_tz is initialized as nil to avoid warnings when connect tries to use it
|
766
800
|
@local_tz = nil
|
767
801
|
@max_identifier_length = nil
|
768
802
|
|
769
|
-
super(connection, logger, config) # configure_connection happens in super
|
770
|
-
|
771
|
-
@type_map = Type::HashLookupTypeMap.new
|
772
|
-
initialize_type_map
|
773
|
-
|
774
803
|
@use_insert_returning = @config.key?(:insert_returning) ?
|
775
804
|
self.class.type_cast_config_to_boolean(@config[:insert_returning]) : true
|
776
805
|
end
|
@@ -793,10 +822,6 @@ module ActiveRecord::ConnectionAdapters
|
|
793
822
|
public :sql_for_insert
|
794
823
|
alias :postgresql_version :database_version
|
795
824
|
|
796
|
-
def jdbc_connection_class(spec)
|
797
|
-
::ArJdbc::PostgreSQL.jdbc_connection_class
|
798
|
-
end
|
799
|
-
|
800
825
|
private
|
801
826
|
|
802
827
|
FEATURE_NOT_SUPPORTED = "0A000" # :nodoc:
|
@@ -829,8 +854,10 @@ module ActiveRecord::ConnectionAdapters
|
|
829
854
|
|
830
855
|
type_casted_binds = type_casted_binds(binds)
|
831
856
|
log(sql, name, binds, type_casted_binds, async: async) do
|
832
|
-
|
833
|
-
|
857
|
+
with_raw_connection do |conn|
|
858
|
+
result = conn.exec_params(sql, type_casted_binds)
|
859
|
+
verified!
|
860
|
+
result
|
834
861
|
end
|
835
862
|
end
|
836
863
|
end
|
@@ -67,28 +67,6 @@ module ArJdbc
|
|
67
67
|
|
68
68
|
# @private
|
69
69
|
module OIDTypes
|
70
|
-
|
71
|
-
# @override
|
72
|
-
def enable_extension(name)
|
73
|
-
result = super(name)
|
74
|
-
@extensions = nil
|
75
|
-
reload_type_map
|
76
|
-
result
|
77
|
-
end
|
78
|
-
|
79
|
-
# @override
|
80
|
-
def disable_extension(name)
|
81
|
-
result = super(name)
|
82
|
-
@extensions = nil
|
83
|
-
reload_type_map
|
84
|
-
result
|
85
|
-
end
|
86
|
-
|
87
|
-
# @override
|
88
|
-
def extensions
|
89
|
-
@extensions ||= super
|
90
|
-
end
|
91
|
-
|
92
70
|
def get_oid_type(oid, fmod, column_name, sql_type = '') # :nodoc:
|
93
71
|
# Note: type_map is storing a bunch of oid type prefixed with a namespace even
|
94
72
|
# if they are not namespaced (e.g. ""."oidvector"). builtin types which are
|
@@ -118,8 +96,15 @@ module ArJdbc
|
|
118
96
|
end
|
119
97
|
|
120
98
|
def reload_type_map
|
121
|
-
|
99
|
+
@lock.synchronize do
|
100
|
+
if @type_map
|
101
|
+
type_map.clear
|
102
|
+
else
|
103
|
+
@type_map = Type::HashLookupTypeMap.new
|
104
|
+
end
|
105
|
+
|
122
106
|
initialize_type_map
|
107
|
+
end
|
123
108
|
end
|
124
109
|
|
125
110
|
def initialize_type_map_inner(m)
|
@@ -274,10 +259,6 @@ module ArJdbc
|
|
274
259
|
$1.to_i if sql_type =~ /\((\d+)(,\d+)?\)/
|
275
260
|
end
|
276
261
|
|
277
|
-
def extract_limit(sql_type)
|
278
|
-
$1.to_i if sql_type =~ /\((.*)\)/
|
279
|
-
end
|
280
|
-
|
281
262
|
# Support arrays/ranges for defining attributes that don't exist in the db
|
282
263
|
ActiveRecord::Type.add_modifier({ array: true }, OID::Array, adapter: :postgresql)
|
283
264
|
ActiveRecord::Type.add_modifier({ range: true }, OID::Range, adapter: :postgresql)
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ArJdbc
|
4
|
+
module PostgreSQL
|
5
|
+
module SchemaStatements
|
6
|
+
ForeignKeyDefinition = ActiveRecord::ConnectionAdapters::ForeignKeyDefinition
|
7
|
+
Utils = ActiveRecord::ConnectionAdapters::PostgreSQL::Utils
|
8
|
+
|
9
|
+
def foreign_keys(table_name)
|
10
|
+
scope = quoted_scope(table_name)
|
11
|
+
fk_info = internal_exec_query(<<~SQL, "SCHEMA", allow_retry: true, materialize_transactions: false)
|
12
|
+
SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete, c.convalidated AS valid, c.condeferrable AS deferrable, c.condeferred AS deferred, c.conkey, c.confkey, c.conrelid, c.confrelid
|
13
|
+
FROM pg_constraint c
|
14
|
+
JOIN pg_class t1 ON c.conrelid = t1.oid
|
15
|
+
JOIN pg_class t2 ON c.confrelid = t2.oid
|
16
|
+
JOIN pg_attribute a1 ON a1.attnum = c.conkey[1] AND a1.attrelid = t1.oid
|
17
|
+
JOIN pg_attribute a2 ON a2.attnum = c.confkey[1] AND a2.attrelid = t2.oid
|
18
|
+
JOIN pg_namespace t3 ON c.connamespace = t3.oid
|
19
|
+
WHERE c.contype = 'f'
|
20
|
+
AND t1.relname = #{scope[:name]}
|
21
|
+
AND t3.nspname = #{scope[:schema]}
|
22
|
+
ORDER BY c.conname
|
23
|
+
SQL
|
24
|
+
|
25
|
+
fk_info.map do |row|
|
26
|
+
to_table = Utils.unquote_identifier(row["to_table"])
|
27
|
+
# conkey = row["conkey"].scan(/\d+/).map(&:to_i)
|
28
|
+
# confkey = row["confkey"].scan(/\d+/).map(&:to_i)
|
29
|
+
conkey = row["conkey"]
|
30
|
+
confkey = row["confkey"]
|
31
|
+
|
32
|
+
if conkey.size > 1
|
33
|
+
column = column_names_from_column_numbers(row["conrelid"], conkey)
|
34
|
+
primary_key = column_names_from_column_numbers(row["confrelid"], confkey)
|
35
|
+
else
|
36
|
+
column = Utils.unquote_identifier(row["column"])
|
37
|
+
primary_key = row["primary_key"]
|
38
|
+
end
|
39
|
+
|
40
|
+
options = {
|
41
|
+
column: column,
|
42
|
+
name: row["name"],
|
43
|
+
primary_key: primary_key
|
44
|
+
}
|
45
|
+
|
46
|
+
options[:on_delete] = extract_foreign_key_action(row["on_delete"])
|
47
|
+
options[:on_update] = extract_foreign_key_action(row["on_update"])
|
48
|
+
options[:deferrable] = extract_constraint_deferrable(row["deferrable"], row["deferred"])
|
49
|
+
|
50
|
+
options[:validate] = row["valid"]
|
51
|
+
|
52
|
+
ForeignKeyDefinition.new(table_name, to_table, options)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|