activerecord-jdbc-adapter 52.8-java → 60.0-java
Sign up to get free protection for your applications and to get access to all the features.
- 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_java.jar +0 -0
- 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 +7 -9
@@ -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
|