activerecord-jdbc-alt-adapter 50.7.0-java → 51.3.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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -3
  3. data/.travis.yml +24 -28
  4. data/Gemfile +5 -2
  5. data/README.md +26 -20
  6. data/Rakefile +4 -30
  7. data/activerecord-jdbc-adapter.gemspec +2 -2
  8. data/activerecord-jdbc-alt-adapter.gemspec +4 -3
  9. data/lib/arel/visitors/sqlserver.rb +17 -3
  10. data/lib/arjdbc/abstract/core.rb +4 -2
  11. data/lib/arjdbc/abstract/database_statements.rb +2 -8
  12. data/lib/arjdbc/abstract/transaction_support.rb +2 -9
  13. data/lib/arjdbc/db2/adapter.rb +2 -52
  14. data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
  15. data/lib/arjdbc/jdbc/column.rb +11 -5
  16. data/lib/arjdbc/jdbc/error.rb +1 -1
  17. data/lib/arjdbc/jdbc.rb +4 -0
  18. data/lib/arjdbc/mssql/adapter.rb +33 -39
  19. data/lib/arjdbc/mssql/connection_methods.rb +0 -5
  20. data/lib/arjdbc/mssql/database_statements.rb +1 -1
  21. data/lib/arjdbc/mssql/explain_support.rb +1 -1
  22. data/lib/arjdbc/mssql/{extensions.rb → extensions/attribute_methods.rb} +0 -0
  23. data/lib/arjdbc/mssql/extensions/calculations.rb +29 -0
  24. data/lib/arjdbc/mssql/schema_creation.rb +12 -0
  25. data/lib/arjdbc/mssql/schema_definitions.rb +17 -0
  26. data/lib/arjdbc/mssql/schema_dumper.rb +37 -0
  27. data/lib/arjdbc/mssql/schema_statements.rb +73 -44
  28. data/lib/arjdbc/mssql/types/date_and_time_types.rb +9 -9
  29. data/lib/arjdbc/mssql/utils.rb +1 -0
  30. data/lib/arjdbc/mssql.rb +1 -1
  31. data/lib/arjdbc/mysql/adapter.rb +12 -1
  32. data/lib/arjdbc/mysql/connection_methods.rb +7 -13
  33. data/lib/arjdbc/postgresql/adapter.rb +29 -12
  34. data/lib/arjdbc/postgresql/column.rb +3 -6
  35. data/lib/arjdbc/postgresql/connection_methods.rb +1 -3
  36. data/lib/arjdbc/postgresql/oid_types.rb +7 -12
  37. data/lib/arjdbc/sqlite3/adapter.rb +169 -139
  38. data/lib/arjdbc/sqlite3/connection_methods.rb +1 -2
  39. data/lib/arjdbc/version.rb +1 -1
  40. data/rakelib/01-tomcat.rake +2 -2
  41. data/rakelib/02-test.rake +2 -0
  42. data/rakelib/rails.rake +1 -1
  43. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +17 -68
  44. data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +38 -282
  45. data/src/java/arjdbc/postgresql/ByteaUtils.java +1 -0
  46. data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +3 -3
  47. data/src/java/arjdbc/util/DateTimeUtils.java +5 -22
  48. metadata +20 -12
  49. data/lib/activerecord-jdbc-alt-adapter.rb +0 -1
@@ -7,6 +7,9 @@ require 'arel/visitors/bind_visitor'
7
7
  require 'arel/visitors/sqlserver'
8
8
  require 'active_record/connection_adapters/abstract_adapter'
9
9
 
10
+ require 'arjdbc/mssql/extensions/attribute_methods'
11
+ require 'arjdbc/mssql/extensions/calculations'
12
+
10
13
  require 'arjdbc/abstract/core'
11
14
  require 'arjdbc/abstract/connection_management'
12
15
  require 'arjdbc/abstract/database_statements'
@@ -18,9 +21,9 @@ require 'arjdbc/mssql/types'
18
21
  require 'arjdbc/mssql/quoting'
19
22
  require 'arjdbc/mssql/schema_definitions'
20
23
  require 'arjdbc/mssql/schema_statements'
24
+ require 'arjdbc/mssql/schema_dumper'
21
25
  require 'arjdbc/mssql/database_statements'
22
26
  require 'arjdbc/mssql/explain_support'
23
- require 'arjdbc/mssql/extensions'
24
27
  require 'arjdbc/mssql/transaction'
25
28
  require 'arjdbc/mssql/errors'
26
29
  require 'arjdbc/mssql/schema_creation'
@@ -51,6 +54,7 @@ module ActiveRecord
51
54
 
52
55
  include MSSQL::Quoting
53
56
  include MSSQL::SchemaStatements
57
+ include MSSQL::ColumnDumper
54
58
  include MSSQL::DatabaseStatements
55
59
  include MSSQL::ExplainSupport
56
60
 
@@ -81,38 +85,11 @@ module ActiveRecord
81
85
  ::ActiveRecord::ConnectionAdapters::MSSQLColumn
82
86
  end
83
87
 
84
- # Does this adapter support DDL rollbacks in transactions? That is, would
85
- # CREATE TABLE or ALTER TABLE get rolled back by a transaction?
86
- def supports_ddl_transactions?
87
- true
88
- end
89
-
90
- # Can this adapter determine the primary key for tables not attached
91
- # to an Active Record class, such as join tables?
92
- def supports_primary_key?
93
- true
94
- end
95
-
96
88
  # Does this adapter support creating foreign key constraints?
97
89
  def supports_foreign_keys?
98
90
  true
99
91
  end
100
92
 
101
- # Does this adapter support index sort order?
102
- def supports_index_sort_order?
103
- true
104
- end
105
-
106
- # Also known as filtered index
107
- def supports_partial_index?
108
- true
109
- end
110
-
111
- # Does this adapter support migrations?
112
- def supports_migrations?
113
- true
114
- end
115
-
116
93
  # Does this adapter support setting the isolation level for a transaction?
117
94
  def supports_transaction_isolation?
118
95
  true
@@ -123,6 +100,11 @@ module ActiveRecord
123
100
  true
124
101
  end
125
102
 
103
+ # Does this adapter support views?
104
+ def supports_views?
105
+ true
106
+ end
107
+
126
108
  # Overrides abstract method which always returns false
127
109
  def valid_type?(type)
128
110
  !native_database_types[type].nil?
@@ -134,13 +116,6 @@ module ActiveRecord
134
116
  super
135
117
  end
136
118
 
137
- def reset!
138
- # execute 'IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION'
139
- # NOTE: it seems the above line interferes with the jdbc driver
140
- # and ending up in connection closed, issue seen in rails 5.2 and 6.0
141
- reconnect!
142
- end
143
-
144
119
  def disable_referential_integrity
145
120
  tables = tables_with_referential_integrity
146
121
 
@@ -211,22 +186,37 @@ module ActiveRecord
211
186
  alias_method :current_schema=, :default_schema=
212
187
 
213
188
  # Overrides method in abstract adapter
189
+ # FIXME: This needs to be fixed the we find a way how to
190
+ # get the collation per column basis. At the moment we only use
191
+ # the global database collation
214
192
  def case_sensitive_comparison(table, attribute, column, value)
215
193
  if value.nil?
216
194
  table[attribute].eq(value)
217
- elsif value.acts_like?(:string)
195
+ elsif [:string, :text].include?(column.type) && collation && !collation.match(/_CS/)
218
196
  table[attribute].eq(Arel::Nodes::Bin.new(Arel::Nodes::BindParam.new))
197
+ # elsif value.acts_like?(:string)
198
+ # table[attribute].eq(Arel::Nodes::Bin.new(Arel::Nodes::BindParam.new))
219
199
  else
220
200
  table[attribute].eq(Arel::Nodes::BindParam.new)
221
201
  end
222
202
  end
223
203
 
224
204
  def configure_connection
225
- # Here goes initial settings per connection
205
+ execute("SET LOCK_TIMEOUT #{lock_timeout}")
226
206
 
227
207
  set_session_transaction_isolation
228
208
  end
229
209
 
210
+ def lock_timeout
211
+ timeout = config[:lock_timeout].to_i
212
+
213
+ if timeout.positive?
214
+ timeout
215
+ else
216
+ 5_000
217
+ end
218
+ end
219
+
230
220
  def set_session_transaction_isolation
231
221
  isolation_level = config[:transaction_isolation]
232
222
 
@@ -263,9 +253,9 @@ module ActiveRecord
263
253
  end
264
254
  end
265
255
 
266
- protected
256
+ private
267
257
 
268
- def translate_exception(e, message)
258
+ def translate_exception(exception, message)
269
259
  case message
270
260
  when /(cannot insert duplicate key .* with unique index) | (violation of unique key constraint)/i
271
261
  RecordNotUnique.new(message)
@@ -275,6 +265,10 @@ module ActiveRecord
275
265
  ActiveRecord::InvalidForeignKey.new(message)
276
266
  when /(String or binary data would be truncated)/i
277
267
  ActiveRecord::ValueTooLong.new(message)
268
+ when /Cannot insert the value NULL into column .* does not allow nulls/
269
+ ActiveRecord::NotNullViolation.new(message)
270
+ when /Arithmetic overflow error converting expression/
271
+ ActiveRecord::RangeError.new(message)
278
272
  else
279
273
  super
280
274
  end
@@ -52,8 +52,6 @@ ArJdbc::ConnectionMethods.module_eval do
52
52
 
53
53
  # @note Assumes SQLServer SQL-JDBC driver on the class-path.
54
54
  def sqlserver_connection(config)
55
- config = config.deep_dup
56
-
57
55
  config[:adapter_spec] ||= ::ArJdbc::MSSQL
58
56
  config[:adapter_class] = ActiveRecord::ConnectionAdapters::MSSQLAdapter unless config.key?(:adapter_class)
59
57
 
@@ -62,15 +60,12 @@ ArJdbc::ConnectionMethods.module_eval do
62
60
  config[:host] ||= 'localhost'
63
61
  config[:driver] ||= 'com.microsoft.sqlserver.jdbc.SQLServerDriver'
64
62
  config[:connection_alive_sql] ||= 'SELECT 1'
65
- config[:lock_timeout] ||= 5000
66
63
 
67
64
  config[:url] ||= begin
68
65
  url = "jdbc:sqlserver://#{config[:host]}"
69
66
  url << ( config[:port] ? ":#{config[:port]};" : ';' )
70
67
  url << "databaseName=#{config[:database]};" if config[:database]
71
68
  url << "instanceName=#{config[:instance]};" if config[:instance]
72
- url << "loginTimeout=#{config[:login_timeout].to_i};" if config[:login_timeout]
73
- url << "lockTimeout=#{config[:lock_timeout].to_i};"
74
69
  app = config[:appname] || config[:application]
75
70
  url << "applicationName=#{app};" if app
76
71
  isc = config[:integrated_security] # Win only - needs sqljdbc_auth.dll
@@ -87,7 +87,7 @@ module ActiveRecord
87
87
  end
88
88
 
89
89
  def identity_column_name(table_name)
90
- for column in schema_cache.columns(table_name)
90
+ for column in columns(table_name)
91
91
  return column.name if column.identity?
92
92
  end
93
93
  nil
@@ -41,7 +41,7 @@ module ActiveRecord
41
41
 
42
42
  binds.each do |bind|
43
43
  value = quote(bind.value_for_database)
44
- sql.sub!('?', value)
44
+ sql = sql.sub('?', value)
45
45
  end
46
46
 
47
47
  sql
@@ -0,0 +1,29 @@
1
+ require 'active_record/relation'
2
+ require 'active_record/version'
3
+
4
+ # NOTE: some improvements in active record broke sql calculations and habtm
5
+ # associations for this adapter and the supporting arel visitor.
6
+ # this extension fixes this issue in rails 5.1.4 onwards
7
+ #
8
+ # https://github.com/rails/rails/pull/29848
9
+ # https://github.com/rails/rails/pull/30686
10
+
11
+ module ActiveRecord
12
+ module ConnectionAdapters
13
+ module MSSQL
14
+ module Calculations
15
+ private
16
+
17
+ def build_count_subquery(relation, column_name, distinct)
18
+ super(relation.unscope(:order), column_name, distinct)
19
+ end
20
+
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ ActiveSupport.on_load(:active_record) do
27
+ mod = ActiveRecord::ConnectionAdapters::MSSQL::Calculations
28
+ ActiveRecord::Relation.prepend(mod)
29
+ end
@@ -15,6 +15,18 @@ module ActiveRecord
15
15
  end
16
16
  end
17
17
 
18
+ def add_column_options!(sql, options)
19
+ sql << " DEFAULT #{quote_default_expression(options[:default], options[:column])}" if options_include_default?(options)
20
+
21
+ sql << ' NOT NULL' if options[:null] == false
22
+
23
+ sql << ' IDENTITY(1,1)' if options[:is_identity] == true
24
+
25
+ sql << ' PRIMARY KEY' if options[:primary_key] == true
26
+
27
+ sql
28
+ end
29
+
18
30
  # There is no RESTRICT in MSSQL but it has NO ACTION which behave
19
31
  # same as RESTRICT, added this behave according rails api.
20
32
  def action_sql(action, dependency)
@@ -2,6 +2,14 @@ module ActiveRecord
2
2
  module ConnectionAdapters
3
3
  module MSSQL
4
4
  module ColumnMethods
5
+ def primary_key(name, type = :primary_key, **options)
6
+ if [:integer, :bigint].include?(type)
7
+ options[:is_identity] = true unless options.key?(:default)
8
+ end
9
+
10
+ super
11
+ end
12
+
5
13
  # datetime with seconds always zero (:00) and without fractional seconds
6
14
  def smalldatetime(*args, **options)
7
15
  args.each { |name| column(name, :smalldatetime, options) }
@@ -64,6 +72,15 @@ module ActiveRecord
64
72
 
65
73
  class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
66
74
  include ColumnMethods
75
+
76
+ def new_column_definition(name, type, **options)
77
+ case type
78
+ when :primary_key
79
+ options[:is_identity] = true
80
+ end
81
+
82
+ super
83
+ end
67
84
  end
68
85
 
69
86
  class Table < ActiveRecord::ConnectionAdapters::Table
@@ -0,0 +1,37 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module MSSQL
4
+ module ColumnDumper # :nodoc:
5
+ MSSQL_NO_LIMIT_TYPES = [
6
+ 'text',
7
+ 'ntext',
8
+ 'varchar(max)',
9
+ 'nvarchar(max)',
10
+ 'varbinary(max)'
11
+ ].freeze
12
+
13
+ private
14
+
15
+ def schema_limit(column)
16
+ return if MSSQL_NO_LIMIT_TYPES.include?(column.sql_type)
17
+
18
+ super
19
+ end
20
+
21
+ def explicit_primary_key_default?(column)
22
+ !column.identity?
23
+ end
24
+
25
+ def default_primary_key?(column)
26
+ super && column.identity?
27
+ end
28
+
29
+ # def schema_collation(column)
30
+ # return unless column.collation
31
+ # column.collation if column.collation != collation
32
+ # end
33
+
34
+ end
35
+ end
36
+ end
37
+ end
@@ -5,7 +5,7 @@ module ActiveRecord
5
5
 
6
6
  NATIVE_DATABASE_TYPES = {
7
7
  # Logical Rails types to SQL Server types
8
- primary_key: 'int NOT NULL IDENTITY(1,1) PRIMARY KEY',
8
+ primary_key: 'bigint NOT NULL IDENTITY(1,1) PRIMARY KEY',
9
9
  integer: { name: 'int', limit: 4 },
10
10
  boolean: { name: 'bit' },
11
11
  decimal: { name: 'decimal' },
@@ -41,43 +41,16 @@ module ActiveRecord
41
41
  NATIVE_DATABASE_TYPES
42
42
  end
43
43
 
44
- # Returns an array of table names defined in the database.
45
- def tables(name = nil)
46
- if name
47
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
48
- Passing arguments to #tables is deprecated without replacement.
49
- MSG
50
- end
51
-
52
- @connection.tables(nil, name)
53
- end
54
-
55
44
  # Returns an array of Column objects for the table specified by +table_name+.
56
45
  # See the concrete implementation for details on the expected parameter values.
57
46
  # NOTE: This is ready, all implemented in the java part of adapter,
58
47
  # it uses MSSQLColumn, SqlTypeMetadata, etc.
59
48
  def columns(table_name)
60
- log('JDBC: GETCOLUMNS', 'SCHEMA') { @connection.columns(table_name) }
49
+ @connection.columns(table_name)
61
50
  rescue => e
62
51
  raise translate_exception_class(e, nil)
63
52
  end
64
53
 
65
- # Returns an array of view names defined in the database.
66
- # (to be implemented)
67
- def views
68
- []
69
- end
70
-
71
- def table_exists?(table_name)
72
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
73
- #table_exists? currently checks both tables and views.
74
- This behavior is deprecated and will be changed with Rails 5.1 to only check tables.
75
- Use #data_source_exists? instead.
76
- MSG
77
-
78
- tables.include?(table_name.to_s)
79
- end
80
-
81
54
  # Returns an array of indexes for the given table.
82
55
  def indexes(table_name, name = nil)
83
56
  @connection.indexes(table_name, name)
@@ -96,7 +69,7 @@ module ActiveRecord
96
69
  end
97
70
 
98
71
  def collation
99
- select_value "SELECT Collation = CAST(SERVERPROPERTY('Collation') AS NVARCHAR(128))"
72
+ @collation ||= select_value("SELECT Collation = CAST(SERVERPROPERTY('Collation') AS NVARCHAR(128))")
100
73
  end
101
74
 
102
75
  def current_database
@@ -178,10 +151,10 @@ module ActiveRecord
178
151
  end
179
152
 
180
153
  # @private these cannot specify a limit
181
- NO_LIMIT_TYPES = %w(text binary boolean date)
154
+ NO_LIMIT_TYPES = %i[text binary boolean date].freeze
182
155
 
183
- def type_to_sql(type, limit = nil, precision = nil, scale = nil)
184
- type_s = type.to_s
156
+ # Maps logical Rails types to MSSQL-specific data types.
157
+ def type_to_sql(type, limit: nil, precision: nil, scale: nil, **) # :nodoc:
185
158
  # MSSQL's NVARCHAR(n | max) column supports either a number between 1 and
186
159
  # 4000, or the word "MAX", which corresponds to 2**30-1 UCS-2 characters.
187
160
  #
@@ -190,11 +163,14 @@ module ActiveRecord
190
163
  #
191
164
  # See: http://msdn.microsoft.com/en-us/library/ms186939.aspx
192
165
  #
193
- if type_s == 'string' && limit == 1073741823
194
- 'NVARCHAR(MAX)'
195
- elsif NO_LIMIT_TYPES.include?(type_s)
166
+ type = type.to_sym if type
167
+ native = native_database_types[type]
168
+
169
+ if type == :string && limit == 1_073_741_823
170
+ 'nvarchar(max)'
171
+ elsif NO_LIMIT_TYPES.include?(type)
196
172
  super(type)
197
- elsif type_s == 'integer' || type_s == 'int'
173
+ elsif %i[int integer].include?(type)
198
174
  if limit.nil? || limit == 4
199
175
  'int'
200
176
  elsif limit == 2
@@ -204,8 +180,22 @@ module ActiveRecord
204
180
  else
205
181
  'bigint'
206
182
  end
207
- elsif type_s == 'uniqueidentifier'
208
- type_s
183
+ elsif type == :uniqueidentifier
184
+ 'uniqueidentifier'
185
+ elsif %i[datetime time].include?(type)
186
+ precision ||= 7
187
+ column_type_sql = (native.is_a?(Hash) ? native[:name] : native).dup
188
+ if (0..7).include?(precision)
189
+ column_type_sql << "(#{precision})"
190
+ else
191
+ raise(
192
+ ActiveRecordError,
193
+ "No #{native[:name]} type has precision of #{precision}. The " \
194
+ 'allowed range of precision is from 0 to 7, even though the ' \
195
+ 'sql type precision is 7 this adapter will persist up to 6 ' \
196
+ 'precision only.'
197
+ )
198
+ end
209
199
  else
210
200
  super
211
201
  end
@@ -241,7 +231,11 @@ module ActiveRecord
241
231
  default = extract_new_default_value(default_or_changes)
242
232
  unless default.nil?
243
233
  column = columns(table_name).find { |c| c.name.to_s == column_name.to_s }
244
- result = execute "ALTER TABLE #{quote_table_name(table_name)} ADD CONSTRAINT DF_#{table_name}_#{column_name} DEFAULT #{quote_default_expression(default, column)} FOR #{quote_column_name(column_name)}"
234
+ result = execute(
235
+ "ALTER TABLE #{quote_table_name(table_name)} " \
236
+ "ADD CONSTRAINT DF_#{table_name}_#{column_name} " \
237
+ "DEFAULT #{quote_default_expression(default, column)} FOR #{quote_column_name(column_name)}"
238
+ )
245
239
  result
246
240
  end
247
241
  end
@@ -257,11 +251,21 @@ module ActiveRecord
257
251
  end
258
252
 
259
253
  if !options[:null].nil? && options[:null] == false && !options[:default].nil?
260
- execute "UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote_default_expression(options[:default], column)} WHERE #{quote_column_name(column_name)} IS NULL"
254
+ execute(
255
+ "UPDATE #{quote_table_name(table_name)} SET " \
256
+ "#{quote_column_name(column_name)}=#{quote_default_expression(options[:default], column)} " \
257
+ "WHERE #{quote_column_name(column_name)} IS NULL"
258
+ )
261
259
  end
262
260
 
263
261
  change_column_type(table_name, column_name, type, options)
264
- change_column_default(table_name, column_name, options[:default]) if options_include_default?(options)
262
+
263
+ if options_include_default?(options)
264
+ change_column_default(table_name, column_name, options[:default])
265
+ elsif options.key?(:default) && options[:null] == false
266
+ # Drop default constraint when null option is false
267
+ remove_default_constraint(table_name, column_name)
268
+ end
265
269
 
266
270
  # add any removed indexes back
267
271
  indexes.each do |index|
@@ -280,7 +284,7 @@ module ActiveRecord
280
284
  end
281
285
  sql_alter = [
282
286
  "ALTER TABLE #{quoted_table}",
283
- "ALTER COLUMN #{quoted_column} #{type_to_sql column.type, column.limit, column.precision, column.scale}",
287
+ "ALTER COLUMN #{quoted_column} #{type_to_sql(column.type, limit: column.limit, precision: column.precision, scale: column.scale)}",
284
288
  (' NOT NULL' unless null)
285
289
  ]
286
290
 
@@ -289,8 +293,33 @@ module ActiveRecord
289
293
 
290
294
  private
291
295
 
296
+ def data_source_sql(name = nil, type: nil)
297
+ scope = quoted_scope(name, type: type)
298
+ table_name = 'TABLE_NAME'
299
+
300
+ sql = "SELECT #{table_name}"
301
+ sql << ' FROM INFORMATION_SCHEMA.TABLES'
302
+ sql << ' WHERE TABLE_CATALOG = DB_NAME()'
303
+ sql << " AND TABLE_SCHEMA = #{quote(scope[:schema])}"
304
+ sql << " AND TABLE_NAME = #{quote(scope[:name])}" if scope[:name]
305
+ sql << " AND TABLE_TYPE = #{quote(scope[:type])}" if scope[:type]
306
+ sql << " ORDER BY #{table_name}"
307
+ sql
308
+ end
309
+
310
+ def quoted_scope(raw_name = nil, type: nil)
311
+ schema = ArJdbc::MSSQL::Utils.unqualify_table_schema(raw_name)
312
+ name = ArJdbc::MSSQL::Utils.unqualify_table_name(raw_name)
313
+
314
+ scope = {}
315
+ scope[:schema] = schema || 'dbo'
316
+ scope[:name] = name if name
317
+ scope[:type] = type if type
318
+ scope
319
+ end
320
+
292
321
  def change_column_type(table_name, column_name, type, options = {})
293
- sql = "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
322
+ sql = "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} #{type_to_sql(type, limit: options[:limit], precision: options[:precision], scale: options[:scale])}"
294
323
  sql << (options[:null] ? " NULL" : " NOT NULL") if options.has_key?(:null)
295
324
  result = execute(sql)
296
325
  result
@@ -8,12 +8,12 @@ module ActiveRecord
8
8
 
9
9
  class DateTime2 < ActiveRecord::Type::DateTime
10
10
  def type_cast_for_schema(value)
11
- return "'#{value}'" if value.acts_like?(:string)
11
+ return %("#{value}") if value.acts_like?(:string)
12
12
 
13
13
  if value.usec > 0
14
- "'#{value.to_s(:db)}.#{value.usec.to_s.remove(/0+$/)}'"
14
+ %("#{value.to_s(:db)}.#{value.usec.to_s.remove(/0+$/)}")
15
15
  else
16
- "'#{value.to_s(:db)}'"
16
+ %("#{value.to_s(:db)}")
17
17
  end
18
18
  end
19
19
 
@@ -49,12 +49,12 @@ module ActiveRecord
49
49
  end
50
50
 
51
51
  def type_cast_for_schema(value)
52
- return "'#{value}'" if value.acts_like?(:string)
52
+ return %("#{value}") if value.acts_like?(:string)
53
53
 
54
54
  if value.usec > 0
55
- "'#{value.to_s(:db)}.#{value.usec.to_s.remove(/0+$/)}'"
55
+ %("#{value.to_s(:db)}.#{value.usec.to_s.remove(/0+$/)}")
56
56
  else
57
- "'#{value.to_s(:db)}'"
57
+ %("#{value.to_s(:db)}")
58
58
  end
59
59
  end
60
60
 
@@ -95,12 +95,12 @@ module ActiveRecord
95
95
 
96
96
  class Time < ActiveRecord::Type::Time
97
97
  def type_cast_for_schema(value)
98
- return "'#{value}'" if value.acts_like?(:string)
98
+ return %("#{value}") if value.acts_like?(:string)
99
99
 
100
100
  if value.usec > 0
101
- "'#{value.to_s(:db)}.#{value.usec.to_s.remove(/0+$/)}'"
101
+ %("#{value.to_s(:db)}.#{value.usec.to_s.remove(/0+$/)}")
102
102
  else
103
- "'#{value.to_s(:db)}'"
103
+ %("#{value.to_s(:db)}")
104
104
  end
105
105
  end
106
106
 
@@ -41,6 +41,7 @@ module ArJdbc
41
41
  end
42
42
 
43
43
  def unqualify_table_name(table_name)
44
+ return if table_name.blank?
44
45
  remove_identifier_delimiters(table_name.to_s.split('.').last)
45
46
  end
46
47
 
data/lib/arjdbc/mssql.rb CHANGED
@@ -4,4 +4,4 @@ require 'arjdbc/mssql/connection_methods'
4
4
  module ArJdbc
5
5
  MsSQL = MSSQL # compatibility with 1.2
6
6
  end
7
- ArJdbc.warn_unsupported_adapter 'mssql', [5, 0] # warns on AR >= 4.2
7
+ ArJdbc.warn_unsupported_adapter 'mssql', [5, 1] # warns on AR >= 4.2
@@ -61,6 +61,10 @@ module ActiveRecord
61
61
  true
62
62
  end
63
63
 
64
+ def supports_transaction_isolation?
65
+ true
66
+ end
67
+
64
68
  # HELPER METHODS ===========================================
65
69
 
66
70
  # Reloading the type map in abstract/statement_cache.rb blows up postgres
@@ -92,7 +96,14 @@ module ActiveRecord
92
96
 
93
97
  #--
94
98
  # QUOTING ==================================================
95
- #++
99
+ #+
100
+
101
+ # FIXME: 5.1 crashes without this. I think this is Arel hitting a fallback path in to_sql.rb.
102
+ # So maybe an untested code path in their source. Still means we are doing something wrong to
103
+ # even hit it.
104
+ def quote(value, comment=nil)
105
+ super(value)
106
+ end
96
107
 
97
108
  # NOTE: quote_string(string) provided by ArJdbc::MySQL (native code),
98
109
  # this piece is also native (mysql2) under MRI: `@connection.escape(string)`
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  ArJdbc::ConnectionMethods.module_eval do
3
3
  def mysql_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.mysql2_connection ActiveRecord::Base.configurations['arunit'].merge(database: ...)
7
6
  config = symbolize_keys_if_necessary(config)
@@ -11,9 +10,11 @@ ArJdbc::ConnectionMethods.module_eval do
11
10
 
12
11
  return jndi_connection(config) if jndi_config?(config)
13
12
 
14
- driver = config[:driver]
15
- mysql_driver = driver.nil? || driver.to_s.start_with?('com.mysql.')
16
- mariadb_driver = ! mysql_driver && driver.to_s.start_with?('org.mariadb.')
13
+ driver = config[:driver] ||=
14
+ defined?(::Jdbc::MySQL.driver_name) ? ::Jdbc::MySQL.driver_name : 'com.mysql.jdbc.Driver'
15
+
16
+ mysql_driver = driver.start_with?('com.mysql.')
17
+ mariadb_driver = ! mysql_driver && driver.start_with?('org.mariadb.')
17
18
 
18
19
  begin
19
20
  require 'jdbc/mysql'
@@ -21,11 +22,6 @@ ArJdbc::ConnectionMethods.module_eval do
21
22
  rescue LoadError # assuming driver.jar is on the class-path
22
23
  end if mysql_driver
23
24
 
24
- if driver.nil?
25
- config[:driver] ||=
26
- defined?(::Jdbc::MySQL.driver_name) ? ::Jdbc::MySQL.driver_name : 'com.mysql.jdbc.Driver'
27
- end
28
-
29
25
  config[:username] = 'root' unless config.key?(:username)
30
26
  # jdbc:mysql://[host][,failoverhost...][:port]/[database]
31
27
  # - if the host name is not specified, it defaults to 127.0.0.1
@@ -40,8 +36,7 @@ ArJdbc::ConnectionMethods.module_eval do
40
36
 
41
37
  properties = ( config[:properties] ||= {} )
42
38
  if mysql_driver
43
- properties['zeroDateTimeBehavior'] ||=
44
- config[:driver].to_s.start_with?('com.mysql.cj.') ? 'CONVERT_TO_NULL' : 'convertToNull'
39
+ properties['zeroDateTimeBehavior'] ||= 'convertToNull'
45
40
  properties['jdbcCompliantTruncation'] ||= false
46
41
  # NOTE: this is "better" than passing what users are used to set on MRI
47
42
  # e.g. 'utf8mb4' will fail cause the driver will check for a Java charset
@@ -113,8 +108,7 @@ ArJdbc::ConnectionMethods.module_eval do
113
108
  rescue LoadError # assuming driver.jar is on the class-path
114
109
  end
115
110
 
116
- config[:driver] ||=
117
- defined?(::Jdbc::MariaDB.driver_name) ? ::Jdbc::MariaDB.driver_name : 'org.mariadb.jdbc.Driver'
111
+ config[:driver] ||= 'org.mariadb.jdbc.Driver'
118
112
 
119
113
  mysql_connection(config)
120
114
  end