activerecord-jdbc-alt-adapter 61.3.0-java → 70.0.0-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +166 -0
- data/.github/workflows/ruby.yml +273 -0
- data/.gitignore +1 -0
- data/.travis.yml +3 -4
- data/Gemfile +5 -3
- data/README.md +5 -1
- data/Rakefile +1 -1
- data/activerecord-jdbc-adapter.gemspec +2 -2
- data/activerecord-jdbc-alt-adapter.gemspec +2 -2
- data/lib/arel/visitors/compat.rb +5 -33
- data/lib/arel/visitors/h2.rb +1 -13
- data/lib/arel/visitors/hsqldb.rb +1 -21
- data/lib/arel/visitors/sql_server.rb +2 -103
- data/lib/arjdbc/abstract/core.rb +8 -9
- data/lib/arjdbc/abstract/database_statements.rb +12 -4
- data/lib/arjdbc/discover.rb +0 -67
- data/lib/arjdbc/hsqldb/adapter.rb +2 -2
- data/lib/arjdbc/jdbc/adapter.rb +3 -3
- data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
- data/lib/arjdbc/jdbc/adapter_require.rb +3 -1
- data/lib/arjdbc/jdbc/column.rb +1 -26
- data/lib/arjdbc/jdbc/type_cast.rb +2 -2
- data/lib/arjdbc/jdbc.rb +0 -7
- data/lib/arjdbc/mssql/adapter.rb +138 -108
- data/lib/arjdbc/mssql/quoting.rb +26 -27
- data/lib/arjdbc/mssql/schema_creation.rb +1 -1
- data/lib/arjdbc/mssql/schema_definitions.rb +18 -3
- data/lib/arjdbc/mssql/schema_dumper.rb +13 -1
- data/lib/arjdbc/mssql/schema_statements.rb +57 -32
- data/lib/arjdbc/mssql/types/date_and_time_types.rb +6 -6
- data/lib/arjdbc/mssql/types/numeric_types.rb +2 -2
- data/lib/arjdbc/mssql.rb +1 -1
- data/lib/arjdbc/mysql/adapter.rb +2 -1
- data/lib/arjdbc/oracle/adapter.rb +4 -23
- data/lib/arjdbc/postgresql/adapter.rb +153 -4
- data/lib/arjdbc/postgresql/oid_types.rb +155 -108
- data/lib/arjdbc/sqlite3/adapter.rb +152 -99
- data/lib/arjdbc/tasks/database_tasks.rb +0 -12
- data/lib/arjdbc/tasks/mssql_database_tasks.rb +1 -1
- data/lib/arjdbc/util/serialized_attributes.rb +0 -22
- data/lib/arjdbc/util/table_copier.rb +2 -1
- data/lib/arjdbc/version.rb +1 -1
- data/rakelib/02-test.rake +3 -18
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +17 -2
- data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +5 -0
- data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +33 -0
- metadata +8 -39
- data/lib/active_record/connection_adapters/as400_adapter.rb +0 -2
- data/lib/active_record/connection_adapters/db2_adapter.rb +0 -1
- data/lib/active_record/connection_adapters/derby_adapter.rb +0 -1
- data/lib/active_record/connection_adapters/informix_adapter.rb +0 -1
- data/lib/arel/visitors/db2.rb +0 -137
- data/lib/arel/visitors/derby.rb +0 -112
- data/lib/arel/visitors/firebird.rb +0 -79
- data/lib/arjdbc/db2/adapter.rb +0 -808
- data/lib/arjdbc/db2/as400.rb +0 -142
- data/lib/arjdbc/db2/column.rb +0 -131
- data/lib/arjdbc/db2/connection_methods.rb +0 -48
- data/lib/arjdbc/db2.rb +0 -4
- data/lib/arjdbc/derby/active_record_patch.rb +0 -13
- data/lib/arjdbc/derby/adapter.rb +0 -521
- data/lib/arjdbc/derby/connection_methods.rb +0 -20
- data/lib/arjdbc/derby/schema_creation.rb +0 -15
- data/lib/arjdbc/derby.rb +0 -3
- data/lib/arjdbc/firebird/adapter.rb +0 -413
- data/lib/arjdbc/firebird/connection_methods.rb +0 -23
- data/lib/arjdbc/firebird.rb +0 -4
- data/lib/arjdbc/informix/adapter.rb +0 -139
- data/lib/arjdbc/informix/connection_methods.rb +0 -9
- data/lib/arjdbc/sybase/adapter.rb +0 -47
- data/lib/arjdbc/sybase.rb +0 -2
- data/lib/arjdbc/tasks/db2_database_tasks.rb +0 -104
- data/lib/arjdbc/tasks/derby_database_tasks.rb +0 -95
- data/src/java/arjdbc/derby/DerbyModule.java +0 -178
- data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +0 -152
- data/src/java/arjdbc/firebird/FirebirdRubyJdbcConnection.java +0 -174
- data/src/java/arjdbc/informix/InformixRubyJdbcConnection.java +0 -75
data/lib/arjdbc/mssql/adapter.rb
CHANGED
@@ -35,14 +35,15 @@ module ActiveRecord
|
|
35
35
|
ADAPTER_NAME = 'MSSQL'.freeze
|
36
36
|
|
37
37
|
MSSQL_VERSION_YEAR = {
|
38
|
-
8
|
39
|
-
9
|
38
|
+
8 => '2000',
|
39
|
+
9 => '2005',
|
40
40
|
10 => '2008',
|
41
41
|
11 => '2012',
|
42
42
|
12 => '2014',
|
43
43
|
13 => '2016',
|
44
44
|
14 => '2017',
|
45
|
-
15 => '2019'
|
45
|
+
15 => '2019',
|
46
|
+
16 => '2022'
|
46
47
|
}.freeze
|
47
48
|
|
48
49
|
include Jdbc::ConnectionPoolCallbacks
|
@@ -143,13 +144,32 @@ module ActiveRecord
|
|
143
144
|
def supports_insert_on_conflict?
|
144
145
|
false
|
145
146
|
end
|
147
|
+
|
146
148
|
alias supports_insert_on_duplicate_skip? supports_insert_on_conflict?
|
147
149
|
alias supports_insert_on_duplicate_update? supports_insert_on_conflict?
|
148
150
|
alias supports_insert_conflict_target? supports_insert_on_conflict?
|
149
151
|
|
152
|
+
def supports_insert_returning?
|
153
|
+
true
|
154
|
+
end
|
155
|
+
|
150
156
|
def build_insert_sql(insert) # :nodoc:
|
151
157
|
# TODO: hope we can implement an upsert like feature
|
152
|
-
"INSERT #{insert.into} #{insert.values_list}"
|
158
|
+
# "INSERT #{insert.into} #{insert.values_list}"
|
159
|
+
sql = +"INSERT #{insert.into}"
|
160
|
+
|
161
|
+
if returning = insert.send(:insert_all).returning
|
162
|
+
returning_sql = if returning.is_a?(String)
|
163
|
+
returning
|
164
|
+
else
|
165
|
+
returning.map { |column| "INSERTED.#{quote_column_name(column)}" }.join(', ')
|
166
|
+
end
|
167
|
+
|
168
|
+
sql << " OUTPUT #{returning_sql}"
|
169
|
+
end
|
170
|
+
|
171
|
+
sql << " #{insert.values_list}"
|
172
|
+
sql
|
153
173
|
end
|
154
174
|
|
155
175
|
# Overrides abstract method which always returns false
|
@@ -158,7 +178,7 @@ module ActiveRecord
|
|
158
178
|
end
|
159
179
|
|
160
180
|
def clear_cache!
|
161
|
-
reload_type_map
|
181
|
+
# reload_type_map
|
162
182
|
super
|
163
183
|
end
|
164
184
|
|
@@ -309,8 +329,121 @@ module ActiveRecord
|
|
309
329
|
end
|
310
330
|
end
|
311
331
|
|
332
|
+
class << self
|
333
|
+
private
|
334
|
+
|
335
|
+
# This method is called indirectly by the abstract method
|
336
|
+
# 'fetch_type_metadata' which then it is called by the java part when
|
337
|
+
# calculating a table's columns.
|
338
|
+
def initialize_type_map(map)
|
339
|
+
# Build the type mapping from SQL Server to ActiveRecord
|
340
|
+
|
341
|
+
# Integer types.
|
342
|
+
map.register_type 'int', MSSQL::Type::Integer.new(limit: 4)
|
343
|
+
map.register_type 'tinyint', MSSQL::Type::TinyInteger.new(limit: 1)
|
344
|
+
map.register_type 'smallint', MSSQL::Type::SmallInteger.new(limit: 2)
|
345
|
+
map.register_type 'bigint', MSSQL::Type::BigInteger.new(limit: 8)
|
346
|
+
|
347
|
+
# Exact Numeric types.
|
348
|
+
map.register_type %r{\Adecimal}i do |sql_type|
|
349
|
+
scale = extract_scale(sql_type)
|
350
|
+
precision = extract_precision(sql_type)
|
351
|
+
if scale == 0
|
352
|
+
MSSQL::Type::DecimalWithoutScale.new(precision: precision)
|
353
|
+
else
|
354
|
+
MSSQL::Type::Decimal.new(precision: precision, scale: scale)
|
355
|
+
end
|
356
|
+
end
|
357
|
+
map.register_type %r{\Amoney\z}i, MSSQL::Type::Money.new
|
358
|
+
map.register_type %r{\Asmallmoney\z}i, MSSQL::Type::SmallMoney.new
|
359
|
+
|
360
|
+
# Approximate Numeric types.
|
361
|
+
map.register_type %r{\Afloat\z}i, MSSQL::Type::Float.new
|
362
|
+
map.register_type %r{\Areal\z}i, MSSQL::Type::Real.new
|
363
|
+
|
364
|
+
# Character strings CHAR and VARCHAR (it can become Unicode UTF-8)
|
365
|
+
map.register_type 'varchar(max)', MSSQL::Type::VarcharMax.new
|
366
|
+
map.register_type %r{\Avarchar\(\d+\)} do |sql_type|
|
367
|
+
limit = extract_limit(sql_type)
|
368
|
+
MSSQL::Type::Varchar.new(limit: limit)
|
369
|
+
end
|
370
|
+
map.register_type %r{\Achar\(\d+\)} do |sql_type|
|
371
|
+
limit = extract_limit(sql_type)
|
372
|
+
MSSQL::Type::Char.new(limit: limit)
|
373
|
+
end
|
374
|
+
|
375
|
+
# Character strings NCHAR and NVARCHAR (by default Unicode UTF-16)
|
376
|
+
map.register_type %r{\Anvarchar\(\d+\)} do |sql_type|
|
377
|
+
limit = extract_limit(sql_type)
|
378
|
+
MSSQL::Type::Nvarchar.new(limit: limit)
|
379
|
+
end
|
380
|
+
map.register_type %r{\Anchar\(\d+\)} do |sql_type|
|
381
|
+
limit = extract_limit(sql_type)
|
382
|
+
MSSQL::Type::Nchar.new(limit: limit)
|
383
|
+
end
|
384
|
+
map.register_type 'nvarchar(max)', MSSQL::Type::NvarcharMax.new
|
385
|
+
map.register_type 'nvarchar(4000)', MSSQL::Type::Nvarchar.new
|
386
|
+
|
387
|
+
# Binary data types.
|
388
|
+
map.register_type 'varbinary(max)', MSSQL::Type::VarbinaryMax.new
|
389
|
+
register_class_with_limit map, %r{\Abinary\(\d+\)}, MSSQL::Type::BinaryBasic
|
390
|
+
register_class_with_limit map, %r{\Avarbinary\(\d+\)}, MSSQL::Type::Varbinary
|
391
|
+
|
392
|
+
# Miscellaneous types, Boolean, XML, UUID
|
393
|
+
# FIXME The xml data needs to be reviewed and fixed
|
394
|
+
map.register_type 'bit', MSSQL::Type::Boolean.new
|
395
|
+
map.register_type %r{\Auniqueidentifier\z}i, MSSQL::Type::UUID.new
|
396
|
+
map.register_type %r{\Axml\z}i, MSSQL::Type::XML.new
|
397
|
+
|
398
|
+
# Date and time types
|
399
|
+
map.register_type 'date', MSSQL::Type::Date.new
|
400
|
+
map.register_type 'datetime', MSSQL::Type::DateTime.new
|
401
|
+
map.register_type 'smalldatetime', MSSQL::Type::SmallDateTime.new
|
402
|
+
register_class_with_precision map, %r{\Atime\(\d+\)}i, MSSQL::Type::Time
|
403
|
+
map.register_type 'time(7)', MSSQL::Type::Time.new
|
404
|
+
register_class_with_precision map, %r{\Adatetime2\(\d+\)}i, MSSQL::Type::DateTime2
|
405
|
+
# map.register_type 'datetime2(7)', MSSQL::Type::DateTime2.new
|
406
|
+
|
407
|
+
# TODO: we should have identity separated from the sql_type
|
408
|
+
# let's say in another attribute (this will help to pass more AR tests),
|
409
|
+
# also we add collation attribute per column.
|
410
|
+
# aliases
|
411
|
+
map.alias_type 'int identity', 'int'
|
412
|
+
map.alias_type 'bigint identity', 'bigint'
|
413
|
+
map.alias_type 'integer', 'int'
|
414
|
+
map.alias_type 'integer', 'int'
|
415
|
+
map.alias_type 'INTEGER', 'int'
|
416
|
+
map.alias_type 'TINYINT', 'tinyint'
|
417
|
+
map.alias_type 'SMALLINT', 'smallint'
|
418
|
+
map.alias_type 'BIGINT', 'bigint'
|
419
|
+
map.alias_type %r{\Anumeric}i, 'decimal'
|
420
|
+
map.alias_type %r{\Anumber}i, 'decimal'
|
421
|
+
map.alias_type %r{\Adouble\z}i, 'float'
|
422
|
+
map.alias_type 'string', 'nvarchar(4000)'
|
423
|
+
map.alias_type %r{\Aboolean\z}i, 'bit'
|
424
|
+
map.alias_type 'DATE', 'date'
|
425
|
+
map.alias_type 'DATETIME', 'datetime'
|
426
|
+
map.alias_type 'SMALLDATETIME', 'smalldatetime'
|
427
|
+
map.alias_type %r{\Atime\z}i, 'time(7)'
|
428
|
+
map.alias_type %r{\Abinary\z}i, 'varbinary(max)'
|
429
|
+
map.alias_type %r{\Ablob\z}i, 'varbinary(max)'
|
430
|
+
map.alias_type %r{\Adatetime2\z}i, 'datetime2(7)'
|
431
|
+
|
432
|
+
# Deprecated SQL Server types.
|
433
|
+
map.register_type 'text', MSSQL::Type::Text.new
|
434
|
+
map.register_type 'ntext', MSSQL::Type::Ntext.new
|
435
|
+
map.register_type 'image', MSSQL::Type::Image.new
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
439
|
+
TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) }
|
440
|
+
|
312
441
|
private
|
313
442
|
|
443
|
+
def type_map
|
444
|
+
TYPE_MAP
|
445
|
+
end
|
446
|
+
|
314
447
|
def translate_exception(exception, message:, sql:, binds:)
|
315
448
|
case message
|
316
449
|
when /no connection available/i
|
@@ -334,109 +467,6 @@ module ActiveRecord
|
|
334
467
|
end
|
335
468
|
end
|
336
469
|
|
337
|
-
# This method is called indirectly by the abstract method
|
338
|
-
# 'fetch_type_metadata' which then it is called by the java part when
|
339
|
-
# calculating a table's columns.
|
340
|
-
def initialize_type_map(map = type_map)
|
341
|
-
# Build the type mapping from SQL Server to ActiveRecord
|
342
|
-
|
343
|
-
# Integer types.
|
344
|
-
map.register_type 'int', MSSQL::Type::Integer.new(limit: 4)
|
345
|
-
map.register_type 'tinyint', MSSQL::Type::TinyInteger.new(limit: 1)
|
346
|
-
map.register_type 'smallint', MSSQL::Type::SmallInteger.new(limit: 2)
|
347
|
-
map.register_type 'bigint', MSSQL::Type::BigInteger.new(limit: 8)
|
348
|
-
|
349
|
-
# Exact Numeric types.
|
350
|
-
map.register_type %r{\Adecimal}i do |sql_type|
|
351
|
-
scale = extract_scale(sql_type)
|
352
|
-
precision = extract_precision(sql_type)
|
353
|
-
if scale == 0
|
354
|
-
MSSQL::Type::DecimalWithoutScale.new(precision: precision)
|
355
|
-
else
|
356
|
-
MSSQL::Type::Decimal.new(precision: precision, scale: scale)
|
357
|
-
end
|
358
|
-
end
|
359
|
-
map.register_type %r{\Amoney\z}i, MSSQL::Type::Money.new
|
360
|
-
map.register_type %r{\Asmallmoney\z}i, MSSQL::Type::SmallMoney.new
|
361
|
-
|
362
|
-
# Approximate Numeric types.
|
363
|
-
map.register_type %r{\Afloat\z}i, MSSQL::Type::Float.new
|
364
|
-
map.register_type %r{\Areal\z}i, MSSQL::Type::Real.new
|
365
|
-
|
366
|
-
# Character strings CHAR and VARCHAR (it can become Unicode UTF-8)
|
367
|
-
map.register_type 'varchar(max)', MSSQL::Type::VarcharMax.new
|
368
|
-
map.register_type %r{\Avarchar\(\d+\)} do |sql_type|
|
369
|
-
limit = extract_limit(sql_type)
|
370
|
-
MSSQL::Type::Varchar.new(limit: limit)
|
371
|
-
end
|
372
|
-
map.register_type %r{\Achar\(\d+\)} do |sql_type|
|
373
|
-
limit = extract_limit(sql_type)
|
374
|
-
MSSQL::Type::Char.new(limit: limit)
|
375
|
-
end
|
376
|
-
|
377
|
-
# Character strings NCHAR and NVARCHAR (by default Unicode UTF-16)
|
378
|
-
map.register_type %r{\Anvarchar\(\d+\)} do |sql_type|
|
379
|
-
limit = extract_limit(sql_type)
|
380
|
-
MSSQL::Type::Nvarchar.new(limit: limit)
|
381
|
-
end
|
382
|
-
map.register_type %r{\Anchar\(\d+\)} do |sql_type|
|
383
|
-
limit = extract_limit(sql_type)
|
384
|
-
MSSQL::Type::Nchar.new(limit: limit)
|
385
|
-
end
|
386
|
-
map.register_type 'nvarchar(max)', MSSQL::Type::NvarcharMax.new
|
387
|
-
map.register_type 'nvarchar(4000)', MSSQL::Type::Nvarchar.new
|
388
|
-
|
389
|
-
# Binary data types.
|
390
|
-
map.register_type 'varbinary(max)', MSSQL::Type::VarbinaryMax.new
|
391
|
-
register_class_with_limit map, %r{\Abinary\(\d+\)}, MSSQL::Type::BinaryBasic
|
392
|
-
register_class_with_limit map, %r{\Avarbinary\(\d+\)}, MSSQL::Type::Varbinary
|
393
|
-
|
394
|
-
# Miscellaneous types, Boolean, XML, UUID
|
395
|
-
# FIXME The xml data needs to be reviewed and fixed
|
396
|
-
map.register_type 'bit', MSSQL::Type::Boolean.new
|
397
|
-
map.register_type %r{\Auniqueidentifier\z}i, MSSQL::Type::UUID.new
|
398
|
-
map.register_type %r{\Axml\z}i, MSSQL::Type::XML.new
|
399
|
-
|
400
|
-
# Date and time types
|
401
|
-
map.register_type 'date', MSSQL::Type::Date.new
|
402
|
-
map.register_type 'datetime', MSSQL::Type::DateTime.new
|
403
|
-
map.register_type 'smalldatetime', MSSQL::Type::SmallDateTime.new
|
404
|
-
register_class_with_precision map, %r{\Atime\(\d+\)}i, MSSQL::Type::Time
|
405
|
-
map.register_type 'time(7)', MSSQL::Type::Time.new
|
406
|
-
register_class_with_precision map, %r{\Adatetime2\(\d+\)}i, MSSQL::Type::DateTime2
|
407
|
-
map.register_type 'datetime2(7)', MSSQL::Type::DateTime2.new
|
408
|
-
|
409
|
-
# TODO: we should have identity separated from the sql_type
|
410
|
-
# let's say in another attribute (this will help to pass more AR tests),
|
411
|
-
# also we add collation attribute per column.
|
412
|
-
# aliases
|
413
|
-
map.alias_type 'int identity', 'int'
|
414
|
-
map.alias_type 'bigint identity', 'bigint'
|
415
|
-
map.alias_type 'integer', 'int'
|
416
|
-
map.alias_type 'integer', 'int'
|
417
|
-
map.alias_type 'INTEGER', 'int'
|
418
|
-
map.alias_type 'TINYINT', 'tinyint'
|
419
|
-
map.alias_type 'SMALLINT', 'smallint'
|
420
|
-
map.alias_type 'BIGINT', 'bigint'
|
421
|
-
map.alias_type %r{\Anumeric}i, 'decimal'
|
422
|
-
map.alias_type %r{\Anumber}i, 'decimal'
|
423
|
-
map.alias_type %r{\Adouble\z}i, 'float'
|
424
|
-
map.alias_type 'string', 'nvarchar(4000)'
|
425
|
-
map.alias_type %r{\Aboolean\z}i, 'bit'
|
426
|
-
map.alias_type 'DATE', 'date'
|
427
|
-
map.alias_type 'DATETIME', 'datetime'
|
428
|
-
map.alias_type 'SMALLDATETIME', 'smalldatetime'
|
429
|
-
map.alias_type %r{\Atime\z}i, 'time(7)'
|
430
|
-
map.alias_type %r{\Abinary\z}i, 'varbinary(max)'
|
431
|
-
map.alias_type %r{\Ablob\z}i, 'varbinary(max)'
|
432
|
-
map.alias_type %r{\Adatetime2\z}i, 'datetime2(7)'
|
433
|
-
|
434
|
-
# Deprecated SQL Server types.
|
435
|
-
map.register_type 'text', MSSQL::Type::Text.new
|
436
|
-
map.register_type 'ntext', MSSQL::Type::Ntext.new
|
437
|
-
map.register_type 'image', MSSQL::Type::Image.new
|
438
|
-
end
|
439
|
-
|
440
470
|
# Returns an array of Column objects for the table specified by +table_name+.
|
441
471
|
# See the concrete implementation for details on the expected parameter values.
|
442
472
|
# NOTE: This is ready, all implemented in the java part of adapter,
|
data/lib/arjdbc/mssql/quoting.rb
CHANGED
@@ -4,8 +4,30 @@ module ActiveRecord
|
|
4
4
|
module ConnectionAdapters
|
5
5
|
module MSSQL
|
6
6
|
module Quoting
|
7
|
-
QUOTED_TRUE = '1'
|
8
|
-
QUOTED_FALSE = '0'
|
7
|
+
QUOTED_TRUE = '1'
|
8
|
+
QUOTED_FALSE = '0'
|
9
|
+
|
10
|
+
def quote(value)
|
11
|
+
# FIXME: this needs improvements to handle other custom types.
|
12
|
+
# Also check if it's possible insert integer into a NVARCHAR
|
13
|
+
case value
|
14
|
+
when ActiveRecord::Type::Binary::Data
|
15
|
+
"0x#{value.hex}"
|
16
|
+
# when SomeOtherBinaryData then BLOB_VALUE_MARKER
|
17
|
+
# when SomeOtherData then "yyy"
|
18
|
+
when String, ActiveSupport::Multibyte::Chars
|
19
|
+
"N'#{quote_string(value)}'"
|
20
|
+
# when OnlyTimeType then "'#{quoted_time(value)}'"
|
21
|
+
when Date, Time
|
22
|
+
"'#{quoted_date(value)}'"
|
23
|
+
when TrueClass
|
24
|
+
quoted_true
|
25
|
+
when FalseClass
|
26
|
+
quoted_false
|
27
|
+
else
|
28
|
+
super
|
29
|
+
end
|
30
|
+
end
|
9
31
|
|
10
32
|
# Quote date/time values for use in SQL input, includes microseconds
|
11
33
|
# with three digits only if the value is a Time responding to usec.
|
@@ -15,7 +37,7 @@ module ActiveRecord
|
|
15
37
|
value = time_with_db_timezone(value)
|
16
38
|
end
|
17
39
|
|
18
|
-
result = value.
|
40
|
+
result = value.to_fs(:db)
|
19
41
|
|
20
42
|
if value.respond_to?(:usec) && value.usec > 0
|
21
43
|
"#{result}.#{sprintf("%06d", value.usec)}"
|
@@ -105,7 +127,7 @@ module ActiveRecord
|
|
105
127
|
private
|
106
128
|
|
107
129
|
def time_with_db_timezone(value)
|
108
|
-
zone_conv_method = if ActiveRecord
|
130
|
+
zone_conv_method = if ActiveRecord.default_timezone == :utc
|
109
131
|
:getutc
|
110
132
|
else
|
111
133
|
:getlocal
|
@@ -117,29 +139,6 @@ module ActiveRecord
|
|
117
139
|
value
|
118
140
|
end
|
119
141
|
end
|
120
|
-
|
121
|
-
# @override
|
122
|
-
# FIXME: it need to be improved to handle other custom types.
|
123
|
-
# Also check if it's possible insert integer into a NVARCHAR
|
124
|
-
def _quote(value)
|
125
|
-
case value
|
126
|
-
when ActiveRecord::Type::Binary::Data
|
127
|
-
"0x#{value.hex}"
|
128
|
-
# when SomeOtherBinaryData then BLOB_VALUE_MARKER
|
129
|
-
# when SomeOtherData then "yyy"
|
130
|
-
when String, ActiveSupport::Multibyte::Chars
|
131
|
-
"N'#{quote_string(value)}'"
|
132
|
-
# when OnlyTimeType then "'#{quoted_time(value)}'"
|
133
|
-
when Date, Time
|
134
|
-
"'#{quoted_date(value)}'"
|
135
|
-
when TrueClass
|
136
|
-
quoted_true
|
137
|
-
when FalseClass
|
138
|
-
quoted_false
|
139
|
-
else
|
140
|
-
super
|
141
|
-
end
|
142
|
-
end
|
143
142
|
end
|
144
143
|
end
|
145
144
|
end
|
@@ -29,7 +29,7 @@ module ActiveRecord
|
|
29
29
|
end
|
30
30
|
|
31
31
|
if supports_foreign_keys?
|
32
|
-
statements.concat(o.foreign_keys.map { |
|
32
|
+
statements.concat(o.foreign_keys.map { |fk| accept fk })
|
33
33
|
end
|
34
34
|
|
35
35
|
create_sql << "(#{statements.join(', ')})" if statements.present?
|
@@ -75,19 +75,34 @@ module ActiveRecord
|
|
75
75
|
class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
|
76
76
|
include ColumnMethods
|
77
77
|
|
78
|
+
def column(name, type, index: nil, **options)
|
79
|
+
# TODO: remove this when the below changed is released
|
80
|
+
# Fix erroneous nil default precision on virtual datetime columns #46110
|
81
|
+
# https://github.com/rails/rails/pull/46110
|
82
|
+
#
|
83
|
+
if @conn.supports_datetime_with_precision?
|
84
|
+
if type == :datetime && !options.key?(:precision)
|
85
|
+
options[:precision] = 7
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
super
|
90
|
+
end
|
91
|
+
|
92
|
+
|
78
93
|
def new_column_definition(name, type, **options)
|
79
94
|
case type
|
80
95
|
when :primary_key
|
81
96
|
options[:is_identity] = true
|
97
|
+
when :datetime
|
98
|
+
options[:precision] = 7 if !options.key?(:precision) && @conn.supports_datetime_with_precision?
|
82
99
|
end
|
83
100
|
|
84
101
|
super
|
85
102
|
end
|
86
103
|
|
87
104
|
def timestamps(**options)
|
88
|
-
if !options.key?(:precision) && @conn.supports_datetime_with_precision?
|
89
|
-
options[:precision] = 7
|
90
|
-
end
|
105
|
+
options[:precision] = 7 if !options.key?(:precision) && @conn.supports_datetime_with_precision?
|
91
106
|
|
92
107
|
super
|
93
108
|
end
|
@@ -28,11 +28,23 @@ module ActiveRecord
|
|
28
28
|
super && column.identity?
|
29
29
|
end
|
30
30
|
|
31
|
+
def schema_precision(column)
|
32
|
+
case column.type
|
33
|
+
when :datetime
|
34
|
+
if column.precision == 7
|
35
|
+
nil
|
36
|
+
else
|
37
|
+
column.precision.inspect
|
38
|
+
end
|
39
|
+
else
|
40
|
+
super
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
31
44
|
# def schema_collation(column)
|
32
45
|
# return unless column.collation
|
33
46
|
# column.collation if column.collation != collation
|
34
47
|
# end
|
35
|
-
|
36
48
|
end
|
37
49
|
end
|
38
50
|
end
|
@@ -7,36 +7,36 @@ module ActiveRecord
|
|
7
7
|
|
8
8
|
NATIVE_DATABASE_TYPES = {
|
9
9
|
# Logical Rails types to SQL Server types
|
10
|
-
primary_key:
|
11
|
-
integer:
|
12
|
-
boolean:
|
13
|
-
decimal:
|
14
|
-
float:
|
15
|
-
date:
|
16
|
-
time:
|
17
|
-
datetime:
|
18
|
-
string:
|
19
|
-
text:
|
20
|
-
binary:
|
10
|
+
primary_key: 'bigint NOT NULL IDENTITY(1,1) PRIMARY KEY',
|
11
|
+
integer: { name: 'int', limit: 4 },
|
12
|
+
boolean: { name: 'bit' },
|
13
|
+
decimal: { name: 'decimal' },
|
14
|
+
float: { name: 'float' },
|
15
|
+
date: { name: 'date' },
|
16
|
+
time: { name: 'time' },
|
17
|
+
datetime: { name: 'datetime2' },
|
18
|
+
string: { name: 'nvarchar', limit: 4000 },
|
19
|
+
text: { name: 'nvarchar(max)' },
|
20
|
+
binary: { name: 'varbinary(max)' },
|
21
21
|
# Other types or SQL Server specific
|
22
|
-
bigint:
|
23
|
-
smalldatetime:
|
22
|
+
bigint: { name: 'bigint' },
|
23
|
+
smalldatetime: { name: 'smalldatetime' },
|
24
24
|
datetime_basic: { name: 'datetime' },
|
25
|
-
timestamp:
|
26
|
-
real:
|
27
|
-
money:
|
28
|
-
smallmoney:
|
29
|
-
char:
|
30
|
-
nchar:
|
31
|
-
varchar:
|
32
|
-
varchar_max:
|
33
|
-
uuid:
|
34
|
-
binary_basic:
|
35
|
-
varbinary:
|
25
|
+
timestamp: { name: 'datetime' },
|
26
|
+
real: { name: 'real' },
|
27
|
+
money: { name: 'money' },
|
28
|
+
smallmoney: { name: 'smallmoney' },
|
29
|
+
char: { name: 'char' },
|
30
|
+
nchar: { name: 'nchar' },
|
31
|
+
varchar: { name: 'varchar', limit: 8000 },
|
32
|
+
varchar_max: { name: 'varchar(max)' },
|
33
|
+
uuid: { name: 'uniqueidentifier' },
|
34
|
+
binary_basic: { name: 'binary' },
|
35
|
+
varbinary: { name: 'varbinary', limit: 8000 },
|
36
36
|
# Deprecated SQL Server types
|
37
|
-
image:
|
38
|
-
ntext:
|
39
|
-
text_basic:
|
37
|
+
image: { name: 'image' },
|
38
|
+
ntext: { name: 'ntext' },
|
39
|
+
text_basic: { name: 'text' }
|
40
40
|
}.freeze
|
41
41
|
|
42
42
|
def native_database_types
|
@@ -127,9 +127,17 @@ module ActiveRecord
|
|
127
127
|
create_database(name, options)
|
128
128
|
end
|
129
129
|
|
130
|
-
def
|
131
|
-
|
130
|
+
def remove_columns(table_name, *column_names, type: nil, **options)
|
131
|
+
if column_names.empty?
|
132
|
+
raise ArgumentError.new('You must specify at least one column name. Example: remove_columns(:people, :first_name)')
|
133
|
+
end
|
134
|
+
|
135
|
+
column_names.each do |column_name|
|
136
|
+
remove_column(table_name, column_name, type, **options)
|
137
|
+
end
|
138
|
+
end
|
132
139
|
|
140
|
+
def remove_column(table_name, column_name, _type = nil, **options)
|
133
141
|
return if options[:if_exists] == true && !column_exists?(table_name, column_name)
|
134
142
|
|
135
143
|
remove_check_constraints(table_name, column_name)
|
@@ -256,6 +264,16 @@ module ActiveRecord
|
|
256
264
|
super
|
257
265
|
end
|
258
266
|
|
267
|
+
def add_column(table_name, column_name, type, **options)
|
268
|
+
if supports_datetime_with_precision?
|
269
|
+
if type == :datetime && !options.key?(:precision)
|
270
|
+
options[:precision] = 7
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
super
|
275
|
+
end
|
276
|
+
|
259
277
|
def create_schema_dumper(options)
|
260
278
|
MSSQL::SchemaDumper.create(self, options)
|
261
279
|
end
|
@@ -323,16 +341,20 @@ module ActiveRecord
|
|
323
341
|
quoted_table = quote_table_name(table_name)
|
324
342
|
quoted_column = quote_column_name(column_name)
|
325
343
|
quoted_default = quote(default)
|
344
|
+
|
326
345
|
unless null || default.nil?
|
327
346
|
execute("UPDATE #{quoted_table} SET #{quoted_column}=#{quoted_default} WHERE #{quoted_column} IS NULL")
|
328
347
|
end
|
348
|
+
|
349
|
+
options = { limit: column.limit, precision: column.precision, scale: column.scale }
|
350
|
+
|
329
351
|
sql_alter = [
|
330
352
|
"ALTER TABLE #{quoted_table}",
|
331
|
-
"ALTER COLUMN #{quoted_column} #{type_to_sql(column.type,
|
332
|
-
('
|
353
|
+
"ALTER COLUMN #{quoted_column} #{type_to_sql(column.type, **options)}",
|
354
|
+
('NOT NULL' unless null)
|
333
355
|
]
|
334
356
|
|
335
|
-
execute(sql_alter.join(' '))
|
357
|
+
execute(sql_alter.compact.join(' '))
|
336
358
|
end
|
337
359
|
|
338
360
|
def update_table_definition(table_name, base) #:nodoc:
|
@@ -350,6 +372,9 @@ module ActiveRecord
|
|
350
372
|
end
|
351
373
|
|
352
374
|
def new_column_from_field(table_name, field)
|
375
|
+
# NOTE: this method is used by the columns method in the abstract Class
|
376
|
+
# to map column_definitions. It would be good if column_definitions is
|
377
|
+
# implemented in ruby
|
353
378
|
field
|
354
379
|
end
|
355
380
|
|
@@ -13,9 +13,9 @@ module ActiveRecord
|
|
13
13
|
return %("#{value}") if value.acts_like?(:string)
|
14
14
|
|
15
15
|
if value.usec > 0
|
16
|
-
%("#{value.
|
16
|
+
%("#{value.to_fs(:db)}.#{value.usec.to_s.remove(/0+$/)}")
|
17
17
|
else
|
18
|
-
%("#{value.
|
18
|
+
%("#{value.to_fs(:db)}")
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
@@ -54,9 +54,9 @@ module ActiveRecord
|
|
54
54
|
return %("#{value}") if value.acts_like?(:string)
|
55
55
|
|
56
56
|
if value.usec > 0
|
57
|
-
%("#{value.
|
57
|
+
%("#{value.to_fs(:db)}.#{value.usec.to_s.remove(/0+$/)}")
|
58
58
|
else
|
59
|
-
%("#{value.
|
59
|
+
%("#{value.to_fs(:db)}")
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
@@ -100,9 +100,9 @@ module ActiveRecord
|
|
100
100
|
return %("#{value}") if value.acts_like?(:string)
|
101
101
|
|
102
102
|
if value.usec > 0
|
103
|
-
%("#{value.
|
103
|
+
%("#{value.to_fs(:db)}.#{value.usec.to_s.remove(/0+$/)}")
|
104
104
|
else
|
105
|
-
%("#{value.
|
105
|
+
%("#{value.to_fs(:db)}")
|
106
106
|
end
|
107
107
|
end
|
108
108
|
|
@@ -35,7 +35,7 @@ module ActiveRecord
|
|
35
35
|
end
|
36
36
|
|
37
37
|
class Money < Decimal
|
38
|
-
def initialize(
|
38
|
+
def initialize(precision: nil, limit: nil, scale: nil)
|
39
39
|
super
|
40
40
|
@precision = 19
|
41
41
|
@scale = 4
|
@@ -46,7 +46,7 @@ module ActiveRecord
|
|
46
46
|
end
|
47
47
|
|
48
48
|
class SmallMoney < Decimal
|
49
|
-
def initialize(
|
49
|
+
def initialize(precision: nil, limit: nil, scale: nil)
|
50
50
|
super
|
51
51
|
@precision = 10
|
52
52
|
@scale = 4
|
data/lib/arjdbc/mssql.rb
CHANGED
data/lib/arjdbc/mysql/adapter.rb
CHANGED