rails-sqlserver-2000-2005-adapter 2.2.6 → 2.2.7
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.
- data/CHANGELOG +13 -1
- data/README.rdoc +31 -3
- data/Rakefile +8 -0
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +26 -7
- data/lib/core_ext/active_record.rb +8 -0
- data/test/cases/adapter_test_sqlserver.rb +43 -0
- data/test/cases/execute_procedure_test_sqlserver.rb +33 -0
- data/test/cases/migration_test_sqlserver.rb +37 -1
- data/test/cases/sqlserver_helper.rb +16 -2
- metadata +2 -1
data/CHANGELOG
CHANGED
@@ -4,7 +4,19 @@ MASTER
|
|
4
4
|
*
|
5
5
|
|
6
6
|
|
7
|
-
* 2.2.
|
7
|
+
* 2.2.7 (January 9th, 2009)
|
8
|
+
|
9
|
+
* Created a connection#execute_procedure method that takes can take any number of ruby objects as variables
|
10
|
+
and quotes them according to the connection's rules. Also added an ActiveRecord::Base class level core
|
11
|
+
extension that hooks into this. It also checks if the connection responds to #execute_procedure and if
|
12
|
+
not returns an empty array. [Ken Collins]
|
13
|
+
|
14
|
+
* Added a #enable_default_unicode_types class attribute access to make all new added or changed string types
|
15
|
+
like :string/:text default to unicode/national data types. See the README for full details. Added a rake
|
16
|
+
task that assists setting this to true when running tests. [Ken Collins]
|
17
|
+
|
18
|
+
|
19
|
+
* 2.2.6 (January 8th, 2009)
|
8
20
|
|
9
21
|
* Introduced a bug in 2.2.5 in the #add_order! core ext for ActiveRecord. Fixed [Ken Collins]
|
10
22
|
|
data/README.rdoc
CHANGED
@@ -6,13 +6,14 @@ The SQL Server adapter for rails is back for ActiveRecord 2.2 and up! We are cur
|
|
6
6
|
|
7
7
|
== What's New
|
8
8
|
|
9
|
+
* An ActiveRecord::Base.execute_procedure method that can be used by classes.
|
9
10
|
* Enabled support for DDL transactions.
|
10
11
|
* Micro second support. Time#usec is automatically converted to SQL Server's 3.33 millisecond limitation.
|
11
12
|
* Datetime data types before type casting are represented correctly. For example: 1998-01-01 23:59:59.997
|
12
13
|
* Implementation for #disable_referential_integrity used by ActiveRecord's Fixtures class.
|
13
14
|
* Pessimistic locking suppot. See the #add_lock! method for details.
|
14
15
|
* Enabled #case_sensitive_equality_operator used by unique validations.
|
15
|
-
* Unicode character support for nchar, nvarchar and ntext data types.
|
16
|
+
* Unicode character support for nchar, nvarchar and ntext data types. Configuration option for defaulting all string data types to the unicode safe types.
|
16
17
|
* View support for table names, identity inserts, and column defaults.
|
17
18
|
|
18
19
|
==== Date/Time Data Type Hinting
|
@@ -26,6 +27,12 @@ Both SQL Server 2000 and 2005 do not have native data types for just 'date' or '
|
|
26
27
|
|
27
28
|
This implementation has some limitations. To date we can only coerce date/time types for models that conform to the expected ActiveRecord class to table naming convention. So a table of 'foo_bar_widgets' will look for coerced types in the FooBarWidget class if it exists.
|
28
29
|
|
30
|
+
==== Executing Stored Procedures
|
31
|
+
|
32
|
+
Every class that sub classes ActiveRecord::Base will now have an execute_procedure class method to use. This method takes the name of the stored procedure which can be a string or symbol and any number of variables to pass to the procedure. Arguments will automatically be quoted per the connection's standards as normal. For example.
|
33
|
+
|
34
|
+
Account.execute_procedure :update_totals, 'admin', nil, true
|
35
|
+
|
29
36
|
==== Native Data Type Support
|
30
37
|
|
31
38
|
Currently the following custom data types have been tested for schema definitions.
|
@@ -51,16 +58,20 @@ For example:
|
|
51
58
|
Manually creating a varchar(max) on SQL Server 2005 is not necessary since this is the default type created when specifying a :text field. As time goes on we will be testing other SQL Server specific data types are handled correctly when created in a migration.
|
52
59
|
|
53
60
|
|
54
|
-
==== Native Text/Binary Data Type Accessor
|
61
|
+
==== Native Text/String/Binary Data Type Accessor
|
55
62
|
|
56
63
|
To pass the ActiveRecord tests we had to implement an class accessor for the native type created for :text columns. By default any :text column created by migrations will create these native types.
|
57
64
|
|
58
65
|
* SQL Server 2000 is 'text'
|
59
66
|
* SQL Server 2005 is 'varchar(max)'
|
60
67
|
|
61
|
-
During testing this type is set to 'varchar(8000)' for
|
68
|
+
During testing this type is set to 'varchar(8000)' for SQL Server 2000. The reason is that rails expects to be able to use SQL = operators on text data types and this is not possible with a native 'text' data type in SQL Server. The default 'varchar(max)' for SQL Server 2005 can be queried using the SQL = operator and has plenty of storage space which is why we made it the default for 2005. If for some reason you want to change the data type created during migrations for any SQL Server version, you can configure this line to your liking in a config/initializers file.
|
62
69
|
|
63
70
|
ActiveRecord::ConnectionAdapters::SQLServerAdapter.native_text_database_type = 'varchar(8000)'
|
71
|
+
|
72
|
+
Also, there is a class attribute setter for the native string database type. This is the same for both SQL Server 2000 and 2005, 'varchar'. However in can be used instead of the #enable_default_unicode_types below for finer grain control over which types you want unicode safe when adding or changing the schema.
|
73
|
+
|
74
|
+
ActiveRecord::ConnectionAdapters::SQLServerAdapter.native_string_database_type = 'nvarchar'
|
64
75
|
|
65
76
|
By default any :binary column created by migrations will create these native types
|
66
77
|
|
@@ -68,6 +79,23 @@ By default any :binary column created by migrations will create these native typ
|
|
68
79
|
* SQL Server 2005 is 'varbinary(max)'
|
69
80
|
|
70
81
|
|
82
|
+
==== Setting Unicode Types As Default
|
83
|
+
|
84
|
+
By default the adapter will use non-unicode safe data types for :string and :text types when DEFINING or CHANGING the schema. If you choose, you can set the following class attribute in a config/initializers file that will change this behavior. When set to true it has the equivalent meaning as the two lower items. These examples show detail level alternatives to achieve similar effects.
|
85
|
+
|
86
|
+
ActiveRecord::ConnectionAdapters::SQLServerAdapter.enable_default_unicode_types = true
|
87
|
+
|
88
|
+
# SQL Server 2000
|
89
|
+
ActiveRecord::ConnectionAdapters::SQLServerAdapter.native_text_database_type = 'ntext'
|
90
|
+
ActiveRecord::ConnectionAdapters::SQLServerAdapter.native_string_database_type = 'nvarchar'
|
91
|
+
|
92
|
+
# SQL Server 2005
|
93
|
+
ActiveRecord::ConnectionAdapters::SQLServerAdapter.native_text_database_type = 'nvarchar(max)'
|
94
|
+
ActiveRecord::ConnectionAdapters::SQLServerAdapter.native_string_database_type = 'nvarchar'
|
95
|
+
|
96
|
+
It is important to remember that unicode types in SQL Server have approximately half the storage capacity as their counter parts. So where a normal string would max out at (8000) a unicode string will top off at (4000).
|
97
|
+
|
98
|
+
|
71
99
|
==== Schema Information Logging
|
72
100
|
|
73
101
|
By default all queries to the INFORMATION_SCHEMA table is silenced. If you think logging these queries are useful, you can enable it by adding this like to a config/initializers file.
|
data/Rakefile
CHANGED
@@ -27,6 +27,7 @@ task :recreate_databases => [:drop_databases, :create_databases]
|
|
27
27
|
|
28
28
|
|
29
29
|
for adapter in %w( sqlserver sqlserver_odbc )
|
30
|
+
|
30
31
|
Rake::TestTask.new("test_#{adapter}") { |t|
|
31
32
|
t.libs << "test"
|
32
33
|
t.libs << "test/connections/native_#{adapter}"
|
@@ -40,5 +41,12 @@ for adapter in %w( sqlserver sqlserver_odbc )
|
|
40
41
|
namespace adapter do
|
41
42
|
task :test => "test_#{adapter}"
|
42
43
|
end
|
44
|
+
|
43
45
|
end
|
44
46
|
|
47
|
+
desc 'Test with unicode types enabled.'
|
48
|
+
Rake::TestTask.new(:test_unicode_types) do |t|
|
49
|
+
ENV['ENABLE_DEFAULT_UNICODE_TYPES'] = 'true'
|
50
|
+
test = Rake::Task['test_sqlserver_odbc']
|
51
|
+
test.invoke
|
52
|
+
end
|
@@ -150,12 +150,13 @@ module ActiveRecord
|
|
150
150
|
class SQLServerAdapter < AbstractAdapter
|
151
151
|
|
152
152
|
ADAPTER_NAME = 'SQLServer'.freeze
|
153
|
-
VERSION = '2.2.
|
153
|
+
VERSION = '2.2.7'.freeze
|
154
154
|
DATABASE_VERSION_REGEXP = /Microsoft SQL Server\s+(\d{4})/
|
155
155
|
SUPPORTED_VERSIONS = [2000,2005].freeze
|
156
156
|
LIMITABLE_TYPES = ['string','integer','float','char','nchar','varchar','nvarchar'].freeze
|
157
157
|
|
158
|
-
cattr_accessor :native_text_database_type, :native_binary_database_type, :
|
158
|
+
cattr_accessor :native_text_database_type, :native_binary_database_type, :native_string_database_type,
|
159
|
+
:log_info_schema_queries, :enable_default_unicode_types
|
159
160
|
|
160
161
|
class << self
|
161
162
|
|
@@ -216,12 +217,21 @@ module ActiveRecord
|
|
216
217
|
"#<#{self.class} version: #{version}, year: #{database_year}, connection_options: #{@connection_options.inspect}>"
|
217
218
|
end
|
218
219
|
|
220
|
+
def native_string_database_type
|
221
|
+
@@native_string_database_type || (enable_default_unicode_types ? 'nvarchar' : 'varchar')
|
222
|
+
end
|
223
|
+
|
219
224
|
def native_text_database_type
|
220
|
-
|
225
|
+
@@native_text_database_type ||
|
226
|
+
if sqlserver_2005?
|
227
|
+
enable_default_unicode_types ? 'nvarchar(max)' : 'varchar(max)'
|
228
|
+
else
|
229
|
+
enable_default_unicode_types ? 'ntext' : 'text'
|
230
|
+
end
|
221
231
|
end
|
222
232
|
|
223
233
|
def native_binary_database_type
|
224
|
-
|
234
|
+
@@native_binary_database_type || (sqlserver_2005? ? 'varbinary(max)' : 'image')
|
225
235
|
end
|
226
236
|
|
227
237
|
# QUOTING ==================================================#
|
@@ -324,6 +334,15 @@ module ActiveRecord
|
|
324
334
|
finish_statement_handle(handle)
|
325
335
|
end
|
326
336
|
|
337
|
+
def execute_procedure(proc_name, *variables)
|
338
|
+
holders = (1..variables.size).to_a.map{|n|'?'}.join(', ')
|
339
|
+
statement = "EXEC #{proc_name} #{holders}".strip
|
340
|
+
sql = statement.gsub('?') { quote(variables.shift) }
|
341
|
+
select(sql,'PROCEDURE',true).inject([]) do |results,row|
|
342
|
+
results << row.with_indifferent_access
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
327
346
|
def begin_db_transaction
|
328
347
|
do_execute "BEGIN TRANSACTION"
|
329
348
|
end
|
@@ -426,8 +445,8 @@ module ActiveRecord
|
|
426
445
|
def native_database_types
|
427
446
|
{
|
428
447
|
:primary_key => "int NOT NULL IDENTITY(1, 1) PRIMARY KEY",
|
429
|
-
:string => { :name =>
|
430
|
-
:text => { :name =>
|
448
|
+
:string => { :name => native_string_database_type, :limit => 255 },
|
449
|
+
:text => { :name => native_text_database_type },
|
431
450
|
:integer => { :name => "int", :limit => 4 },
|
432
451
|
:float => { :name => "float", :limit => 8 },
|
433
452
|
:decimal => { :name => "decimal" },
|
@@ -435,7 +454,7 @@ module ActiveRecord
|
|
435
454
|
:timestamp => { :name => "datetime" },
|
436
455
|
:time => { :name => "datetime" },
|
437
456
|
:date => { :name => "datetime" },
|
438
|
-
:binary => { :name =>
|
457
|
+
:binary => { :name => native_binary_database_type },
|
439
458
|
:boolean => { :name => "bit"},
|
440
459
|
# These are custom types that may move somewhere else for good schema_dumper.rb hacking to output them.
|
441
460
|
:char => { :name => 'char' },
|
@@ -12,6 +12,14 @@ module ActiveRecord
|
|
12
12
|
|
13
13
|
module ClassMethods
|
14
14
|
|
15
|
+
def execute_procedure(proc_name, *variables)
|
16
|
+
if connection.respond_to?(:execute_procedure)
|
17
|
+
connection.execute_procedure(proc_name,*variables)
|
18
|
+
else
|
19
|
+
[]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
15
23
|
def coerce_sqlserver_date(*attributes)
|
16
24
|
write_inheritable_attribute :coerced_sqlserver_date_columns, Set.new(attributes.map(&:to_s))
|
17
25
|
end
|
@@ -194,6 +194,35 @@ class AdapterTestSqlserver < ActiveRecord::TestCase
|
|
194
194
|
|
195
195
|
end
|
196
196
|
|
197
|
+
context 'testing #enable_default_unicode_types configuration' do
|
198
|
+
|
199
|
+
should 'use non-unicode types when set to false' do
|
200
|
+
with_enable_default_unicode_types(false) do
|
201
|
+
if sqlserver_2000?
|
202
|
+
assert_equal 'varchar', @connection.native_string_database_type
|
203
|
+
assert_equal 'text', @connection.native_text_database_type
|
204
|
+
elsif sqlserver_2005?
|
205
|
+
assert_equal 'varchar', @connection.native_string_database_type
|
206
|
+
assert_equal 'varchar(max)', @connection.native_text_database_type
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
should 'use unicode types when set to true' do
|
212
|
+
with_enable_default_unicode_types(true) do
|
213
|
+
if sqlserver_2000?
|
214
|
+
assert_equal 'nvarchar', @connection.native_string_database_type
|
215
|
+
assert_equal 'ntext', @connection.native_text_database_type
|
216
|
+
elsif sqlserver_2005?
|
217
|
+
assert_equal 'nvarchar', @connection.native_string_database_type
|
218
|
+
assert_equal 'nvarchar(max)', @connection.native_text_database_type
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
end
|
224
|
+
|
225
|
+
|
197
226
|
end
|
198
227
|
|
199
228
|
context 'For chronic data types' do
|
@@ -530,6 +559,20 @@ class AdapterTestSqlserver < ActiveRecord::TestCase
|
|
530
559
|
@connection.send :order_to_min_set, order
|
531
560
|
end
|
532
561
|
|
562
|
+
def with_enable_default_unicode_types(setting)
|
563
|
+
old_setting = ActiveRecord::ConnectionAdapters::SQLServerAdapter.enable_default_unicode_types
|
564
|
+
old_text = ActiveRecord::ConnectionAdapters::SQLServerAdapter.native_text_database_type
|
565
|
+
old_string = ActiveRecord::ConnectionAdapters::SQLServerAdapter.native_string_database_type
|
566
|
+
ActiveRecord::ConnectionAdapters::SQLServerAdapter.enable_default_unicode_types = setting
|
567
|
+
ActiveRecord::ConnectionAdapters::SQLServerAdapter.native_text_database_type = nil
|
568
|
+
ActiveRecord::ConnectionAdapters::SQLServerAdapter.native_string_database_type = nil
|
569
|
+
yield
|
570
|
+
ensure
|
571
|
+
ActiveRecord::ConnectionAdapters::SQLServerAdapter.enable_default_unicode_types = old_setting
|
572
|
+
ActiveRecord::ConnectionAdapters::SQLServerAdapter.native_text_database_type = old_text
|
573
|
+
ActiveRecord::ConnectionAdapters::SQLServerAdapter.native_string_database_type = old_string
|
574
|
+
end
|
575
|
+
|
533
576
|
end
|
534
577
|
|
535
578
|
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'cases/sqlserver_helper'
|
2
|
+
|
3
|
+
class ExecuteProcedureTestSqlserver < ActiveRecord::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@klass = ActiveRecord::Base
|
7
|
+
end
|
8
|
+
|
9
|
+
should 'execute a simple procedure' do
|
10
|
+
tables = @klass.execute_procedure :sp_tables
|
11
|
+
assert_instance_of Array, tables
|
12
|
+
assert_instance_of HashWithIndifferentAccess, tables.first
|
13
|
+
end
|
14
|
+
|
15
|
+
should 'take parameter arguments' do
|
16
|
+
tables = @klass.execute_procedure :sp_tables, 'sql_server_chronics'
|
17
|
+
table_info = tables.first
|
18
|
+
assert_equal 1, tables.size
|
19
|
+
assert_equal 'activerecord_unittest', table_info[:TABLE_QUALIFIER], "Table Info: #{table_info.inspect}"
|
20
|
+
assert_equal 'TABLE', table_info[:TABLE_TYPE], "Table Info: #{table_info.inspect}"
|
21
|
+
end
|
22
|
+
|
23
|
+
should 'quote bind vars correctly' do
|
24
|
+
assert_sql(/EXEC sp_tables '%sql_server%', NULL, NULL, NULL, 1/) do
|
25
|
+
@klass.execute_procedure :sp_tables, '%sql_server%', nil, nil, nil, true
|
26
|
+
end if sqlserver_2005?
|
27
|
+
assert_sql(/EXEC sp_tables '%sql_server%', NULL, NULL, NULL/) do
|
28
|
+
@klass.execute_procedure :sp_tables, '%sql_server%', nil, nil, nil
|
29
|
+
end if sqlserver_2000?
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
end
|
@@ -40,7 +40,6 @@ class MigrationTest < ActiveRecord::TestCase
|
|
40
40
|
|
41
41
|
include SqlserverCoercedTest
|
42
42
|
|
43
|
-
|
44
43
|
def test_coerced_test_add_column_not_null_without_default
|
45
44
|
Person.connection.create_table :testings do |t|
|
46
45
|
t.column :foo, :string
|
@@ -53,5 +52,42 @@ class MigrationTest < ActiveRecord::TestCase
|
|
53
52
|
Person.connection.drop_table :testings rescue nil
|
54
53
|
end
|
55
54
|
|
55
|
+
end
|
56
|
+
|
57
|
+
class ChangeTableMigrationsTest < ActiveRecord::TestCase
|
58
|
+
|
59
|
+
COERCED_TESTS = [:test_string_creates_string_column]
|
60
|
+
|
61
|
+
include SqlserverCoercedTest
|
62
|
+
|
63
|
+
def setup
|
64
|
+
@connection = Person.connection
|
65
|
+
@connection.create_table :delete_me, :force => true do |t|
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def teardown
|
70
|
+
@connection.drop_table :delete_me rescue nil
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_coerced_string_creates_string_column
|
74
|
+
with_sqlserver_change_table do |t|
|
75
|
+
@connection.expects(:add_column).with(:delete_me, :foo, sqlserver_string_column, {})
|
76
|
+
@connection.expects(:add_column).with(:delete_me, :bar, sqlserver_string_column, {})
|
77
|
+
t.string :foo, :bar
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
protected
|
82
|
+
|
83
|
+
def with_sqlserver_change_table
|
84
|
+
@connection.change_table :delete_me do |t|
|
85
|
+
yield t
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def sqlserver_string_column
|
90
|
+
"#{@connection.native_string_database_type}(255)"
|
91
|
+
end
|
56
92
|
|
57
93
|
end
|
@@ -47,16 +47,30 @@ module SqlserverCoercedTest
|
|
47
47
|
self.const_get(:COERCED_TESTS) rescue nil
|
48
48
|
end
|
49
49
|
def method_added(method)
|
50
|
-
|
50
|
+
if coerced_tests && coerced_tests.include?(method)
|
51
|
+
undef_method(method)
|
52
|
+
STDOUT.puts("Undefined coerced test: #{self.name}##{method}")
|
53
|
+
end
|
51
54
|
end
|
52
55
|
end
|
53
56
|
end
|
54
57
|
|
58
|
+
# Set weather to test unicode string defaults or not. Used from rake task.
|
59
|
+
|
60
|
+
if ENV['ENABLE_DEFAULT_UNICODE_TYPES'] == 'true'
|
61
|
+
puts "With enabled unicode string types"
|
62
|
+
ActiveRecord::ConnectionAdapters::SQLServerAdapter.enable_default_unicode_types = true
|
63
|
+
end
|
64
|
+
|
55
65
|
# Change the text database type to support ActiveRecord's tests for = on text columns which
|
56
66
|
# is not supported in SQL Server text columns, so use varchar(8000) instead.
|
57
67
|
|
58
68
|
if ActiveRecord::Base.connection.sqlserver_2000?
|
59
|
-
ActiveRecord::ConnectionAdapters::SQLServerAdapter.
|
69
|
+
if ActiveRecord::ConnectionAdapters::SQLServerAdapter.enable_default_unicode_types
|
70
|
+
ActiveRecord::ConnectionAdapters::SQLServerAdapter.native_text_database_type = 'nvarchar(4000)'
|
71
|
+
else
|
72
|
+
ActiveRecord::ConnectionAdapters::SQLServerAdapter.native_text_database_type = 'varchar(8000)'
|
73
|
+
end
|
60
74
|
end
|
61
75
|
|
62
76
|
# Our changes/additions to ActiveRecord test helpers specific for SQL Server.
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails-sqlserver-2000-2005-adapter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.2.
|
4
|
+
version: 2.2.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ken Collins
|
@@ -75,6 +75,7 @@ test_files:
|
|
75
75
|
- test/cases/column_test_sqlserver.rb
|
76
76
|
- test/cases/connection_test_sqlserver.rb
|
77
77
|
- test/cases/eager_association_test_sqlserver.rb
|
78
|
+
- test/cases/execute_procedure_test_sqlserver.rb
|
78
79
|
- test/cases/inheritance_test_sqlserver.rb
|
79
80
|
- test/cases/migration_test_sqlserver.rb
|
80
81
|
- test/cases/offset_and_limit_test_sqlserver.rb
|