activerecord-sqlserver-adapter 5.0.5 → 5.0.6

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 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