activerecord-jdbc-adapter 52.7-java → 60.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/.gitignore +1 -2
- data/.travis.yml +58 -37
- data/Gemfile +9 -2
- data/README.md +25 -9
- data/Rakefile +1 -1
- data/Rakefile.jdbc +8 -1
- data/activerecord-jdbc-adapter.gemspec +5 -8
- data/lib/arjdbc/abstract/connection_management.rb +7 -0
- data/lib/arjdbc/abstract/core.rb +16 -23
- data/lib/arjdbc/abstract/database_statements.rb +26 -2
- data/lib/arjdbc/abstract/statement_cache.rb +2 -5
- data/lib/arjdbc/abstract/transaction_support.rb +5 -3
- data/lib/arjdbc/db2/column.rb +0 -39
- data/lib/arjdbc/derby/adapter.rb +1 -20
- data/lib/arjdbc/firebird/adapter.rb +0 -21
- data/lib/arjdbc/h2/adapter.rb +0 -15
- data/lib/arjdbc/hsqldb/adapter.rb +0 -14
- data/lib/arjdbc/informix/adapter.rb +0 -23
- data/lib/arjdbc/jdbc/adapter.rb +3 -1
- data/lib/arjdbc/jdbc/adapter_require.rb +3 -1
- data/lib/arjdbc/jdbc/base_ext.rb +3 -1
- data/lib/arjdbc/jdbc/callbacks.rb +2 -0
- data/lib/arjdbc/jdbc/column.rb +2 -0
- data/lib/arjdbc/jdbc/connection.rb +2 -0
- data/lib/arjdbc/jdbc/connection_methods.rb +2 -0
- data/lib/arjdbc/jdbc/error.rb +2 -0
- data/lib/arjdbc/jdbc/extension.rb +2 -0
- data/lib/arjdbc/jdbc/java.rb +3 -1
- data/lib/arjdbc/jdbc/railtie.rb +3 -1
- data/lib/arjdbc/jdbc/rake_tasks.rb +3 -1
- data/lib/arjdbc/jdbc/serialized_attributes_helper.rb +3 -1
- data/lib/arjdbc/jdbc/type_cast.rb +2 -0
- data/lib/arjdbc/jdbc/type_converter.rb +2 -0
- data/lib/arjdbc/mysql/adapter.rb +47 -18
- data/lib/arjdbc/mysql/connection_methods.rb +0 -1
- data/lib/arjdbc/postgresql/adapter.rb +220 -213
- data/lib/arjdbc/postgresql/base/array_decoder.rb +2 -0
- data/lib/arjdbc/postgresql/base/array_encoder.rb +4 -2
- data/lib/arjdbc/postgresql/base/array_parser.rb +4 -2
- data/lib/arjdbc/postgresql/base/pgconn.rb +2 -0
- data/lib/arjdbc/postgresql/column.rb +6 -4
- data/lib/arjdbc/postgresql/connection_methods.rb +0 -1
- data/lib/arjdbc/postgresql/name.rb +2 -0
- data/lib/arjdbc/postgresql/oid_types.rb +2 -0
- data/lib/arjdbc/sqlite3/adapter.rb +175 -180
- data/lib/arjdbc/sqlite3/connection_methods.rb +15 -5
- data/lib/arjdbc/tasks/databases.rake +13 -10
- data/lib/arjdbc/util/quoted_cache.rb +3 -1
- data/lib/arjdbc/util/serialized_attributes.rb +3 -1
- data/lib/arjdbc/util/table_copier.rb +3 -1
- data/lib/arjdbc/version.rb +1 -1
- data/pom.xml +4 -4
- data/rakelib/01-tomcat.rake +2 -2
- data/rakelib/rails.rake +1 -1
- data/src/java/arjdbc/ArJdbcModule.java +5 -5
- data/src/java/arjdbc/jdbc/DriverWrapper.java +1 -9
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +434 -701
- data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +0 -51
- data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +13 -23
- data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +31 -24
- data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +94 -99
- metadata +8 -10
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# This implements a basic encoder to work around ActiveRecord's dependence on the pg gem
|
2
4
|
module ActiveRecord::ConnectionAdapters::PostgreSQL::OID
|
3
5
|
class Array < ActiveModel::Type::Value
|
@@ -6,10 +8,10 @@ module ActiveRecord::ConnectionAdapters::PostgreSQL::OID
|
|
6
8
|
class Array
|
7
9
|
|
8
10
|
def initialize(name:, delimiter:)
|
9
|
-
@type = if name == 'string[]'
|
11
|
+
@type = if name == 'string[]'
|
10
12
|
'text'.freeze
|
11
13
|
else
|
12
|
-
base_type = name.chomp('[]'
|
14
|
+
base_type = name.chomp('[]').to_sym
|
13
15
|
ActiveRecord::Base.connection.native_database_types[base_type][:name]
|
14
16
|
end
|
15
17
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# based on active_record/connection_adapters/postgresql/array_parser.rb
|
2
4
|
# until it's some day shareable with Rails ... this is not public API !
|
3
5
|
module ActiveRecord
|
@@ -33,7 +35,7 @@ module ActiveRecord
|
|
33
35
|
is_escaping = false
|
34
36
|
is_quoted = false
|
35
37
|
was_quoted = false
|
36
|
-
current_item = ''
|
38
|
+
current_item = ''.dup
|
37
39
|
|
38
40
|
local_index = index
|
39
41
|
while local_index
|
@@ -58,7 +60,7 @@ module ActiveRecord
|
|
58
60
|
is_escaping = true
|
59
61
|
when COMMA
|
60
62
|
add_item_to_array(array, current_item, was_quoted)
|
61
|
-
current_item = ''
|
63
|
+
current_item = ''.dup
|
62
64
|
was_quoted = false
|
63
65
|
when DOUBLE_QUOTE
|
64
66
|
is_quoted = true
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ArJdbc
|
2
4
|
module PostgreSQL
|
3
5
|
|
@@ -20,13 +22,13 @@ module ArJdbc
|
|
20
22
|
# Quoted types
|
21
23
|
when /\A[\(B]?'(.*)'.*::"?([\w. ]+)"?(?:\[\])?\z/m
|
22
24
|
# The default 'now'::date is CURRENT_DATE
|
23
|
-
if $1 == "now"
|
25
|
+
if $1 == "now" && $2 == "date"
|
24
26
|
nil
|
25
27
|
else
|
26
|
-
$1.gsub("''"
|
28
|
+
$1.gsub("''", "'")
|
27
29
|
end
|
28
30
|
# Boolean types
|
29
|
-
when 'true'
|
31
|
+
when 'true', 'false'
|
30
32
|
default
|
31
33
|
# Numeric types
|
32
34
|
when /\A\(?(-?\d+(\.\d*)?)\)?(::bigint)?\z/
|
@@ -46,7 +48,7 @@ module ArJdbc
|
|
46
48
|
end
|
47
49
|
|
48
50
|
def has_default_function?(default_value, default)
|
49
|
-
!default_value && %r{\w+\(.*\)|\(.*\)::\w+|CURRENT_DATE|CURRENT_TIMESTAMP}
|
51
|
+
!default_value && %r{\w+\(.*\)|\(.*\)::\w+|CURRENT_DATE|CURRENT_TIMESTAMP}.match?(default)
|
50
52
|
end
|
51
53
|
end
|
52
54
|
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
ArJdbc::ConnectionMethods.module_eval do
|
3
3
|
def postgresql_connection(config)
|
4
|
-
config = config.deep_dup
|
5
4
|
# NOTE: this isn't "really" necessary but Rails (in tests) assumes being able to :
|
6
5
|
# ActiveRecord::Base.postgresql_connection ActiveRecord::Base.configurations['arunit'].merge(:insert_returning => false)
|
7
6
|
# ... while using symbols by default but than configurations returning string keys ;(
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
ArJdbc.load_java_part :SQLite3
|
2
4
|
|
3
5
|
require "arjdbc/abstract/core"
|
@@ -30,7 +32,7 @@ module ArJdbc
|
|
30
32
|
SchemaCreation = ConnectionAdapters::SQLite3::SchemaCreation
|
31
33
|
SQLite3Adapter = ConnectionAdapters::AbstractAdapter
|
32
34
|
|
33
|
-
ADAPTER_NAME = 'SQLite'
|
35
|
+
ADAPTER_NAME = 'SQLite'
|
34
36
|
|
35
37
|
# DIFFERENCE: FQN
|
36
38
|
include ::ActiveRecord::ConnectionAdapters::SQLite3::Quoting
|
@@ -54,20 +56,8 @@ module ArJdbc
|
|
54
56
|
# DIFFERENCE: class_attribute in original adapter is moved down to our section which is a class
|
55
57
|
# since we cannot define it here in the module (original source this is a class).
|
56
58
|
|
57
|
-
class StatementPool < ConnectionAdapters::StatementPool
|
58
|
-
private
|
59
|
-
|
60
|
-
def dealloc(stmt)
|
61
|
-
stmt[:stmt].close unless stmt[:stmt].closed?
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
59
|
def initialize(connection, logger, connection_options, config)
|
66
60
|
super(connection, logger, config)
|
67
|
-
|
68
|
-
@active = true
|
69
|
-
@statements = StatementPool.new(self.class.type_cast_config_to_integer(config[:statement_limit]))
|
70
|
-
|
71
61
|
configure_connection
|
72
62
|
end
|
73
63
|
|
@@ -80,15 +70,19 @@ module ArJdbc
|
|
80
70
|
end
|
81
71
|
|
82
72
|
def supports_partial_index?
|
83
|
-
|
73
|
+
database_version >= "3.9.0"
|
74
|
+
end
|
75
|
+
|
76
|
+
def supports_expression_index?
|
77
|
+
database_version >= "3.9.0"
|
84
78
|
end
|
85
79
|
|
86
80
|
def requires_reloading?
|
87
81
|
true
|
88
82
|
end
|
89
83
|
|
90
|
-
def
|
91
|
-
|
84
|
+
def supports_foreign_keys?
|
85
|
+
true
|
92
86
|
end
|
93
87
|
|
94
88
|
def supports_views?
|
@@ -99,26 +93,18 @@ module ArJdbc
|
|
99
93
|
true
|
100
94
|
end
|
101
95
|
|
102
|
-
def
|
103
|
-
|
104
|
-
end
|
105
|
-
|
106
|
-
def active?
|
107
|
-
@active
|
96
|
+
def supports_json?
|
97
|
+
true
|
108
98
|
end
|
109
99
|
|
110
|
-
|
111
|
-
|
112
|
-
def disconnect!
|
113
|
-
super
|
114
|
-
@active = false
|
115
|
-
@connection.close rescue nil
|
100
|
+
def supports_insert_on_conflict?
|
101
|
+
database_version >= "3.24.0"
|
116
102
|
end
|
103
|
+
alias supports_insert_on_duplicate_skip? supports_insert_on_conflict?
|
104
|
+
alias supports_insert_on_duplicate_update? supports_insert_on_conflict?
|
105
|
+
alias supports_insert_conflict_target? supports_insert_on_conflict?
|
117
106
|
|
118
|
-
#
|
119
|
-
def clear_cache!
|
120
|
-
@statements.clear
|
121
|
-
end
|
107
|
+
# DIFFERENCE: active?, reconnect!, disconnect! handles by arjdbc core
|
122
108
|
|
123
109
|
def supports_index_sort_order?
|
124
110
|
true
|
@@ -144,90 +130,66 @@ module ArJdbc
|
|
144
130
|
true
|
145
131
|
end
|
146
132
|
|
133
|
+
def supports_lazy_transactions?
|
134
|
+
true
|
135
|
+
end
|
136
|
+
|
147
137
|
# REFERENTIAL INTEGRITY ====================================
|
148
138
|
|
149
139
|
def disable_referential_integrity # :nodoc:
|
150
|
-
|
140
|
+
old_foreign_keys = query_value("PRAGMA foreign_keys")
|
141
|
+
old_defer_foreign_keys = query_value("PRAGMA defer_foreign_keys")
|
151
142
|
|
152
143
|
begin
|
144
|
+
execute("PRAGMA defer_foreign_keys = ON")
|
153
145
|
execute("PRAGMA foreign_keys = OFF")
|
154
146
|
yield
|
155
147
|
ensure
|
156
|
-
execute("PRAGMA
|
148
|
+
execute("PRAGMA defer_foreign_keys = #{old_defer_foreign_keys}")
|
149
|
+
execute("PRAGMA foreign_keys = #{old_foreign_keys}")
|
157
150
|
end
|
158
151
|
end
|
159
|
-
|
152
|
+
|
160
153
|
#--
|
161
154
|
# DATABASE STATEMENTS ======================================
|
162
155
|
#++
|
163
156
|
|
157
|
+
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(:begin, :commit, :explain, :select, :pragma, :release, :savepoint, :rollback) # :nodoc:
|
158
|
+
private_constant :READ_QUERY
|
159
|
+
|
160
|
+
def write_query?(sql) # :nodoc:
|
161
|
+
!READ_QUERY.match?(sql)
|
162
|
+
end
|
163
|
+
|
164
164
|
def explain(arel, binds = [])
|
165
165
|
sql = "EXPLAIN QUERY PLAN #{to_sql(arel, binds)}"
|
166
166
|
# DIFFERENCE: FQN
|
167
167
|
::ActiveRecord::ConnectionAdapters::SQLite3::ExplainPrettyPrinter.new.pp(exec_query(sql, "EXPLAIN", []))
|
168
168
|
end
|
169
169
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
log(sql, name, binds, type_casted_binds) do
|
174
|
-
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
175
|
-
# Don't cache statements if they are not prepared
|
176
|
-
unless prepare
|
177
|
-
stmt = @connection.prepare(sql)
|
178
|
-
begin
|
179
|
-
cols = stmt.columns
|
180
|
-
unless without_prepared_statement?(binds)
|
181
|
-
stmt.bind_params(type_casted_binds)
|
182
|
-
end
|
183
|
-
records = stmt.to_a
|
184
|
-
ensure
|
185
|
-
stmt.close
|
186
|
-
end
|
187
|
-
else
|
188
|
-
cache = @statements[sql] ||= {
|
189
|
-
stmt: @connection.prepare(sql)
|
190
|
-
}
|
191
|
-
stmt = cache[:stmt]
|
192
|
-
cols = cache[:cols] ||= stmt.columns
|
193
|
-
stmt.reset!
|
194
|
-
stmt.bind_params(type_casted_binds)
|
195
|
-
records = stmt.to_a
|
196
|
-
end
|
170
|
+
# DIFFERENCE: implemented in ArJdbc::Abstract::DatabaseStatements
|
171
|
+
#def exec_query(sql, name = nil, binds = [], prepare: false)
|
197
172
|
|
198
|
-
|
199
|
-
|
200
|
-
end
|
201
|
-
end
|
202
|
-
|
203
|
-
def exec_delete(sql, name = 'SQL', binds = [])
|
204
|
-
exec_query(sql, name, binds)
|
205
|
-
@connection.changes
|
206
|
-
end
|
207
|
-
alias :exec_update :exec_delete
|
173
|
+
# DIFFERENCE: implemented in ArJdbc::Abstract::DatabaseStatements
|
174
|
+
#def exec_delete(sql, name = "SQL", binds = [])
|
208
175
|
|
209
176
|
def last_inserted_id(result)
|
210
177
|
@connection.last_insert_row_id
|
211
178
|
end
|
212
179
|
|
213
|
-
|
214
|
-
|
215
|
-
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
216
|
-
@connection.execute(sql)
|
217
|
-
end
|
218
|
-
end
|
219
|
-
end
|
180
|
+
# DIFFERENCE: implemented in ArJdbc::Abstract::DatabaseStatements
|
181
|
+
#def execute(sql, name = nil) #:nodoc:
|
220
182
|
|
221
183
|
def begin_db_transaction #:nodoc:
|
222
|
-
log("begin transaction",nil) { @connection.transaction }
|
184
|
+
log("begin transaction", nil) { @connection.transaction }
|
223
185
|
end
|
224
186
|
|
225
187
|
def commit_db_transaction #:nodoc:
|
226
|
-
log("commit transaction",nil) { @connection.commit }
|
188
|
+
log("commit transaction", nil) { @connection.commit }
|
227
189
|
end
|
228
190
|
|
229
191
|
def exec_rollback_db_transaction #:nodoc:
|
230
|
-
log("rollback transaction",nil) { @connection.rollback }
|
192
|
+
log("rollback transaction", nil) { @connection.rollback }
|
231
193
|
end
|
232
194
|
|
233
195
|
# SCHEMA STATEMENTS ========================================
|
@@ -251,13 +213,6 @@ module ArJdbc
|
|
251
213
|
rename_table_indexes(table_name, new_name)
|
252
214
|
end
|
253
215
|
|
254
|
-
# DIFFERENCE: deprecated causes a JRuby 9.1 bug where "super" calls itself -> do inline
|
255
|
-
def valid_alter_table_type?(type, options = {})
|
256
|
-
ActiveSupport::Deprecation.deprecation_warning(__method__)
|
257
|
-
!invalid_alter_table_type?(type, options)
|
258
|
-
end
|
259
|
-
#deprecate :valid_alter_table_type?
|
260
|
-
|
261
216
|
def add_column(table_name, column_name, type, options = {}) #:nodoc:
|
262
217
|
if invalid_alter_table_type?(type, options)
|
263
218
|
alter_table(table_name) do |definition|
|
@@ -271,6 +226,9 @@ module ArJdbc
|
|
271
226
|
def remove_column(table_name, column_name, type = nil, options = {}) #:nodoc:
|
272
227
|
alter_table(table_name) do |definition|
|
273
228
|
definition.remove_column column_name
|
229
|
+
definition.foreign_keys.delete_if do |_, fk_options|
|
230
|
+
fk_options[:column] == column_name.to_s
|
231
|
+
end
|
274
232
|
end
|
275
233
|
end
|
276
234
|
|
@@ -330,14 +288,6 @@ module ArJdbc
|
|
330
288
|
end
|
331
289
|
end
|
332
290
|
|
333
|
-
def insert_fixtures(rows, table_name)
|
334
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
335
|
-
`insert_fixtures` is deprecated and will be removed in the next version of Rails.
|
336
|
-
Consider using `insert_fixtures_set` for performance improvement.
|
337
|
-
MSG
|
338
|
-
insert_fixtures_set(table_name => rows)
|
339
|
-
end
|
340
|
-
|
341
291
|
def insert_fixtures_set(fixture_set, tables_to_delete = [])
|
342
292
|
disable_referential_integrity do
|
343
293
|
transaction(requires_new: true) do
|
@@ -349,8 +299,44 @@ module ArJdbc
|
|
349
299
|
end
|
350
300
|
end
|
351
301
|
end
|
352
|
-
|
302
|
+
|
303
|
+
def build_insert_sql(insert) # :nodoc:
|
304
|
+
sql = +"INSERT #{insert.into} #{insert.values_list}"
|
305
|
+
|
306
|
+
if insert.skip_duplicates?
|
307
|
+
sql << " ON CONFLICT #{insert.conflict_target} DO NOTHING"
|
308
|
+
elsif insert.update_duplicates?
|
309
|
+
sql << " ON CONFLICT #{insert.conflict_target} DO UPDATE SET "
|
310
|
+
sql << insert.updatable_columns.map { |column| "#{column}=excluded.#{column}" }.join(",")
|
311
|
+
end
|
312
|
+
|
313
|
+
sql
|
314
|
+
end
|
315
|
+
|
316
|
+
def get_database_version # :nodoc:
|
317
|
+
SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)"))
|
318
|
+
end
|
319
|
+
|
320
|
+
def build_truncate_statements(*table_names)
|
321
|
+
truncate_tables = table_names.map do |table_name|
|
322
|
+
"DELETE FROM #{quote_table_name(table_name)}"
|
323
|
+
end
|
324
|
+
combine_multi_statements(truncate_tables)
|
325
|
+
end
|
326
|
+
|
327
|
+
def check_version
|
328
|
+
if database_version < "3.8.0"
|
329
|
+
raise "Your version of SQLite (#{database_version}) is too old. Active Record supports SQLite >= 3.8."
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
353
333
|
private
|
334
|
+
# See https://www.sqlite.org/limits.html,
|
335
|
+
# the default value is 999 when not configured.
|
336
|
+
def bind_params_length
|
337
|
+
999
|
338
|
+
end
|
339
|
+
|
354
340
|
def initialize_type_map(m = type_map)
|
355
341
|
super
|
356
342
|
register_class_with_limit m, %r(int)i, SQLite3Integer
|
@@ -369,14 +355,27 @@ module ArJdbc
|
|
369
355
|
type.to_sym == :primary_key || options[:primary_key]
|
370
356
|
end
|
371
357
|
|
372
|
-
def alter_table(table_name,
|
358
|
+
def alter_table(table_name, foreign_keys = foreign_keys(table_name), **options)
|
373
359
|
altered_table_name = "a#{table_name}"
|
374
|
-
|
360
|
+
|
361
|
+
caller = lambda do |definition|
|
362
|
+
rename = options[:rename] || {}
|
363
|
+
foreign_keys.each do |fk|
|
364
|
+
if column = rename[fk.options[:column]]
|
365
|
+
fk.options[:column] = column
|
366
|
+
end
|
367
|
+
to_table = strip_table_name_prefix_and_suffix(fk.to_table)
|
368
|
+
definition.foreign_key(to_table, fk.options)
|
369
|
+
end
|
370
|
+
|
371
|
+
yield definition if block_given?
|
372
|
+
end
|
375
373
|
|
376
374
|
transaction do
|
377
|
-
|
378
|
-
|
379
|
-
|
375
|
+
disable_referential_integrity do
|
376
|
+
move_table(table_name, altered_table_name, options.merge(temporary: true))
|
377
|
+
move_table(altered_table_name, table_name, &caller)
|
378
|
+
end
|
380
379
|
end
|
381
380
|
end
|
382
381
|
|
@@ -395,23 +394,24 @@ module ArJdbc
|
|
395
394
|
end
|
396
395
|
columns(from).each do |column|
|
397
396
|
column_name = options[:rename] ?
|
398
|
-
|
399
|
-
|
400
|
-
|
397
|
+
(options[:rename][column.name] ||
|
398
|
+
options[:rename][column.name.to_sym] ||
|
399
|
+
column.name) : column.name
|
401
400
|
|
402
401
|
@definition.column(column_name, column.type,
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
402
|
+
limit: column.limit, default: column.default,
|
403
|
+
precision: column.precision, scale: column.scale,
|
404
|
+
null: column.null, collation: column.collation,
|
405
|
+
primary_key: column_name == from_primary_key
|
407
406
|
)
|
408
407
|
end
|
408
|
+
|
409
409
|
yield @definition if block_given?
|
410
410
|
end
|
411
411
|
copy_table_indexes(from, to, options[:rename] || {})
|
412
412
|
copy_table_contents(from, to,
|
413
|
-
|
414
|
-
|
413
|
+
@definition.columns.map(&:name),
|
414
|
+
options[:rename] || {})
|
415
415
|
end
|
416
416
|
|
417
417
|
def copy_table_indexes(from, to, rename = {})
|
@@ -426,9 +426,12 @@ module ArJdbc
|
|
426
426
|
name = name[1..-1]
|
427
427
|
end
|
428
428
|
|
429
|
-
|
430
|
-
|
431
|
-
to_column_names.
|
429
|
+
columns = index.columns
|
430
|
+
if columns.is_a?(Array)
|
431
|
+
to_column_names = columns(to).map(&:name)
|
432
|
+
columns = columns.map { |c| rename[c] || c }.select do |column|
|
433
|
+
to_column_names.include?(column)
|
434
|
+
end
|
432
435
|
end
|
433
436
|
|
434
437
|
unless columns.empty?
|
@@ -454,27 +457,23 @@ module ArJdbc
|
|
454
457
|
SELECT #{quoted_from_columns} FROM #{quote_table_name(from)}")
|
455
458
|
end
|
456
459
|
|
457
|
-
def
|
458
|
-
@sqlite_version ||= SQLite3Adapter::Version.new(select_value("select sqlite_version(*)"))
|
459
|
-
end
|
460
|
-
|
461
|
-
def translate_exception(exception, message)
|
460
|
+
def translate_exception(exception, message:, sql:, binds:)
|
462
461
|
case exception.message
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
462
|
+
# SQLite 3.8.2 returns a newly formatted error message:
|
463
|
+
# UNIQUE constraint failed: *table_name*.*column_name*
|
464
|
+
# Older versions of SQLite return:
|
465
|
+
# column *column_name* is not unique
|
466
|
+
when /column(s)? .* (is|are) not unique/, /UNIQUE constraint failed: .*/
|
467
|
+
# DIFFERENCE: FQN
|
468
|
+
::ActiveRecord::RecordNotUnique.new(message, sql: sql, binds: binds)
|
469
|
+
when /.* may not be NULL/, /NOT NULL constraint failed: .*/
|
470
|
+
# DIFFERENCE: FQN
|
471
|
+
::ActiveRecord::NotNullViolation.new(message, sql: sql, binds: binds)
|
472
|
+
when /FOREIGN KEY constraint failed/i
|
473
|
+
# DIFFERENCE: FQN
|
474
|
+
::ActiveRecord::InvalidForeignKey.new(message, sql: sql, binds: binds)
|
475
|
+
else
|
476
|
+
super
|
478
477
|
end
|
479
478
|
end
|
480
479
|
|
@@ -482,11 +481,11 @@ module ArJdbc
|
|
482
481
|
|
483
482
|
def table_structure_with_collation(table_name, basic_structure)
|
484
483
|
collation_hash = {}
|
485
|
-
sql =
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
484
|
+
sql = <<~SQL
|
485
|
+
SELECT sql FROM
|
486
|
+
(SELECT * FROM sqlite_master UNION ALL
|
487
|
+
SELECT * FROM sqlite_temp_master)
|
488
|
+
WHERE type = 'table' AND name = #{quote(table_name)}
|
490
489
|
SQL
|
491
490
|
|
492
491
|
# Result will have following sample string
|
@@ -495,9 +494,9 @@ module ArJdbc
|
|
495
494
|
result = exec_query(sql, "SCHEMA").first
|
496
495
|
|
497
496
|
if result
|
498
|
-
# Splitting with left parentheses and
|
497
|
+
# Splitting with left parentheses and discarding the first part will return all
|
499
498
|
# columns separated with comma(,).
|
500
|
-
columns_string = result["sql"].split("(").last
|
499
|
+
columns_string = result["sql"].split("(", 2).last
|
501
500
|
|
502
501
|
columns_string.split(",").each do |column_string|
|
503
502
|
# This regex will match the column name and collation type and will save
|
@@ -515,7 +514,7 @@ module ArJdbc
|
|
515
514
|
column
|
516
515
|
end
|
517
516
|
else
|
518
|
-
basic_structure.
|
517
|
+
basic_structure.to_a
|
519
518
|
end
|
520
519
|
end
|
521
520
|
|
@@ -597,24 +596,6 @@ module ActiveRecord::ConnectionAdapters
|
|
597
596
|
|
598
597
|
private
|
599
598
|
|
600
|
-
# @override {ActiveRecord::ConnectionAdapters::Column#simplified_type}
|
601
|
-
def simplified_type(field_type)
|
602
|
-
case field_type
|
603
|
-
when /boolean/i then :boolean
|
604
|
-
when /text/i then :text
|
605
|
-
when /varchar/i then :string
|
606
|
-
when /int/i then :integer
|
607
|
-
when /float/i then :float
|
608
|
-
when /real|decimal/i then
|
609
|
-
extract_scale(field_type) == 0 ? :integer : :decimal
|
610
|
-
when /datetime/i then :datetime
|
611
|
-
when /date/i then :date
|
612
|
-
when /time/i then :time
|
613
|
-
when /blob/i then :binary
|
614
|
-
else super
|
615
|
-
end
|
616
|
-
end
|
617
|
-
|
618
599
|
# @override {ActiveRecord::ConnectionAdapters::Column#extract_limit}
|
619
600
|
def extract_limit(sql_type)
|
620
601
|
return nil if sql_type =~ /^(real)\(\d+/i
|
@@ -646,28 +627,31 @@ module ActiveRecord::ConnectionAdapters
|
|
646
627
|
class SQLite3Adapter < AbstractAdapter
|
647
628
|
include ArJdbc::Abstract::Core
|
648
629
|
include ArJdbc::SQLite3
|
630
|
+
include ArJdbc::Abstract::ConnectionManagement
|
649
631
|
include ArJdbc::Abstract::DatabaseStatements
|
650
632
|
include ArJdbc::Abstract::StatementCache
|
651
633
|
include ArJdbc::Abstract::TransactionSupport
|
652
634
|
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
635
|
+
def self.represent_boolean_as_integer=(value) # :nodoc:
|
636
|
+
if value == false
|
637
|
+
raise "`.represent_boolean_as_integer=` is now always true, so make sure your application can work with it and remove this settings."
|
638
|
+
end
|
639
|
+
|
640
|
+
ActiveSupport::Deprecation.warn(
|
641
|
+
"`.represent_boolean_as_integer=` is now always true, so setting this is deprecated and will be removed in Rails 6.1."
|
642
|
+
)
|
643
|
+
end
|
644
|
+
|
645
|
+
def self.database_exists?(config)
|
646
|
+
config = config.symbolize_keys
|
647
|
+
if config[:database] == ":memory:"
|
648
|
+
return true
|
649
|
+
else
|
650
|
+
database_file = defined?(Rails.root) ? File.expand_path(config[:database], Rails.root) : config[:database]
|
651
|
+
File.exist?(database_file)
|
652
|
+
end
|
653
|
+
end
|
654
|
+
|
671
655
|
|
672
656
|
def supports_transaction_isolation?
|
673
657
|
false
|
@@ -676,7 +660,7 @@ module ActiveRecord::ConnectionAdapters
|
|
676
660
|
def begin_isolated_db_transaction(isolation)
|
677
661
|
raise ActiveRecord::TransactionIsolationError, 'adapter does not support setting transaction isolation'
|
678
662
|
end
|
679
|
-
|
663
|
+
|
680
664
|
# SQLite driver doesn't support all types of insert statements with executeUpdate so
|
681
665
|
# make it act like a regular query and the ids will be returned from #last_inserted_id
|
682
666
|
# example: INSERT INTO "aircraft" DEFAULT VALUES
|
@@ -699,5 +683,16 @@ module ActiveRecord::ConnectionAdapters
|
|
699
683
|
|
700
684
|
# Note: This is not an override of ours but a moved line from AR Sqlite3Adapter to register ours vs our copied module (which would be their class).
|
701
685
|
# ActiveSupport.run_load_hooks(:active_record_sqlite3adapter, SQLite3Adapter)
|
686
|
+
|
687
|
+
private
|
688
|
+
|
689
|
+
# because the JDBC driver doesn't like multiple SQL statements in one JDBC statement
|
690
|
+
def combine_multi_statements(total_sql)
|
691
|
+
if total_sql.length == 1
|
692
|
+
total_sql.first
|
693
|
+
else
|
694
|
+
total_sql
|
695
|
+
end
|
696
|
+
end
|
702
697
|
end
|
703
698
|
end
|