activerecord-jdbc-alt-adapter 61.2.0-java → 70.0.0.rc2-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 +118 -0
- data/.github/workflows/ruby.yml +273 -0
- data/.gitignore +1 -0
- data/.travis.yml +3 -4
- data/Gemfile +9 -7
- 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 +4 -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 +32 -17
- data/lib/arjdbc/mssql/schema_dumper.rb +13 -1
- data/lib/arjdbc/mssql/schema_statements.rb +61 -36
- data/lib/arjdbc/mssql/transaction.rb +2 -2
- 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 +152 -4
- data/lib/arjdbc/postgresql/oid_types.rb +142 -106
- data/lib/arjdbc/sqlite3/adapter.rb +132 -88
- data/lib/arjdbc/tasks/database_tasks.rb +0 -12
- 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 +9 -40
- 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?
|
@@ -14,80 +14,95 @@ module ActiveRecord
|
|
14
14
|
|
15
15
|
# datetime with seconds always zero (:00) and without fractional seconds
|
16
16
|
def smalldatetime(*args, **options)
|
17
|
-
args.each { |name| column(name, :smalldatetime, options) }
|
17
|
+
args.each { |name| column(name, :smalldatetime, **options) }
|
18
18
|
end
|
19
19
|
|
20
20
|
# this is the old sql server datetime type, the precision is as follow
|
21
21
|
# xx1, xx3, and xx7
|
22
22
|
def datetime_basic(*args, **options)
|
23
|
-
args.each { |name| column(name, :datetime_basic, options) }
|
23
|
+
args.each { |name| column(name, :datetime_basic, **options) }
|
24
24
|
end
|
25
25
|
|
26
26
|
def real(*args, **options)
|
27
|
-
args.each { |name| column(name, :real, options) }
|
27
|
+
args.each { |name| column(name, :real, **options) }
|
28
28
|
end
|
29
29
|
|
30
30
|
def money(*args, **options)
|
31
|
-
args.each { |name| column(name, :money, options) }
|
31
|
+
args.each { |name| column(name, :money, **options) }
|
32
32
|
end
|
33
33
|
|
34
34
|
def smallmoney(*args, **options)
|
35
|
-
args.each { |name| column(name, :smallmoney, options) }
|
35
|
+
args.each { |name| column(name, :smallmoney, **options) }
|
36
36
|
end
|
37
37
|
|
38
38
|
def char(*args, **options)
|
39
|
-
args.each { |name| column(name, :char, options) }
|
39
|
+
args.each { |name| column(name, :char, **options) }
|
40
40
|
end
|
41
41
|
|
42
42
|
def varchar(*args, **options)
|
43
|
-
args.each { |name| column(name, :varchar, options) }
|
43
|
+
args.each { |name| column(name, :varchar, **options) }
|
44
44
|
end
|
45
45
|
|
46
46
|
def varchar_max(*args, **options)
|
47
|
-
args.each { |name| column(name, :varchar_max, options) }
|
47
|
+
args.each { |name| column(name, :varchar_max, **options) }
|
48
48
|
end
|
49
49
|
|
50
50
|
def text_basic(*args, **options)
|
51
|
-
args.each { |name| column(name, :text_basic, options) }
|
51
|
+
args.each { |name| column(name, :text_basic, **options) }
|
52
52
|
end
|
53
53
|
|
54
54
|
def nchar(*args, **options)
|
55
|
-
args.each { |name| column(name, :nchar, options) }
|
55
|
+
args.each { |name| column(name, :nchar, **options) }
|
56
56
|
end
|
57
57
|
|
58
58
|
def ntext(*args, **options)
|
59
|
-
args.each { |name| column(name, :ntext, options) }
|
59
|
+
args.each { |name| column(name, :ntext, **options) }
|
60
60
|
end
|
61
61
|
|
62
62
|
def binary_basic(*args, **options)
|
63
|
-
args.each { |name| column(name, :binary_basic, options) }
|
63
|
+
args.each { |name| column(name, :binary_basic, **options) }
|
64
64
|
end
|
65
65
|
|
66
66
|
def varbinary(*args, **options)
|
67
|
-
args.each { |name| column(name, :varbinary, options) }
|
67
|
+
args.each { |name| column(name, :varbinary, **options) }
|
68
68
|
end
|
69
69
|
|
70
70
|
def uuid(*args, **options)
|
71
|
-
args.each { |name| column(name, :uniqueidentifier, options) }
|
71
|
+
args.each { |name| column(name, :uniqueidentifier, **options) }
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
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)
|
@@ -138,7 +146,7 @@ module ActiveRecord
|
|
138
146
|
execute "ALTER TABLE #{quote_table_name(table_name)} DROP COLUMN #{quote_column_name(column_name)}"
|
139
147
|
end
|
140
148
|
|
141
|
-
def drop_table(table_name, options
|
149
|
+
def drop_table(table_name, **options)
|
142
150
|
# mssql cannot recreate referenced table with force: :cascade
|
143
151
|
# https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-table-transact-sql?view=sql-server-2017
|
144
152
|
if options[:force] == :cascade
|
@@ -248,7 +256,7 @@ module ActiveRecord
|
|
248
256
|
(order_columns << super).join(', ')
|
249
257
|
end
|
250
258
|
|
251
|
-
def add_timestamps(table_name, options
|
259
|
+
def add_timestamps(table_name, **options)
|
252
260
|
if !options.key?(:precision) && supports_datetime_with_precision?
|
253
261
|
options[:precision] = 7
|
254
262
|
end
|
@@ -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:
|
@@ -345,11 +367,14 @@ module ActiveRecord
|
|
345
367
|
MSSQL::SchemaCreation.new(self)
|
346
368
|
end
|
347
369
|
|
348
|
-
def create_table_definition(
|
349
|
-
MSSQL::TableDefinition.new(self,
|
370
|
+
def create_table_definition(name, **options)
|
371
|
+
MSSQL::TableDefinition.new(self, name, **options)
|
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
|
|