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 CHANGED
@@ -4,7 +4,19 @@ MASTER
4
4
  *
5
5
 
6
6
 
7
- * 2.2.6 (January 8th, 2008)
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 both versions. 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.
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.6'.freeze
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, :log_info_schema_queries
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
- self.class.native_text_database_type || (sqlserver_2005? ? 'varchar(max)' : 'text')
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
- self.class.native_binary_database_type || (sqlserver_2005? ? 'varbinary(max)' : 'image')
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 => "varchar", :limit => 255 },
430
- :text => { :name => native_text_database_type },
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 => native_binary_database_type },
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
- undef_method(method) if coerced_tests && coerced_tests.include?(method)
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.native_text_database_type = 'varchar(8000)'
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.6
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