activerecord-jdbc-alt-adapter 72.1.0-java → 80.1.0.beta1-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 +23 -16
- data/.github/workflows/ruby.yml +123 -18
- data/.mise.toml +3 -0
- data/Gemfile +43 -48
- data/README.md +3 -2
- data/RUNNING_TESTS.md +9 -1
- data/Rakefile +63 -15
- data/activerecord-jdbc-adapter.gemspec +2 -2
- data/activerecord-jdbc-alt-adapter.gemspec +1 -1
- data/lib/arjdbc/abstract/core.rb +0 -17
- data/lib/arjdbc/abstract/database_statements.rb +19 -38
- data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
- data/lib/arjdbc/mssql/adapter.rb +12 -11
- data/lib/arjdbc/mssql/column.rb +2 -2
- data/lib/arjdbc/mssql/database_statements.rb +31 -29
- data/lib/arjdbc/mssql/explain_support.rb +6 -1
- data/lib/arjdbc/mssql/schema_creation.rb +1 -1
- data/lib/arjdbc/mssql/schema_statements.rb +4 -0
- data/lib/arjdbc/mssql/type_metadata.rb +36 -0
- data/lib/arjdbc/mssql/types/binary_types.rb +5 -4
- data/lib/arjdbc/mssql/types/deprecated_types.rb +15 -12
- data/lib/arjdbc/mssql/types/string_types.rb +10 -8
- data/lib/arjdbc/mssql.rb +1 -1
- data/lib/arjdbc/postgresql/adapter.rb +4 -5
- data/lib/arjdbc/postgresql/database_statements.rb +45 -0
- data/lib/arjdbc/postgresql/schema_statements.rb +24 -0
- data/lib/arjdbc/sqlite3/adapter.rb +51 -7
- data/lib/arjdbc/sqlite3/database_statements.rb +26 -0
- data/lib/arjdbc/tasks/mssql_database_tasks.rb +1 -21
- data/lib/arjdbc/version.rb +1 -1
- data/pom.xml +3 -3
- data/rakelib/02-test.rake +1 -1
- data/rakelib/db.rake +5 -3
- data/rakelib/rails.rake +0 -1
- data/src/java/arjdbc/ArJdbcModule.java +13 -10
- data/src/java/arjdbc/db2/DB2Module.java +4 -4
- data/src/java/arjdbc/db2/DB2RubyJdbcConnection.java +8 -9
- data/src/java/arjdbc/h2/H2Module.java +2 -1
- data/src/java/arjdbc/h2/H2RubyJdbcConnection.java +8 -7
- data/src/java/arjdbc/hsqldb/HSQLDBModule.java +5 -6
- data/src/java/arjdbc/jdbc/DataSourceConnectionFactory.java +4 -3
- data/src/java/arjdbc/jdbc/DriverWrapper.java +13 -8
- data/src/java/arjdbc/jdbc/JdbcResult.java +10 -7
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +171 -155
- data/src/java/arjdbc/mssql/MSSQLModule.java +3 -3
- data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +13 -9
- data/src/java/arjdbc/mysql/MySQLModule.java +3 -3
- data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +25 -23
- data/src/java/arjdbc/oracle/OracleModule.java +2 -3
- data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +22 -18
- data/src/java/arjdbc/postgresql/PostgreSQLModule.java +2 -3
- data/src/java/arjdbc/postgresql/PostgreSQLResult.java +24 -12
- data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +16 -12
- data/src/java/arjdbc/sqlite3/SQLite3Module.java +2 -3
- data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +78 -29
- data/src/java/arjdbc/util/DateTimeUtils.java +7 -5
- data/src/java/arjdbc/util/ObjectSupport.java +2 -2
- data/src/java/arjdbc/util/StringHelper.java +1 -1
- metadata +8 -6
- data/.travis.yml +0 -128
data/Rakefile
CHANGED
|
@@ -5,6 +5,21 @@
|
|
|
5
5
|
#
|
|
6
6
|
# Environment variables used by this Rakefile:
|
|
7
7
|
#
|
|
8
|
+
# DBS
|
|
9
|
+
# Limits the command performed to only work for one of the database
|
|
10
|
+
# types listed in this env var. You can set to a combination of mysql,
|
|
11
|
+
# postgres, or sqlite, separated by commas. For example:
|
|
12
|
+
#
|
|
13
|
+
# mysql,postgres,sqlite
|
|
14
|
+
#
|
|
15
|
+
# You may use pg or postgres as aliases for postgresql
|
|
16
|
+
# You may use sqlite3 as an alias for sqlite
|
|
17
|
+
# You may use all to mean all three
|
|
18
|
+
#
|
|
19
|
+
# NOTE: if you ever want to add a new type of database to be released,
|
|
20
|
+
# just fix up this documentation, the error string in invalid_dbs,
|
|
21
|
+
# and add it to the ALL_DBS array. Everything else should just work!
|
|
22
|
+
#
|
|
8
23
|
# INCLUDE_JAR_IN_GEM [default task - false, other taks - true]:
|
|
9
24
|
# Note: This is something you should not normally have to set.
|
|
10
25
|
# For local development we always will end up including the jar file
|
|
@@ -85,6 +100,12 @@ end
|
|
|
85
100
|
|
|
86
101
|
desc "Releasing AR-JDBC gems (use NOOP=true to disable gem pushing)"
|
|
87
102
|
task 'release:do' do
|
|
103
|
+
unless ENV["DBS"]
|
|
104
|
+
puts "you must explicitly provide a DBS env var when calling release:do. An empty one will not default to 'all' " \
|
|
105
|
+
"for this command\n\n"
|
|
106
|
+
invalid_dbs!
|
|
107
|
+
end
|
|
108
|
+
|
|
88
109
|
Rake::Task['build'].invoke
|
|
89
110
|
# Rake::Task['build:adapters'].invoke
|
|
90
111
|
|
|
@@ -107,8 +128,41 @@ task 'release:push' do
|
|
|
107
128
|
sh "for gem in `ls pkg/*-#{current_version.call}-java.gem`; do gem push $gem; done"
|
|
108
129
|
end
|
|
109
130
|
|
|
110
|
-
|
|
111
|
-
|
|
131
|
+
ALL_DBS = ["mysql", "postgresql", "sqlite3"] #NOTE: if we add a new database type to be released, just add it here!
|
|
132
|
+
DB_ALIASES = ALL_DBS.map {|db| [db, db]}.to_h.merge({
|
|
133
|
+
"pg" => "postgresql",
|
|
134
|
+
"postgres" => "postgresql",
|
|
135
|
+
"sqlite" => "sqlite3"
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
def invalid_dbs!
|
|
139
|
+
raise ArgumentError, "Invalid DBS env var\nThe DBS env var must be set to a combination of mysql, postgres, or " \
|
|
140
|
+
"sqlite, separated by commas. For example:\n\nmysql,postgres,sqlite\n\nYou may use pg or " \
|
|
141
|
+
"postgres as aliases for postgresql\nYou may use sqlite3 as an alias for sqlite\n" \
|
|
142
|
+
"You may use all as a shortcut to listing them all out"
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def make_db_list
|
|
146
|
+
env_dbs = ENV["DBS"]
|
|
147
|
+
return ALL_DBS if !env_dbs || env_dbs == "all"
|
|
148
|
+
requested = env_dbs.split(",").map(&:strip).reject(&:empty?).map(&:downcase)
|
|
149
|
+
invalid_dbs! unless requested.size > 0 && requested == requested.uniq
|
|
150
|
+
|
|
151
|
+
canonical = requested.map do |name|
|
|
152
|
+
DB_ALIASES.fetch(name) { invalid_dbs! }
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
invalid_dbs! unless canonical == canonical.uniq
|
|
156
|
+
|
|
157
|
+
canonical
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
db_list = make_db_list
|
|
161
|
+
ADAPTERS = db_list.map { |db| "activerecord-jdbc#{db}-adapter" }
|
|
162
|
+
|
|
163
|
+
db_list.map! {|db| db == 'postgresql' ? 'postgres' : db } #naming convention for DRIVERS
|
|
164
|
+
DRIVERS = db_list.map { |a| "jdbc-#{a}" }
|
|
165
|
+
|
|
112
166
|
TARGETS = ( ADAPTERS + DRIVERS )
|
|
113
167
|
|
|
114
168
|
ADAPTERS.each do |target|
|
|
@@ -185,7 +239,7 @@ if defined? JRUBY_VERSION
|
|
|
185
239
|
#directory classes = 'pkg/classes'; CLEAN << classes
|
|
186
240
|
|
|
187
241
|
file jar_file => FileList[ 'src/java/**/*.java' ] do
|
|
188
|
-
source = target = '
|
|
242
|
+
source = target = '21'; debug = true
|
|
189
243
|
|
|
190
244
|
get_driver_jars_local = lambda do |*args|
|
|
191
245
|
driver_deps = args.empty? ? [ :Postgres, :MySQL ] : args
|
|
@@ -230,7 +284,7 @@ if defined? JRUBY_VERSION
|
|
|
230
284
|
if match = requirement.match(/^jar\s+([\w\-\.]+):([\w\-]+),\s+?([\w\.\-]+)?/)
|
|
231
285
|
matched_jar = Jars.send :to_jar, match[1], match[2], match[3], nil
|
|
232
286
|
matched_jar = File.join( Jars.home, matched_jar )
|
|
233
|
-
matched_jars << matched_jar if File.
|
|
287
|
+
matched_jars << matched_jar if File.exist?( matched_jar )
|
|
234
288
|
end
|
|
235
289
|
end
|
|
236
290
|
matched_jars
|
|
@@ -262,18 +316,12 @@ if defined? JRUBY_VERSION
|
|
|
262
316
|
end
|
|
263
317
|
|
|
264
318
|
classpath = []
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
if classpath.empty?; require 'rbconfig'
|
|
270
|
-
libdir = RbConfig::CONFIG['libdir']
|
|
271
|
-
if libdir.start_with? 'classpath:'
|
|
272
|
-
error "Cannot build activerecord-jdbc with jruby-complete"
|
|
273
|
-
end
|
|
274
|
-
classpath << File.join(libdir, 'jruby.jar')
|
|
319
|
+
require 'rbconfig'
|
|
320
|
+
libdir = RbConfig::CONFIG['libdir']
|
|
321
|
+
if libdir.start_with? 'classpath:'
|
|
322
|
+
error "Cannot build activerecord-jdbc with jruby-complete"
|
|
275
323
|
end
|
|
276
|
-
|
|
324
|
+
classpath << File.join(libdir, 'jruby.jar')
|
|
277
325
|
classpath += driver_jars
|
|
278
326
|
classpath = classpath.compact.join(File::PATH_SEPARATOR)
|
|
279
327
|
|
|
@@ -10,7 +10,7 @@ Gem::Specification.new do |gem|
|
|
|
10
10
|
gem.homepage = 'https://github.com/jruby/activerecord-jdbc-adapter'
|
|
11
11
|
gem.license = 'BSD-2-Clause'
|
|
12
12
|
gem.summary = 'JDBC adapter for ActiveRecord, for use within JRuby on Rails.'
|
|
13
|
-
gem.description = "" <<
|
|
13
|
+
gem.description = +"" <<
|
|
14
14
|
"AR-JDBC is a database adapter for Rails' ActiveRecord component " <<
|
|
15
15
|
"designed to be used with JRuby built upon Java's JDBC API for " <<
|
|
16
16
|
"database access. Provides (ActiveRecord) built-in adapters: MySQL, " <<
|
|
@@ -41,7 +41,7 @@ Gem::Specification.new do |gem|
|
|
|
41
41
|
gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
|
|
42
42
|
gem.test_files = gem.files.grep(%r{^test/})
|
|
43
43
|
|
|
44
|
-
gem.add_dependency "activerecord", "~>
|
|
44
|
+
gem.add_dependency "activerecord", "~> 8.1.0"
|
|
45
45
|
|
|
46
46
|
#gem.add_development_dependency 'test-unit', '2.5.4'
|
|
47
47
|
#gem.add_development_dependency 'test-unit-context', '>= 0.3.0'
|
|
@@ -43,7 +43,7 @@ Gem::Specification.new do |gem|
|
|
|
43
43
|
gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
|
|
44
44
|
gem.test_files = gem.files.grep(%r{^test/})
|
|
45
45
|
|
|
46
|
-
gem.add_dependency "activerecord", "~>
|
|
46
|
+
gem.add_dependency "activerecord", "~> 8.1.0"
|
|
47
47
|
|
|
48
48
|
#gem.add_development_dependency 'test-unit', '2.5.4'
|
|
49
49
|
#gem.add_development_dependency 'test-unit-context', '>= 0.3.0'
|
data/lib/arjdbc/abstract/core.rb
CHANGED
|
@@ -56,23 +56,6 @@ module ArJdbc
|
|
|
56
56
|
else super
|
|
57
57
|
end
|
|
58
58
|
end
|
|
59
|
-
|
|
60
|
-
# this version of log() automatically fills type_casted_binds from binds if necessary
|
|
61
|
-
def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil, async: false)
|
|
62
|
-
if binds.any? && (type_casted_binds.nil? || type_casted_binds.empty?)
|
|
63
|
-
type_casted_binds = lambda {
|
|
64
|
-
# extract_raw_bind_values
|
|
65
|
-
binds.map do |bind|
|
|
66
|
-
if bind.respond_to?(:value_for_database)
|
|
67
|
-
bind.value_for_database
|
|
68
|
-
else
|
|
69
|
-
bind
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
}
|
|
73
|
-
end
|
|
74
|
-
super
|
|
75
|
-
end
|
|
76
59
|
end
|
|
77
60
|
end
|
|
78
61
|
|
|
@@ -10,21 +10,17 @@ module ArJdbc
|
|
|
10
10
|
NO_BINDS = [].freeze
|
|
11
11
|
|
|
12
12
|
def exec_insert(sql, name = nil, binds = NO_BINDS, pk = nil, sequence_name = nil, returning: nil)
|
|
13
|
-
sql =
|
|
13
|
+
sql = preprocess_query(sql)
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
mark_transaction_written_if_write(sql)
|
|
20
|
-
|
|
21
|
-
binds = convert_legacy_binds_to_attributes(binds) if binds.first.is_a?(Array)
|
|
15
|
+
type_casted_binds = type_casted_binds(binds)
|
|
22
16
|
|
|
23
17
|
with_raw_connection do |conn|
|
|
24
18
|
if without_prepared_statement?(binds)
|
|
25
19
|
log(sql, name) { conn.execute_insert_pk(sql, pk) }
|
|
26
20
|
else
|
|
27
|
-
log(sql, name, binds) do
|
|
21
|
+
log(sql, name, binds, type_casted_binds) do
|
|
22
|
+
# TODO: the ideas is to pass type casted binds but dozens of tests fail
|
|
23
|
+
# conn.execute_insert_pk(sql, type_casted_binds, pk)
|
|
28
24
|
conn.execute_insert_pk(sql, binds, pk)
|
|
29
25
|
end
|
|
30
26
|
end
|
|
@@ -34,15 +30,7 @@ module ArJdbc
|
|
|
34
30
|
# It appears that at this point (AR 5.0) "prepare" should only ever be true
|
|
35
31
|
# if prepared statements are enabled
|
|
36
32
|
def internal_exec_query(sql, name = nil, binds = NO_BINDS, prepare: false, async: false, allow_retry: false, materialize_transactions: true)
|
|
37
|
-
sql =
|
|
38
|
-
|
|
39
|
-
if preventing_writes? && write_query?(sql)
|
|
40
|
-
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
mark_transaction_written_if_write(sql)
|
|
44
|
-
|
|
45
|
-
binds = convert_legacy_binds_to_attributes(binds) if binds.first.is_a?(Array)
|
|
33
|
+
sql = preprocess_query(sql)
|
|
46
34
|
|
|
47
35
|
# puts "[1]internal----->sql: #{sql}, binds: #{binds}"
|
|
48
36
|
type_casted_binds = type_casted_binds(binds)
|
|
@@ -55,28 +43,28 @@ module ArJdbc
|
|
|
55
43
|
log(sql, name, type_casted_binds, async: async) do
|
|
56
44
|
# this is different from normal AR that always caches
|
|
57
45
|
cached_statement = fetch_cached_statement(sql) if prepare && @jdbc_statement_cache_enabled
|
|
58
|
-
conn.execute_prepared_query(sql,
|
|
46
|
+
conn.execute_prepared_query(sql, binds, cached_statement)
|
|
59
47
|
end
|
|
60
48
|
end
|
|
61
49
|
end
|
|
62
50
|
end
|
|
63
51
|
|
|
64
52
|
def exec_update(sql, name = 'SQL', binds = NO_BINDS)
|
|
65
|
-
sql =
|
|
66
|
-
|
|
67
|
-
if preventing_writes?
|
|
68
|
-
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
mark_transaction_written_if_write(sql)
|
|
53
|
+
sql = preprocess_query(sql)
|
|
72
54
|
|
|
73
55
|
binds = convert_legacy_binds_to_attributes(binds) if binds.first.is_a?(Array)
|
|
74
56
|
|
|
57
|
+
type_casted_binds = type_casted_binds(binds)
|
|
58
|
+
|
|
75
59
|
with_raw_connection do |conn|
|
|
76
60
|
if without_prepared_statement?(binds)
|
|
77
61
|
log(sql, name) { conn.execute_update(sql) }
|
|
78
62
|
else
|
|
79
|
-
log(sql, name, binds
|
|
63
|
+
log(sql, name, binds, type_casted_binds) do
|
|
64
|
+
# TODO: the ideas is to pass type casted binds but some tests fail
|
|
65
|
+
# conn.execute_prepared_update(sql, type_casted_binds)
|
|
66
|
+
conn.execute_prepared_update(sql, binds)
|
|
67
|
+
end
|
|
80
68
|
end
|
|
81
69
|
end
|
|
82
70
|
end
|
|
@@ -90,22 +78,15 @@ module ArJdbc
|
|
|
90
78
|
|
|
91
79
|
private
|
|
92
80
|
|
|
81
|
+
def without_prepared_statement?(binds)
|
|
82
|
+
!prepared_statements || binds.empty?
|
|
83
|
+
end
|
|
84
|
+
|
|
93
85
|
def convert_legacy_binds_to_attributes(binds)
|
|
94
86
|
binds.map do |column, value|
|
|
95
87
|
ActiveRecord::Relation::QueryAttribute.new(nil, type_cast(value, column), ActiveModel::Type::Value.new)
|
|
96
88
|
end
|
|
97
89
|
end
|
|
98
|
-
|
|
99
|
-
def raw_execute(sql, name, async: false, allow_retry: false, materialize_transactions: true)
|
|
100
|
-
log(sql, name, async: async) do
|
|
101
|
-
with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
|
|
102
|
-
result = conn.execute(sql)
|
|
103
|
-
verified!
|
|
104
|
-
result
|
|
105
|
-
end
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
|
|
109
90
|
end
|
|
110
91
|
end
|
|
111
92
|
end
|
|
Binary file
|
data/lib/arjdbc/mssql/adapter.rb
CHANGED
|
@@ -29,6 +29,7 @@ require 'arjdbc/mssql/transaction'
|
|
|
29
29
|
require 'arjdbc/mssql/errors'
|
|
30
30
|
require 'arjdbc/mssql/schema_creation'
|
|
31
31
|
require 'arjdbc/mssql/database_limits'
|
|
32
|
+
require "arjdbc/mssql/type_metadata"
|
|
32
33
|
|
|
33
34
|
require "arjdbc/mssql/adapter_hash_config"
|
|
34
35
|
|
|
@@ -479,31 +480,31 @@ module ActiveRecord
|
|
|
479
480
|
def translate_exception(exception, message:, sql:, binds:)
|
|
480
481
|
case message
|
|
481
482
|
when /no connection available/i
|
|
482
|
-
ConnectionNotEstablished.new(
|
|
483
|
+
ConnectionNotEstablished.new(message, connection_pool: @pool)
|
|
483
484
|
when /(cannot insert duplicate key .* with unique index) | (violation of unique key constraint)/i
|
|
484
|
-
RecordNotUnique.new(message, sql: sql, binds: binds)
|
|
485
|
+
RecordNotUnique.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
485
486
|
when /Violation of PRIMARY KEY constraint .* Cannot insert duplicate key in object .* The duplicate key value is/i
|
|
486
|
-
RecordNotUnique.new(message, sql: sql, binds: binds)
|
|
487
|
+
RecordNotUnique.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
487
488
|
when /Lock request time out period exceeded/i
|
|
488
489
|
LockTimeout.new(message, sql: sql, binds: binds)
|
|
489
490
|
when /The .* statement conflicted with the FOREIGN KEY constraint/
|
|
490
|
-
InvalidForeignKey.new(message, sql: sql, binds: binds)
|
|
491
|
+
InvalidForeignKey.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
491
492
|
when /Could not drop object .* because it is referenced by a FOREIGN KEY constraint/
|
|
492
|
-
StatementInvalid.new(message, sql: sql, binds: binds)
|
|
493
|
+
StatementInvalid.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
493
494
|
when /The .* statement conflicted with the REFERENCE constraint/
|
|
494
|
-
InvalidForeignKey.new(message, sql: sql, binds: binds)
|
|
495
|
+
InvalidForeignKey.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
495
496
|
when /(String or binary data would be truncated)/i
|
|
496
|
-
ValueTooLong.new(message, sql: sql, binds: binds)
|
|
497
|
+
ValueTooLong.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
497
498
|
when /Cannot insert the value NULL into column .* does not allow nulls/
|
|
498
|
-
NotNullViolation.new(message, sql: sql, binds: binds)
|
|
499
|
+
NotNullViolation.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
499
500
|
when /Arithmetic overflow error converting expression/
|
|
500
501
|
RangeError.new(message, sql: sql, binds: binds)
|
|
501
502
|
when /Snapshot isolation transaction aborted due to update conflict. You cannot use snapshot isolation/
|
|
502
|
-
StatementInvalid.new(message, sql: sql, binds: binds)
|
|
503
|
+
StatementInvalid.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
503
504
|
when /Incorrect syntax near the keyword .*/
|
|
504
|
-
StatementInvalid.new(message, sql: sql, binds: binds)
|
|
505
|
+
StatementInvalid.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
505
506
|
when /Could not find stored procedure .*/
|
|
506
|
-
StatementInvalid.new(message, sql: sql, binds: binds)
|
|
507
|
+
StatementInvalid.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
507
508
|
else
|
|
508
509
|
super
|
|
509
510
|
end
|
data/lib/arjdbc/mssql/column.rb
CHANGED
|
@@ -6,12 +6,12 @@ module ActiveRecord
|
|
|
6
6
|
class MSSQLColumn < Column
|
|
7
7
|
attr_reader :table_name
|
|
8
8
|
|
|
9
|
-
def initialize(name, raw_default, sql_type_metadata = nil, null = true, table_name = nil, default_function = nil, collation = nil, comment: nil)
|
|
9
|
+
def initialize(name, cast_type, raw_default, sql_type_metadata = nil, null = true, table_name = nil, default_function = nil, collation = nil, comment: nil)
|
|
10
10
|
@table_name = table_name
|
|
11
11
|
|
|
12
12
|
default_val, default_fun = extract_default(raw_default)
|
|
13
13
|
|
|
14
|
-
super(name, default_val, sql_type_metadata, null, default_fun, collation: collation, comment: comment)
|
|
14
|
+
super(name, cast_type, default_val, sql_type_metadata, null, default_fun, collation: collation, comment: comment)
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def extract_default(value)
|
|
@@ -92,12 +92,8 @@ module ActiveRecord
|
|
|
92
92
|
end
|
|
93
93
|
end
|
|
94
94
|
|
|
95
|
-
def internal_exec_query(sql, name = 'SQL', binds = [], prepare: false, async: false, allow_retry: false)
|
|
96
|
-
sql =
|
|
97
|
-
|
|
98
|
-
check_if_write_query(sql)
|
|
99
|
-
|
|
100
|
-
mark_transaction_written_if_write(sql)
|
|
95
|
+
def internal_exec_query(sql, name = 'SQL', binds = [], prepare: false, async: false, allow_retry: false, materialize_transactions: true)
|
|
96
|
+
sql = preprocess_query(sql)
|
|
101
97
|
|
|
102
98
|
# binds = convert_legacy_binds_to_attributes(binds) if binds.first.is_a?(Array)
|
|
103
99
|
|
|
@@ -105,7 +101,7 @@ module ActiveRecord
|
|
|
105
101
|
type_casted_binds = type_casted_binds(binds)
|
|
106
102
|
# puts "[2]internal----->sql: #{type_casted_binds.size}, binds: #{type_casted_binds}"
|
|
107
103
|
|
|
108
|
-
if
|
|
104
|
+
if binds.nil? || binds.empty?
|
|
109
105
|
log(sql, name) do
|
|
110
106
|
with_raw_connection do |conn|
|
|
111
107
|
result = conditional_indentity_insert(sql) do
|
|
@@ -132,14 +128,12 @@ module ActiveRecord
|
|
|
132
128
|
end
|
|
133
129
|
|
|
134
130
|
def exec_update(sql, name = nil, binds = [])
|
|
135
|
-
sql =
|
|
131
|
+
sql = preprocess_query(sql)
|
|
136
132
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
mark_transaction_written_if_write(sql)
|
|
133
|
+
type_casted_binds = type_casted_binds(binds)
|
|
140
134
|
|
|
141
135
|
# puts "exec_update----->sql: #{sql}, binds: #{binds}"
|
|
142
|
-
if
|
|
136
|
+
if binds.nil? || binds.empty?
|
|
143
137
|
log(sql, name) do
|
|
144
138
|
with_raw_connection do |conn|
|
|
145
139
|
result = conn.execute_update(sql)
|
|
@@ -148,9 +142,9 @@ module ActiveRecord
|
|
|
148
142
|
end
|
|
149
143
|
end
|
|
150
144
|
else
|
|
151
|
-
log(sql, name, binds) do
|
|
145
|
+
log(sql, name, binds, type_casted_binds) do
|
|
152
146
|
with_raw_connection do |conn|
|
|
153
|
-
result = conn.execute_prepared_update(sql,
|
|
147
|
+
result = conn.execute_prepared_update(sql, type_casted_binds)
|
|
154
148
|
verified!
|
|
155
149
|
result
|
|
156
150
|
end
|
|
@@ -160,14 +154,12 @@ module ActiveRecord
|
|
|
160
154
|
alias :exec_delete :exec_update
|
|
161
155
|
|
|
162
156
|
def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil, returning: nil)
|
|
163
|
-
sql =
|
|
157
|
+
sql = preprocess_query(sql)
|
|
164
158
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
mark_transaction_written_if_write(sql)
|
|
159
|
+
type_casted_binds = type_casted_binds(binds)
|
|
168
160
|
|
|
169
161
|
# puts "exec_insert----->sql: #{sql}, binds: #{binds}"
|
|
170
|
-
if
|
|
162
|
+
if binds.nil? || binds.empty?
|
|
171
163
|
log(sql, name) do
|
|
172
164
|
with_raw_connection do |conn|
|
|
173
165
|
result = conditional_indentity_insert(sql) do
|
|
@@ -178,12 +170,14 @@ module ActiveRecord
|
|
|
178
170
|
end
|
|
179
171
|
end
|
|
180
172
|
else
|
|
181
|
-
log(sql, name, binds) do
|
|
173
|
+
log(sql, name, binds, type_casted_binds) do
|
|
182
174
|
with_raw_connection do |conn|
|
|
183
175
|
result = conditional_indentity_insert(sql) do
|
|
184
176
|
# DEPRECATION WARNING: to_time will always preserve the timezone offset of the receiver in Rails 8.0.
|
|
185
177
|
# To opt in to the new behavior, set `ActiveSupport.to_time_preserves_timezone = true`.
|
|
186
178
|
# (called from block in execute_insert_pk
|
|
179
|
+
# TODO: the ideas is to pass type casted binds but causes strange test failures
|
|
180
|
+
# conn.execute_insert_pk(sql, type_casted_binds, pk)
|
|
187
181
|
conn.execute_insert_pk(sql, binds, pk)
|
|
188
182
|
end
|
|
189
183
|
verified!
|
|
@@ -195,15 +189,23 @@ module ActiveRecord
|
|
|
195
189
|
|
|
196
190
|
private
|
|
197
191
|
|
|
198
|
-
def
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
192
|
+
def cast_result(raw_result)
|
|
193
|
+
return ActiveRecord::Result.empty if raw_result.nil?
|
|
194
|
+
|
|
195
|
+
# nothing to cast here. the java part returns an AR Result
|
|
196
|
+
raw_result
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def perform_query(raw_connection, sql, binds, type_casted_binds, prepare:, notification_payload:, batch:)
|
|
201
|
+
result = conditional_indentity_insert(sql) { raw_connection.execute(sql) }
|
|
202
|
+
|
|
203
|
+
count = 0
|
|
204
|
+
count = result.count if result.respond_to?(:count)
|
|
205
|
+
|
|
206
|
+
verified!
|
|
207
|
+
notification_payload[:row_count] = count
|
|
208
|
+
result
|
|
207
209
|
end
|
|
208
210
|
|
|
209
211
|
def sql_for_insert(sql, pk, binds, returning) # :nodoc:
|
|
@@ -50,7 +50,12 @@ module ActiveRecord
|
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
binds.each do |bind|
|
|
53
|
-
value =
|
|
53
|
+
value = if bind.is_a?(::ActiveModel::Attribute)
|
|
54
|
+
quote(bind.value_for_database)
|
|
55
|
+
else
|
|
56
|
+
quote(bind)
|
|
57
|
+
end
|
|
58
|
+
|
|
54
59
|
sql = sql.sub('?', value)
|
|
55
60
|
end
|
|
56
61
|
|
|
@@ -55,7 +55,7 @@ module ActiveRecord
|
|
|
55
55
|
end
|
|
56
56
|
|
|
57
57
|
def add_column_options!(sql, options)
|
|
58
|
-
sql << " DEFAULT #{
|
|
58
|
+
sql << " DEFAULT #{quote_default_expression_for_column_definition(options[:default], options[:column])}" if options_include_default?(options)
|
|
59
59
|
|
|
60
60
|
sql << ' NOT NULL' if options[:null] == false
|
|
61
61
|
|
|
@@ -419,6 +419,10 @@ module ActiveRecord
|
|
|
419
419
|
field
|
|
420
420
|
end
|
|
421
421
|
|
|
422
|
+
def fetch_type_metadata(sql_type)
|
|
423
|
+
MSSQL::TypeMetadata.new(super(sql_type))
|
|
424
|
+
end
|
|
425
|
+
|
|
422
426
|
def create_db_edition_options(options = {})
|
|
423
427
|
edition_config = options.select { |k, _v| k.match?('azure') }
|
|
424
428
|
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
module ConnectionAdapters
|
|
5
|
+
module MSSQL
|
|
6
|
+
class TypeMetadata < DelegateClass(SqlTypeMetadata)
|
|
7
|
+
undef to_yaml if method_defined?(:to_yaml)
|
|
8
|
+
|
|
9
|
+
include Deduplicable
|
|
10
|
+
|
|
11
|
+
def initialize(type_metadata)
|
|
12
|
+
super(type_metadata)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def ==(other)
|
|
16
|
+
other.is_a?(TypeMetadata) &&
|
|
17
|
+
__getobj__ == other.__getobj__
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
alias eql? ==
|
|
21
|
+
|
|
22
|
+
def hash
|
|
23
|
+
TypeMetadata.hash ^
|
|
24
|
+
__getobj__.hash
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def deduplicated
|
|
30
|
+
__setobj__(__getobj__.deduplicate)
|
|
31
|
+
super
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -20,12 +20,13 @@ module ActiveRecord
|
|
|
20
20
|
|
|
21
21
|
# This is the Rails binary type
|
|
22
22
|
class VarbinaryMax < ActiveRecord::Type::Binary
|
|
23
|
-
def
|
|
24
|
-
|
|
23
|
+
def initialize(**args)
|
|
24
|
+
super
|
|
25
|
+
@limit = 2_147_483_647
|
|
25
26
|
end
|
|
26
27
|
|
|
27
|
-
def
|
|
28
|
-
|
|
28
|
+
def type
|
|
29
|
+
:binary
|
|
29
30
|
end
|
|
30
31
|
end
|
|
31
32
|
|
|
@@ -7,32 +7,35 @@ module ActiveRecord
|
|
|
7
7
|
module Type
|
|
8
8
|
|
|
9
9
|
class Text < ActiveRecord::Type::String
|
|
10
|
-
def
|
|
11
|
-
|
|
10
|
+
def initialize(**args)
|
|
11
|
+
super
|
|
12
|
+
@limit = 2_147_483_647
|
|
12
13
|
end
|
|
13
14
|
|
|
14
|
-
def
|
|
15
|
-
|
|
15
|
+
def type
|
|
16
|
+
:text_basic
|
|
16
17
|
end
|
|
17
18
|
end
|
|
18
19
|
|
|
19
20
|
class Ntext < ActiveRecord::Type::String
|
|
20
|
-
def
|
|
21
|
-
|
|
21
|
+
def initialize(**args)
|
|
22
|
+
super
|
|
23
|
+
@limit = 2_147_483_647
|
|
22
24
|
end
|
|
23
25
|
|
|
24
|
-
def
|
|
25
|
-
|
|
26
|
+
def type
|
|
27
|
+
:ntext
|
|
26
28
|
end
|
|
27
29
|
end
|
|
28
30
|
|
|
29
31
|
class Image < ActiveRecord::Type::Binary
|
|
30
|
-
def
|
|
31
|
-
|
|
32
|
+
def initialize(**args)
|
|
33
|
+
super
|
|
34
|
+
@limit = 2_147_483_647
|
|
32
35
|
end
|
|
33
36
|
|
|
34
|
-
def
|
|
35
|
-
|
|
37
|
+
def type
|
|
38
|
+
:image
|
|
36
39
|
end
|
|
37
40
|
end
|
|
38
41
|
|
|
@@ -19,12 +19,13 @@ module ActiveRecord
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
class VarcharMax < ActiveRecord::Type::String
|
|
22
|
-
def
|
|
23
|
-
|
|
22
|
+
def initialize(**args)
|
|
23
|
+
super
|
|
24
|
+
@limit = 2_147_483_647
|
|
24
25
|
end
|
|
25
26
|
|
|
26
|
-
def
|
|
27
|
-
|
|
27
|
+
def type
|
|
28
|
+
:varchar_max
|
|
28
29
|
end
|
|
29
30
|
end
|
|
30
31
|
|
|
@@ -43,12 +44,13 @@ module ActiveRecord
|
|
|
43
44
|
|
|
44
45
|
# This is Rails logical text type
|
|
45
46
|
class NvarcharMax < ActiveRecord::Type::String
|
|
46
|
-
def
|
|
47
|
-
|
|
47
|
+
def initialize(**args)
|
|
48
|
+
super
|
|
49
|
+
@limit = 2_147_483_647
|
|
48
50
|
end
|
|
49
51
|
|
|
50
|
-
def
|
|
51
|
-
|
|
52
|
+
def type
|
|
53
|
+
:text
|
|
52
54
|
end
|
|
53
55
|
end
|
|
54
56
|
|
data/lib/arjdbc/mssql.rb
CHANGED