activerecord-sqlserver-adapter 5.0.5 → 5.0.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 69b10b0d78acaca77e2fab6abc716d5e696bd2f8
4
- data.tar.gz: 1fbba6b96b92e9b32c858545284d2a9f6769f291
3
+ metadata.gz: c87b967854fdb250bb0ca9159ca183a6193ae29a
4
+ data.tar.gz: 9b39e726bac55f07636ff11e23090512a7d35e96
5
5
  SHA512:
6
- metadata.gz: 27ac0eb8a5661af8ac248d860156cebf2d458ce62a0846c5d8c0f3b43b231f2ef84fd9c97be2c79df04083bab50d309a1576a89107b165c47b50b6f5b88ceb30
7
- data.tar.gz: e4e3ffb46db2289a830298f20fe5929afe021a05070c18145ed368979205e0039448a5efb2d186df2743c961ebc6ff7f1d0a09673afc37da97dd462c37391c56
6
+ metadata.gz: fa2739f0f136f581c72b66fa9207793204c837ff9ce7173f37ba4e0227b7378d9a71b44d877bcd889b4415fda0d3197a4008f9e8a614a88d71716879bad3481f
7
+ data.tar.gz: 30f4417f5f319feb26b1188fe579407bc8b3b3124c8c40ce62aed4f16e7225e95b0caa820f70ef0ee17b6779bd08a0bc5ec98a3c47cb70720ddb776aed1b13c2
@@ -4,7 +4,7 @@ services:
4
4
  - docker
5
5
  env:
6
6
  global:
7
- - TINYTDS_VERSION=1.1.0
7
+ - TINYTDS_VERSION=1.3.0
8
8
  - ACTIVERECORD_UNITTEST_HOST=localhost
9
9
  - ACTIVERECORD_UNITTEST_DATASERVER=localhost
10
10
  rvm:
@@ -1,3 +1,49 @@
1
+ ## v5.0.6
2
+
3
+ #### Fixed
4
+
5
+ * Performance w/inserts. Check binds & use schema cache for id inserts.
6
+ Fixes #572. Thanks @noelr.
7
+ * Add smalldatetime type for migrations. Fixes #507
8
+
9
+ #### Changed
10
+
11
+ * Misc index enhancements or testing. Fixes #570
12
+ Enable `supports_index_sort_order?`, test `supports_partial_index?`, test how expression indexes work.
13
+
14
+ #### Added
15
+
16
+ * New `primary_key_nonclustered` type for easy In-Memory table creation.
17
+ * Examples for an In-Memory table.
18
+
19
+ ```ruby
20
+ create_table :in_memory_table, id: false,
21
+ options: 'WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_AND_DATA)' do |t|
22
+ t.primary_key_nonclustered :id
23
+ t.string :name
24
+ t.timestamps
25
+ end
26
+ ```
27
+
28
+ * Enable supports_json? Fixes #577.
29
+
30
+ ```ruby
31
+ create_table :users do |t|
32
+ t.string :name, :email
33
+ t.json :data # Creates a nvarchar(max) column.
34
+ end
35
+
36
+ class Users < ActiveRecord::Base
37
+ attribute :data, ActiveRecord::Type::SQLServer::Json.new
38
+ end
39
+
40
+ User.create! name: 'Ken Collins', data: { 'admin' => true, 'foo' => 'bar' }
41
+
42
+ admin = User.where("JSON_VALUE(data, '$.admin') = CAST(1 AS BIT)").first
43
+ admin.data['foo'] # => "bar"
44
+ ```
45
+
46
+
1
47
  ## v5.0.5
2
48
 
3
49
  #### Changed
@@ -1,36 +1,5 @@
1
1
 
2
- ## SHORT TERM
2
+ ## Rails v5.1
3
3
 
4
- Misc remidners while in the heat of adapting the adpater.
5
-
6
-
7
- ## LONG TERM
8
-
9
- After we get some tests passing
10
-
11
- * Check `sql_for_insert` can do without the table regular expresion.
12
- * Do we need the `query_requires_identity_insert` check in `execute`?
13
- * Does the schema cache serialize properly since we conform to that now?
14
- * What does `supports_materialized_views?` means for SQL Server
15
- - http://michaeljswart.com/2014/12/materialized-views-in-sql-server/
16
- - https://blogs.msdn.microsoft.com/ssma/2011/06/20/migrating-oracle-materialized-view-to-sql-server/
17
- - http://stackoverflow.com/questions/3986366/how-to-create-materialized-views-in-sql-server
18
4
  * BIGINT PK support. https://github.com/rails/rails/pull/26266
19
- * Can we use `OPTIMIZE FOR UNKNOWN`
20
- - http://sqlblog.com/blogs/aaron_bertrand/archive/2011/09/17/bad-habits-to-kick-using-exec-instead-of-sp-executesql.aspx
21
- - http://stackoverflow.com/questions/24016199/sql-server-stored-procedure-become-very-slow-raw-sql-query-is-still-very-fast
22
- - https://blogs.msdn.microsoft.com/sqlprogrammability/2008/11/26/optimize-for-unknown-a-little-known-sql-server-2008-feature/
23
- * Re-visit all `current_adapter?(:PostgreSQLAdapter)` checks and find ones we can play in.
24
-
25
-
26
- #### Does Find By SQL Work?
27
-
28
- With binds and prepareable?
29
5
 
30
- ```ruby
31
- # Post.find_by_sql ["SELECT title FROM posts WHERE author = ? AND created > ?", author_id, start_date]
32
- # Post.find_by_sql ["SELECT body FROM comments WHERE author = :user_id OR approved_by = :user_id", { :user_id => user_id }]
33
- #
34
- def find_by_sql(sql, binds = [], preparable: nil)
35
- result_set = connection.select_all(sanitize_sql(sql), "#{name} Load", binds, preparable: preparable)
36
- ```
data/README.md CHANGED
@@ -1,3 +1,4 @@
1
+ [![Support via Gratipay](https://cdn.rawgit.com/gratipay/gratipay-badge/2.3.0/dist/gratipay.svg)](https://gratipay.com/metaskills/)
1
2
 
2
3
  # ActiveRecord SQL Server Adapter. For SQL Server 2012 And Higher.
3
4
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 5.0.5
1
+ 5.0.6
@@ -2,7 +2,7 @@ init:
2
2
  - SET PATH=C:\Ruby%ruby_version%\bin;%PATH%
3
3
  - SET PATH=C:\MinGW\msys\1.0\bin;%PATH%
4
4
  - SET RAKEOPT=-rdevkit
5
- - SET TINYTDS_VERSION=1.1.0
5
+ - SET TINYTDS_VERSION=1.3.0
6
6
  clone_depth: 5
7
7
  skip_tags: true
8
8
  matrix:
data/circle.yml CHANGED
@@ -6,7 +6,7 @@ general:
6
6
  machine:
7
7
  environment:
8
8
  PATH: /opt/local/bin:${PATH}
9
- TINYTDS_VERSION: 1.1.0
9
+ TINYTDS_VERSION: 1.3.0
10
10
  ACTIVERECORD_UNITTEST_HOST: localhost
11
11
  ACTIVERECORD_UNITTEST_DATASERVER: localhost
12
12
  services:
@@ -20,7 +20,7 @@ module ActiveRecord
20
20
  end
21
21
 
22
22
  def exec_insert(sql, name, binds, pk = nil, _sequence_name = nil)
23
- if pk && id_insert_table_name = query_requires_identity_insert?(sql)
23
+ if id_insert_table_name = exec_insert_requires_identity?(sql, pk, binds)
24
24
  with_identity_insert_enabled(id_insert_table_name) { exec_query(sql, name, binds) }
25
25
  else
26
26
  exec_query(sql, name, binds)
@@ -281,6 +281,30 @@ module ActiveRecord
281
281
  @update_sql = false
282
282
  end
283
283
 
284
+ # === SQLServer Specific (Identity Inserts) ===================== #
285
+
286
+ def exec_insert_requires_identity?(sql, pk, binds)
287
+ query_requires_identity_insert?(sql) if pk && binds.map(&:name).include?(pk)
288
+ end
289
+
290
+ def query_requires_identity_insert?(sql)
291
+ if insert_sql?(sql)
292
+ table_name = get_table_name(sql)
293
+ id_column = identity_columns(table_name).first
294
+ id_column && sql =~ /^\s*(INSERT|EXEC sp_executesql N'INSERT)[^(]+\([^)]*\b(#{id_column.name})\b,?[^)]*\)/i ? quote_table_name(table_name) : false
295
+ else
296
+ false
297
+ end
298
+ end
299
+
300
+ def insert_sql?(sql)
301
+ !(sql =~ /^\s*(INSERT|EXEC sp_executesql N'INSERT)/i).nil?
302
+ end
303
+
304
+ def identity_columns(table_name)
305
+ schema_cache.columns(table_name).select(&:is_identity?)
306
+ end
307
+
284
308
  # === SQLServer Specific (Selecting) ============================ #
285
309
 
286
310
  def raw_select(sql, name = 'SQL', binds = [], options = {})
@@ -253,6 +253,7 @@ module ActiveRecord
253
253
  def initialize_native_database_types
254
254
  {
255
255
  primary_key: 'int NOT NULL IDENTITY(1,1) PRIMARY KEY',
256
+ primary_key_nonclustered: 'int NOT NULL IDENTITY(1,1) PRIMARY KEY NONCLUSTERED',
256
257
  integer: { name: 'int', limit: 4 },
257
258
  bigint: { name: 'bigint' },
258
259
  boolean: { name: 'bit' },
@@ -280,7 +281,8 @@ module ActiveRecord
280
281
  varbinary: { name: 'varbinary', limit: 8000 },
281
282
  binary: { name: 'varbinary(max)' },
282
283
  uuid: { name: 'uniqueidentifier' },
283
- ss_timestamp: { name: 'timestamp' }
284
+ ss_timestamp: { name: 'timestamp' },
285
+ json: { name: 'nvarchar(max)' }
284
286
  }
285
287
  end
286
288
 
@@ -496,27 +498,6 @@ module ActiveRecord
496
498
  match_data ? match_data[1] : column_name
497
499
  end
498
500
 
499
- # === SQLServer Specific (Identity Inserts) ===================== #
500
-
501
- def query_requires_identity_insert?(sql)
502
- if insert_sql?(sql)
503
- table_name = get_table_name(sql)
504
- id_column = identity_columns(table_name).first
505
- id_column && sql =~ /^\s*(INSERT|EXEC sp_executesql N'INSERT)[^(]+\([^)]*\b(#{id_column.name})\b,?[^)]*\)/i ? quote_table_name(table_name) : false
506
- else
507
- false
508
- end
509
- end
510
-
511
- def insert_sql?(sql)
512
- !(sql =~ /^\s*(INSERT|EXEC sp_executesql N'INSERT)/i).nil?
513
- end
514
-
515
- def identity_columns(table_name)
516
- columns(table_name).select(&:is_identity?)
517
- end
518
-
519
-
520
501
  private
521
502
 
522
503
  def create_table_definition(*args)
@@ -11,6 +11,10 @@ module ActiveRecord
11
11
  column name, type, options
12
12
  end
13
13
 
14
+ def primary_key_nonclustered(*args, **options)
15
+ args.each { |name| column(name, :primary_key_nonclustered, options) }
16
+ end
17
+
14
18
  def real(*args, **options)
15
19
  args.each { |name| column(name, :real, options) }
16
20
  end
@@ -19,6 +23,10 @@ module ActiveRecord
19
23
  args.each { |name| column(name, :money, options) }
20
24
  end
21
25
 
26
+ def smalldatetime(*args, **options)
27
+ args.each { |name| column(name, :smalldatetime, options) }
28
+ end
29
+
22
30
  def datetime(*args, **options)
23
31
  args.each do |name|
24
32
  if options[:precision]
@@ -81,6 +89,10 @@ module ActiveRecord
81
89
  args.each { |name| column(name, :ss_timestamp, options) }
82
90
  end
83
91
 
92
+ def json(*args, **options)
93
+ args.each { |name| column(name, :text, options) }
94
+ end
95
+
84
96
  end
85
97
 
86
98
  class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
@@ -40,6 +40,7 @@ require 'active_record/connection_adapters/sqlserver/type/varbinary_max'
40
40
  # Other Data Types
41
41
  require 'active_record/connection_adapters/sqlserver/type/uuid'
42
42
  require 'active_record/connection_adapters/sqlserver/type/timestamp'
43
+ require 'active_record/connection_adapters/sqlserver/type/json'
43
44
 
44
45
  module ActiveRecord
45
46
  module Type
@@ -0,0 +1,11 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module SQLServer
4
+ module Type
5
+ class Json < ActiveRecord::Type::Internal::AbstractJson
6
+
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -19,7 +19,7 @@ module ActiveRecord
19
19
  end
20
20
 
21
21
  def apply_seconds_precision(value)
22
- value.change usec: 0
22
+ value.change usec: 0 if value
23
23
  end
24
24
 
25
25
  end
@@ -97,10 +97,6 @@ module ActiveRecord
97
97
  true
98
98
  end
99
99
 
100
- def supports_index_sort_order?
101
- false
102
- end
103
-
104
100
  def supports_partial_index?
105
101
  true
106
102
  end
@@ -134,7 +130,7 @@ module ActiveRecord
134
130
  end
135
131
 
136
132
  def supports_json?
137
- true
133
+ @version_year >= 2016
138
134
  end
139
135
 
140
136
  def supports_comments?
@@ -145,6 +141,10 @@ module ActiveRecord
145
141
  false
146
142
  end
147
143
 
144
+ def supports_in_memory_oltp?
145
+ @version_year >= 2014
146
+ end
147
+
148
148
  def disable_referential_integrity
149
149
  tables = tables_with_referential_integrity
150
150
  tables.each { |t| do_execute "ALTER TABLE #{t} NOCHECK CONSTRAINT ALL" }
@@ -304,6 +304,7 @@ module ActiveRecord
304
304
  register_class_with_limit m, %r{\Anvarchar}i, SQLServer::Type::UnicodeVarchar
305
305
  m.alias_type 'string', 'nvarchar(4000)'
306
306
  m.register_type 'nvarchar(max)', SQLServer::Type::UnicodeVarcharMax.new
307
+ m.register_type 'nvarchar(max)', SQLServer::Type::UnicodeVarcharMax.new
307
308
  m.register_type 'ntext', SQLServer::Type::UnicodeText.new
308
309
  # Binary Strings
309
310
  register_class_with_limit m, %r{\Abinary}i, SQLServer::Type::Binary
@@ -368,17 +369,15 @@ module ActiveRecord
368
369
  ).tap do |client|
369
370
  if config[:azure]
370
371
  client.execute('SET ANSI_NULLS ON').do
371
- client.execute('SET CURSOR_CLOSE_ON_COMMIT OFF').do
372
372
  client.execute('SET ANSI_NULL_DFLT_ON ON').do
373
- client.execute('SET IMPLICIT_TRANSACTIONS OFF').do
374
373
  client.execute('SET ANSI_PADDING ON').do
375
- client.execute('SET QUOTED_IDENTIFIER ON').do
376
374
  client.execute('SET ANSI_WARNINGS ON').do
377
375
  else
378
376
  client.execute('SET ANSI_DEFAULTS ON').do
379
- client.execute('SET CURSOR_CLOSE_ON_COMMIT OFF').do
380
- client.execute('SET IMPLICIT_TRANSACTIONS OFF').do
381
377
  end
378
+ client.execute('SET QUOTED_IDENTIFIER ON').do
379
+ client.execute('SET CURSOR_CLOSE_ON_COMMIT OFF').do
380
+ client.execute('SET IMPLICIT_TRANSACTIONS OFF').do
382
381
  client.execute('SET TEXTSIZE 2147483647').do
383
382
  client.execute('SET CONCAT_NULL_YIELDS_NULL ON').do
384
383
  end
@@ -420,6 +419,7 @@ module ActiveRecord
420
419
 
421
420
  def version_year
422
421
  vstring = _raw_select('SELECT @@version', fetch: :rows).first.first.to_s
422
+ return 2016 if vstring =~ /vNext/
423
423
  /SQL Server (\d+)/.match(vstring).to_a.last.to_s.to_i
424
424
  rescue Exception => e
425
425
  2016
@@ -3,7 +3,7 @@
3
3
  set -x
4
4
  set -e
5
5
 
6
- tag=1.3
6
+ tag=1.4
7
7
 
8
8
  docker pull metaskills/mssql-server-linux-rails:$tag
9
9
 
@@ -290,21 +290,6 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
290
290
 
291
291
  end
292
292
 
293
- describe 'indexes' do
294
-
295
- let(:desc_index_name) { 'idx_credit_limit_test_desc' }
296
-
297
- it 'have indexes with descending order' do
298
- begin
299
- connection.execute "CREATE INDEX [#{desc_index_name}] ON [accounts] (credit_limit DESC)"
300
- assert connection.indexes('accounts').find { |i| i.name == desc_index_name }
301
- ensure
302
- connection.execute "DROP INDEX [#{desc_index_name}] ON [accounts]"
303
- end
304
- end
305
-
306
- end
307
-
308
293
  describe 'views' do
309
294
 
310
295
  # Using connection.views
@@ -431,5 +416,14 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
431
416
 
432
417
  end
433
418
 
419
+ it 'in_memory_oltp' do
420
+ if ENV['IN_MEMORY_OLTP'] && connection.supports_in_memory_oltp?
421
+ SSTMemory.primary_key.must_equal 'id'
422
+ SSTMemory.columns_hash['id'].must_be :is_identity?
423
+ else
424
+ skip 'supports_in_memory_oltp? => false'
425
+ end
426
+ end
427
+
434
428
  end
435
429
 
@@ -806,3 +806,13 @@ module ActiveRecord
806
806
  coerce_tests! %r{with offset which return 0 rows}
807
807
  end
808
808
  end
809
+
810
+
811
+
812
+
813
+ module ActiveRecord
814
+ class StatementCacheTest < ActiveRecord::TestCase
815
+ # Getting random failures.
816
+ coerce_tests! :test_find_does_not_use_statement_cache_if_table_name_is_changed
817
+ end
818
+ end
@@ -36,7 +36,7 @@ class ConnectionTestSQLServer < ActiveRecord::TestCase
36
36
  describe 'Connection management' do
37
37
 
38
38
  it 'set spid on connect' do
39
- assert_instance_of Fixnum, connection.spid
39
+ ['Fixnum', 'Integer'].must_include connection.spid.class.name
40
40
  end
41
41
 
42
42
  it 'reset spid on disconnect!' do
@@ -3,6 +3,7 @@ require 'bundler/setup'
3
3
  Bundler.require :default, :development
4
4
  require 'pry'
5
5
  require 'support/minitest_sqlserver'
6
+ require 'support/test_in_memory_oltp'
6
7
  require 'cases/helper'
7
8
  require 'support/load_schema_sqlserver'
8
9
  require 'support/coerceable_test_sqlserver'
@@ -0,0 +1,47 @@
1
+ require 'cases/helper_sqlserver'
2
+
3
+ class IndexTestSQLServer < ActiveRecord::TestCase
4
+
5
+ before do
6
+ connection.create_table(:testings) do |t|
7
+ t.column :foo, :string, limit: 100
8
+ t.column :bar, :string, limit: 100
9
+ t.string :first_name
10
+ t.string :last_name, limit: 100
11
+ t.string :key, limit: 100
12
+ t.boolean :administrator
13
+ end
14
+ end
15
+
16
+ after do
17
+ connection.drop_table :testings rescue nil
18
+ end
19
+
20
+ it 'add index with order' do
21
+ assert_sql(/CREATE.*INDEX.*\(\[last_name\] DESC\)/i) do
22
+ connection.add_index 'testings', ['last_name'], order: { last_name: :desc }
23
+ connection.remove_index 'testings', ['last_name']
24
+ end
25
+ assert_sql(/CREATE.*INDEX.*\(\[last_name\] DESC, \[first_name\]\)/i) do
26
+ connection.add_index 'testings', ['last_name', 'first_name'], order: { last_name: :desc }
27
+ connection.remove_index 'testings', ['last_name', 'first_name']
28
+ end
29
+ assert_sql(/CREATE.*INDEX.*\(\[last_name\] DESC, \[first_name\] ASC\)/i) do
30
+ connection.add_index 'testings', ['last_name', 'first_name'], order: { last_name: :desc, first_name: :asc }
31
+ connection.remove_index 'testings', ['last_name', 'first_name']
32
+ end
33
+ end
34
+
35
+ it 'add index with where' do
36
+ assert_sql(/CREATE.*INDEX.*\(\[last_name\]\) WHERE \[first_name\] = N'john doe'/i) do
37
+ connection.add_index 'testings', 'last_name', where: "[first_name] = N'john doe'"
38
+ connection.remove_index 'testings', 'last_name'
39
+ end
40
+ end
41
+
42
+ it 'add index with expression' do
43
+ connection.execute "ALTER TABLE [testings] ADD [first_name_upper] AS UPPER([first_name])"
44
+ connection.add_index 'testings', 'first_name_upper'
45
+ end
46
+
47
+ end
@@ -0,0 +1,32 @@
1
+ require 'cases/helper_sqlserver'
2
+
3
+ if ActiveRecord::Base.connection.supports_json?
4
+ class JsonTestSQLServer < ActiveRecord::TestCase
5
+
6
+ before do
7
+ @o1 = SSTestDatatypeMigrationJson.create! json_col: { 'a' => 'a', 'b' => 'b', 'c' => 'c' }
8
+ @o2 = SSTestDatatypeMigrationJson.create! json_col: { 'a' => nil, 'b' => 'b', 'c' => 'c' }
9
+ @o3 = SSTestDatatypeMigrationJson.create! json_col: { 'x' => 1, 'y' => 2, 'z' => 3 }
10
+ @o4 = SSTestDatatypeMigrationJson.create! json_col: { 'array' => [1, 2, 3] }
11
+ @o5 = SSTestDatatypeMigrationJson.create! json_col: nil
12
+ end
13
+
14
+ it 'can return and save JSON data' do
15
+ SSTestDatatypeMigrationJson.find(@o1.id).json_col.must_equal({ 'a' => 'a', 'b' => 'b', 'c' => 'c' })
16
+ @o1.json_col = { 'a' => 'a' }
17
+ @o1.json_col.must_equal({ 'a' => 'a' })
18
+ @o1.save!
19
+ @o1.reload.json_col.must_equal({ 'a' => 'a' })
20
+ end
21
+
22
+ it 'can use ISJSON function' do
23
+ SSTestDatatypeMigrationJson.where('ISJSON(json_col) > 0').count.must_equal 4
24
+ SSTestDatatypeMigrationJson.where('ISJSON(json_col) IS NULL').count.must_equal 1
25
+ end
26
+
27
+ it 'can use JSON_VALUE function' do
28
+ SSTestDatatypeMigrationJson.where("JSON_VALUE(json_col, '$.b') = 'b'").count.must_equal 2
29
+ end
30
+
31
+ end
32
+ end
@@ -85,6 +85,7 @@ class SchemaDumperTestSQLServer < ActiveRecord::TestCase
85
85
  # Our type methods.
86
86
  columns['real_col'].sql_type.must_equal 'real'
87
87
  columns['money_col'].sql_type.must_equal 'money'
88
+ columns['smalldatetime_col'].sql_type.must_equal 'smalldatetime'
88
89
  columns['datetime2_col'].sql_type.must_equal 'datetime2(7)'
89
90
  columns['datetimeoffset'].sql_type.must_equal 'datetimeoffset(7)'
90
91
  columns['smallmoney_col'].sql_type.must_equal 'smallmoney'
@@ -97,8 +98,10 @@ class SchemaDumperTestSQLServer < ActiveRecord::TestCase
97
98
  columns['varbinary_col'].sql_type.must_equal 'varbinary(8000)'
98
99
  columns['uuid_col'].sql_type.must_equal 'uniqueidentifier'
99
100
  columns['sstimestamp_col'].sql_type.must_equal 'timestamp'
101
+ columns['json_col'].sql_type.must_equal 'nvarchar(max)'
100
102
  assert_line :real_col, type: 'real', limit: nil, precision: nil, scale: nil, default: nil
101
103
  assert_line :money_col, type: 'money', limit: nil, precision: 19, scale: 4, default: nil
104
+ assert_line :smalldatetime_col, type: 'smalldatetime', limit: nil, precision: nil, scale: nil, default: nil
102
105
  assert_line :datetime2_col, type: 'datetime', limit: nil, precision: 7, scale: nil, default: nil
103
106
  assert_line :datetimeoffset, type: 'datetimeoffset', limit: nil, precision: 7, scale: nil, default: nil
104
107
  assert_line :smallmoney_col, type: 'smallmoney', limit: nil, precision: 10, scale: 4, default: nil
@@ -111,6 +114,7 @@ class SchemaDumperTestSQLServer < ActiveRecord::TestCase
111
114
  assert_line :varbinary_col, type: 'varbinary', limit: nil, precision: nil, scale: nil, default: nil
112
115
  assert_line :uuid_col, type: 'uuid', limit: nil, precision: nil, scale: nil, default: nil
113
116
  assert_line :sstimestamp_col, type: 'ss_timestamp', limit: nil, precision: nil, scale: nil, default: nil
117
+ assert_line :json_col, type: 'text', limit: 2147483647, precision: nil, scale: nil, default: nil
114
118
  end
115
119
 
116
120
  # Special Cases
@@ -3,7 +3,6 @@ require 'cases/helper_sqlserver'
3
3
  class ScratchpadTestSQLServer < ActiveRecord::TestCase
4
4
 
5
5
  it 'helps debug things' do
6
- #
7
6
  end
8
7
 
9
8
  end
@@ -17,7 +17,7 @@ class SpecificSchemaTestSQLServer < ActiveRecord::TestCase
17
17
 
18
18
  it 'models can use tinyint pk tables' do
19
19
  obj = SSTestTinyintPk.create! name: '1'
20
- obj.id.is_a? Fixnum
20
+ ['Fixnum', 'Integer'].must_include obj.id.class.name
21
21
  SSTestTinyintPk.find(obj.id).must_equal obj
22
22
  end
23
23
 
@@ -1,3 +1,8 @@
1
1
  class SSTestDatatypeMigration < ActiveRecord::Base
2
2
  self.table_name = :sst_datatypes_migration
3
3
  end
4
+
5
+ class SSTestDatatypeMigrationJson < ActiveRecord::Base
6
+ self.table_name = :sst_datatypes_migration
7
+ attribute :json_col, ActiveRecord::Type::SQLServer::Json.new
8
+ end
@@ -0,0 +1,3 @@
1
+ class SSTMemory < ActiveRecord::Base
2
+ self.table_name = 'sst_memory'
3
+ end
@@ -0,0 +1,81 @@
1
+ -- https://msdn.microsoft.com/en-us/library/mt694156.aspx
2
+ -- https://raw.githubusercontent.com/Microsoft/sql-server-samples/master/samples/features/in-memory/t-sql-scripts/enable-in-memory-oltp.sql
3
+ --
4
+ -- The below scipt enables the use of In-Memory OLTP in the current database,
5
+ -- provided it is supported in the edition / pricing tier of the database.
6
+ -- It does the following:
7
+ -- 1. Validate that In-Memory OLTP is supported.
8
+ -- 2. In SQL Server, it will add a MEMORY_OPTIMIZED_DATA filegroup to the database
9
+ -- and create a container within the filegroup in the default data folder.
10
+ -- 3. Change the database compatibility level to 130 (needed for parallel queries
11
+ -- and auto-update of statistics).
12
+ -- 4. Enables the database option MEMORY_OPTIMIZED_ELEVATE_TO_SNAPSHOT to avoid the
13
+ -- need to use the WITH (SNAPSHOT) hint for ad hoc queries accessing memory-optimized
14
+ -- tables.
15
+ --
16
+ -- Applies To: SQL Server 2016 (or higher); Azure SQL Database
17
+ -- Author: Jos de Bruijn (Microsoft)
18
+ -- Last Updated: 2016-05-02
19
+
20
+ SET NOCOUNT ON;
21
+ SET XACT_ABORT ON;
22
+
23
+ -- 1. validate that In-Memory OLTP is supported
24
+ IF SERVERPROPERTY(N'IsXTPSupported') = 0
25
+ BEGIN
26
+ PRINT N'Error: In-Memory OLTP is not supported for this server edition or database pricing tier.';
27
+ END
28
+ IF DB_ID() < 5
29
+ BEGIN
30
+ PRINT N'Error: In-Memory OLTP is not supported in system databases. Connect to a user database.';
31
+ END
32
+ ELSE
33
+ BEGIN
34
+ BEGIN TRY;
35
+ -- 2. add MEMORY_OPTIMIZED_DATA filegroup when not using Azure SQL DB
36
+ IF SERVERPROPERTY('EngineEdition') != 5
37
+ BEGIN
38
+ DECLARE @SQLDataFolder nvarchar(max) = cast(SERVERPROPERTY('InstanceDefaultDataPath') as nvarchar(max))
39
+ DECLARE @MODName nvarchar(max) = DB_NAME() + N'_mod';
40
+ DECLARE @MemoryOptimizedFilegroupFolder nvarchar(max) = @SQLDataFolder + @MODName;
41
+
42
+ DECLARE @SQL nvarchar(max) = N'';
43
+
44
+ -- add filegroup
45
+ IF NOT EXISTS (SELECT 1 FROM sys.filegroups WHERE type = N'FX')
46
+ BEGIN
47
+ SET @SQL = N'
48
+ ALTER DATABASE CURRENT
49
+ ADD FILEGROUP ' + QUOTENAME(@MODName) + N' CONTAINS MEMORY_OPTIMIZED_DATA;';
50
+ EXECUTE (@SQL);
51
+
52
+ END;
53
+
54
+ -- add container in the filegroup
55
+ IF NOT EXISTS (SELECT * FROM sys.database_files WHERE data_space_id IN (SELECT data_space_id FROM sys.filegroups WHERE type = N'FX'))
56
+ BEGIN
57
+ SET @SQL = N'
58
+ ALTER DATABASE CURRENT
59
+ ADD FILE (name = N''' + @MODName + ''', filename = '''
60
+ + @MemoryOptimizedFilegroupFolder + N''')
61
+ TO FILEGROUP ' + QUOTENAME(@MODName);
62
+ EXECUTE (@SQL);
63
+ END
64
+ END
65
+
66
+ -- 3. set compat level to 130 if it is lower
67
+ IF (SELECT compatibility_level FROM sys.databases WHERE database_id=DB_ID()) < 130
68
+ ALTER DATABASE CURRENT SET COMPATIBILITY_LEVEL = 130
69
+
70
+ -- 4. enable MEMORY_OPTIMIZED_ELEVATE_TO_SNAPSHOT for the database
71
+ ALTER DATABASE CURRENT SET MEMORY_OPTIMIZED_ELEVATE_TO_SNAPSHOT = ON;
72
+
73
+
74
+ END TRY
75
+ BEGIN CATCH
76
+ PRINT N'Error enabling In-Memory OLTP';
77
+ IF XACT_STATE() != 0
78
+ ROLLBACK;
79
+ THROW;
80
+ END CATCH;
81
+ END;
@@ -21,6 +21,7 @@ ActiveRecord::Schema.define do
21
21
  # Our type methods.
22
22
  t.real :real_col
23
23
  t.money :money_col
24
+ t.smalldatetime :smalldatetime_col
24
25
  t.datetime2 :datetime2_col
25
26
  t.datetimeoffset :datetimeoffset
26
27
  t.smallmoney :smallmoney_col
@@ -33,10 +34,24 @@ ActiveRecord::Schema.define do
33
34
  t.varbinary :varbinary_col
34
35
  t.uuid :uuid_col
35
36
  t.ss_timestamp :sstimestamp_col
37
+ if supports_json?
38
+ t.json :json_col
39
+ else
40
+ t.text :json_col
41
+ end
36
42
  end
37
43
 
38
44
  # Edge Cases
39
45
 
46
+ if ENV['IN_MEMORY_OLTP'] && supports_in_memory_oltp?
47
+ create_table 'sst_memory', force: true, id: false,
48
+ options: 'WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_AND_DATA)' do |t|
49
+ t.primary_key_nonclustered :id
50
+ t.string :name
51
+ t.timestamps
52
+ end
53
+ end
54
+
40
55
  create_table 'sst_bookings', force: true do |t|
41
56
  t.string :name
42
57
  t.datetime2 :created_at, null: false
@@ -0,0 +1,15 @@
1
+ if ENV['IN_MEMORY_OLTP']
2
+ require 'config'
3
+ require 'active_record'
4
+ require 'support/config'
5
+ require 'support/connection'
6
+
7
+ ARTest.connect
8
+
9
+ if ActiveRecord::Base.connection.supports_in_memory_oltp?
10
+ puts 'Configuring In-Memory OLTP...'
11
+ inmem_file = ARTest::SQLServer.test_root_sqlserver, 'schema', 'enable-in-memory-oltp.sql'
12
+ inmem_sql = File.read File.join(inmem_file)
13
+ ActiveRecord::Base.connection.execute(inmem_sql)
14
+ end
15
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-sqlserver-adapter
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.5
4
+ version: 5.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ken Collins
@@ -14,7 +14,7 @@ authors:
14
14
  autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
- date: 2017-02-23 00:00:00.000000000 Z
17
+ date: 2017-03-22 00:00:00.000000000 Z
18
18
  dependencies:
19
19
  - !ruby/object:Gem::Dependency
20
20
  name: activerecord
@@ -98,6 +98,7 @@ files:
98
98
  - lib/active_record/connection_adapters/sqlserver/type/decimal.rb
99
99
  - lib/active_record/connection_adapters/sqlserver/type/float.rb
100
100
  - lib/active_record/connection_adapters/sqlserver/type/integer.rb
101
+ - lib/active_record/connection_adapters/sqlserver/type/json.rb
101
102
  - lib/active_record/connection_adapters/sqlserver/type/money.rb
102
103
  - lib/active_record/connection_adapters/sqlserver/type/real.rb
103
104
  - lib/active_record/connection_adapters/sqlserver/type/small_integer.rb
@@ -142,6 +143,8 @@ files:
142
143
  - test/cases/fetch_test_sqlserver.rb
143
144
  - test/cases/fully_qualified_identifier_test_sqlserver.rb
144
145
  - test/cases/helper_sqlserver.rb
146
+ - test/cases/index_test_sqlserver.rb
147
+ - test/cases/json_test_sqlserver.rb
145
148
  - test/cases/migration_test_sqlserver.rb
146
149
  - test/cases/order_test_sqlserver.rb
147
150
  - test/cases/pessimistic_locking_test_sqlserver.rb
@@ -174,6 +177,7 @@ files:
174
177
  - test/models/sqlserver/quoted_table.rb
175
178
  - test/models/sqlserver/quoted_view_1.rb
176
179
  - test/models/sqlserver/quoted_view_2.rb
180
+ - test/models/sqlserver/sst_memory.rb
177
181
  - test/models/sqlserver/string_default.rb
178
182
  - test/models/sqlserver/string_defaults_big_view.rb
179
183
  - test/models/sqlserver/string_defaults_view.rb
@@ -182,6 +186,7 @@ files:
182
186
  - test/models/sqlserver/uppered.rb
183
187
  - test/models/sqlserver/uuid.rb
184
188
  - test/schema/datatypes/2012.sql
189
+ - test/schema/enable-in-memory-oltp.sql
185
190
  - test/schema/sqlserver_specific_schema.rb
186
191
  - test/support/coerceable_test_sqlserver.rb
187
192
  - test/support/connection_reflection.rb
@@ -190,6 +195,7 @@ files:
190
195
  - test/support/paths_sqlserver.rb
191
196
  - test/support/rake_helpers.rb
192
197
  - test/support/sql_counter_sqlserver.rb
198
+ - test/support/test_in_memory_oltp.rb
193
199
  homepage: http://github.com/rails-sqlserver/activerecord-sqlserver-adapter
194
200
  licenses:
195
201
  - MIT
@@ -210,7 +216,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
210
216
  version: '0'
211
217
  requirements: []
212
218
  rubyforge_project:
213
- rubygems_version: 2.6.4
219
+ rubygems_version: 2.6.8
214
220
  signing_key:
215
221
  specification_version: 4
216
222
  summary: ActiveRecord SQL Server Adapter.
@@ -229,6 +235,8 @@ test_files:
229
235
  - test/cases/fetch_test_sqlserver.rb
230
236
  - test/cases/fully_qualified_identifier_test_sqlserver.rb
231
237
  - test/cases/helper_sqlserver.rb
238
+ - test/cases/index_test_sqlserver.rb
239
+ - test/cases/json_test_sqlserver.rb
232
240
  - test/cases/migration_test_sqlserver.rb
233
241
  - test/cases/order_test_sqlserver.rb
234
242
  - test/cases/pessimistic_locking_test_sqlserver.rb
@@ -261,6 +269,7 @@ test_files:
261
269
  - test/models/sqlserver/quoted_table.rb
262
270
  - test/models/sqlserver/quoted_view_1.rb
263
271
  - test/models/sqlserver/quoted_view_2.rb
272
+ - test/models/sqlserver/sst_memory.rb
264
273
  - test/models/sqlserver/string_default.rb
265
274
  - test/models/sqlserver/string_defaults_big_view.rb
266
275
  - test/models/sqlserver/string_defaults_view.rb
@@ -269,6 +278,7 @@ test_files:
269
278
  - test/models/sqlserver/uppered.rb
270
279
  - test/models/sqlserver/uuid.rb
271
280
  - test/schema/datatypes/2012.sql
281
+ - test/schema/enable-in-memory-oltp.sql
272
282
  - test/schema/sqlserver_specific_schema.rb
273
283
  - test/support/coerceable_test_sqlserver.rb
274
284
  - test/support/connection_reflection.rb
@@ -277,3 +287,4 @@ test_files:
277
287
  - test/support/paths_sqlserver.rb
278
288
  - test/support/rake_helpers.rb
279
289
  - test/support/sql_counter_sqlserver.rb
290
+ - test/support/test_in_memory_oltp.rb