activerecord-sqlserver-adapter 2.3.8 → 2.3.9
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +16 -1
- data/RUNNING_UNIT_TESTS +4 -42
- data/Rakefile +51 -25
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +221 -136
- data/lib/active_record/connection_adapters/sqlserver_adapter/core_ext/active_record.rb +1 -1
- data/test/cases/adapter_test_sqlserver.rb +4 -19
- data/test/cases/basics_test_sqlserver.rb +3 -1
- data/test/cases/execute_procedure_test_sqlserver.rb +0 -9
- data/test/cases/migration_test_sqlserver.rb +0 -37
- data/test/cases/specific_schema_test_sqlserver.rb +49 -1
- data/test/cases/sqlserver_helper.rb +17 -10
- data/test/schema/sqlserver_specific_schema.rb +3 -0
- metadata +52 -9
- data/autotest/discover.rb +0 -4
- data/autotest/railssqlserver.rb +0 -16
- data/autotest/sqlserver.rb +0 -54
data/CHANGELOG
CHANGED
@@ -1,5 +1,20 @@
|
|
1
1
|
|
2
|
-
|
2
|
+
|
3
|
+
* 2.3.9
|
4
|
+
|
5
|
+
* Support DSN'less connections. Resolves ticket 38.
|
6
|
+
|
7
|
+
* Support upcoming ruby odbc 0.99992
|
8
|
+
|
9
|
+
* Include new raw connection interfaces developed and optimized under the 3.0 branch.
|
10
|
+
|
11
|
+
* The remove_column conforms to ArgumentError exceptions. [Ken Collins]
|
12
|
+
|
13
|
+
* Add support for default function values in schema reflection. Allows for uniqueidentifier default
|
14
|
+
values like NEWID(). These are not automatically inserted into the INSERT statement as of yet, that
|
15
|
+
could be done user side on a before save callback now. Includes new #newid_function and
|
16
|
+
#newsequentialid_function on the connection for helping. Resolves tikcet #42. [Ken Collins]
|
17
|
+
|
3
18
|
|
4
19
|
* 2.3.8
|
5
20
|
|
data/RUNNING_UNIT_TESTS
CHANGED
@@ -11,55 +11,17 @@ assumes you have a DSN setup that matches the name of the default database names
|
|
11
11
|
|
12
12
|
== Requirements
|
13
13
|
|
14
|
-
|
15
|
-
source. Info here. http://gems.github.com/
|
16
|
-
|
17
|
-
We use echoe for packagemanagement to rubyforge. Not needed really for the tests
|
18
|
-
but since we need it... you need to install it.
|
19
|
-
|
20
|
-
* gem install echoe
|
21
|
-
* gem install thoughtbot-shoulda -s http://gems.github.com
|
14
|
+
* gem install shoulda
|
22
15
|
* gem install mocha
|
23
16
|
|
24
|
-
The tests of this adapter depend on the existence of rails checkout.
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
#{RAILS_ROOT}/vendor/plugins/adapters/sqlserver
|
29
|
-
#{RAILS_ROOT}/vendor/rails/activerecord/test
|
17
|
+
The tests of this adapter depend on the existence of rails checkout. Make sure
|
18
|
+
to checkout remotes/origin/2-3-stable, then make sure to export RAILS_SOURCE to
|
19
|
+
the full path of that repo.
|
30
20
|
|
31
21
|
Define a user named 'rails' in SQL Server with all privileges granted for the
|
32
22
|
test databases. Use an empty password for said user.
|
33
23
|
|
34
24
|
|
35
|
-
== Running with Rake
|
36
|
-
|
37
|
-
The easiest way to run the unit tests is through Rake. Either run "rake test" which
|
38
|
-
defaults to ODBC mode or being mode specific using either "rake sqlserver:test:adonet"
|
39
|
-
or "rake sqlserver:test:odbc". For more information, checkout the full array of rake tasks
|
40
|
-
with "rake -T"
|
41
|
-
|
42
|
-
Rake can be found at http://rake.rubyforge.org
|
43
|
-
|
44
|
-
|
45
|
-
== Running with Autotest
|
46
|
-
|
47
|
-
Using autotest is easy, just run "autotest" and the tests will run continually in the
|
48
|
-
same order as the rake test command. By default autotest will use ODBC connection. If
|
49
|
-
you want to change this you can edit the autotest/sqlserver.rb file and set odbc_mode
|
50
|
-
to false.
|
51
|
-
|
52
|
-
Lastly, you can run autotest on just the adapter specific tests with "autotest sqlserver".
|
53
|
-
This will continuously run ONLY the SQL Sever specific behavior tests which are much
|
54
|
-
quicker to run than the entire active record test suite.
|
55
|
-
|
56
|
-
|
57
|
-
== Running by hand
|
58
25
|
|
59
|
-
Unit tests are located in test directory. If you only want to run a single test suite,
|
60
|
-
you can do so with:
|
61
26
|
|
62
|
-
rake test_sqlserver TEST=base_test.rb
|
63
|
-
|
64
|
-
That'll run the base suite using the SQLServer-Ruby adapter.
|
65
27
|
|
data/Rakefile
CHANGED
@@ -3,39 +3,65 @@ require 'rake/testtask'
|
|
3
3
|
require 'rake/rdoctask'
|
4
4
|
|
5
5
|
|
6
|
-
|
6
|
+
def test_libs(mode='odbc')
|
7
|
+
['lib',
|
8
|
+
'test',
|
9
|
+
"test/connections/native_sqlserver#{mode == 'adonet' ? '' : "_#{mode}"}",
|
10
|
+
"#{ENV['RAILS_SOURCE']}/activerecord/test"]
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_files
|
14
|
+
Dir.glob("test/cases/**/*_test_sqlserver.rb").sort +
|
15
|
+
(Dir.glob("#{ENV['RAILS_SOURCE']}/activerecord/test/cases/**/*_test.rb") -
|
16
|
+
Dir.glob("#{ENV['RAILS_SOURCE']}/activerecord/test/cases/adapters/**/*_test.rb")).sort
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
task :test => ['test:odbc']
|
21
|
+
|
22
|
+
|
23
|
+
namespace :test do
|
7
24
|
|
8
|
-
|
25
|
+
['odbc','adonet'].each do |mode|
|
9
26
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
t.libs << "test/connections/native_sqlserver#{mode == 'adonet' ? '' : "_#{mode}"}"
|
15
|
-
t.libs << "../../../rails/activerecord/test/"
|
16
|
-
t.test_files = (
|
17
|
-
Dir.glob("test/cases/**/*_test_sqlserver.rb").sort +
|
18
|
-
Dir.glob("../../../rails/activerecord/test/**/*_test.rb").sort )
|
19
|
-
t.verbose = true
|
20
|
-
end
|
21
|
-
|
22
|
-
end
|
23
|
-
|
24
|
-
desc 'Test with unicode types enabled, uses ODBC mode.'
|
25
|
-
task :unicode_types do
|
26
|
-
ENV['ENABLE_DEFAULT_UNICODE_TYPES'] = 'true'
|
27
|
-
test = Rake::Task['sqlserver:test:odbc']
|
28
|
-
test.invoke
|
27
|
+
Rake::TestTask.new(mode) do |t|
|
28
|
+
t.libs = test_libs(mode)
|
29
|
+
t.test_files = test_files
|
30
|
+
t.verbose = true
|
29
31
|
end
|
30
32
|
|
31
33
|
end
|
34
|
+
|
35
|
+
desc 'Test without unicode types enabled, uses ODBC mode.'
|
36
|
+
task :non_unicode_types do
|
37
|
+
ENV['ENABLE_DEFAULT_UNICODE_TYPES'] = 'false'
|
38
|
+
test = Rake::Task['test:odbc']
|
39
|
+
test.invoke
|
40
|
+
end
|
32
41
|
|
33
42
|
end
|
34
43
|
|
35
44
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
45
|
+
namespace :profile do
|
46
|
+
|
47
|
+
['odbc','adonet'].each do |mode|
|
48
|
+
namespace mode.to_sym do
|
49
|
+
|
50
|
+
Dir.glob("test/profile/*_profile_case.rb").sort.each do |test_file|
|
51
|
+
|
52
|
+
profile_case = File.basename(test_file).sub('_profile_case.rb','')
|
53
|
+
|
54
|
+
Rake::TestTask.new(profile_case) do |t|
|
55
|
+
t.libs = test_libs(mode)
|
56
|
+
t.test_files = [test_file]
|
57
|
+
t.verbose = true
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
40
65
|
end
|
41
66
|
|
67
|
+
|
@@ -20,7 +20,7 @@ module ActiveRecord
|
|
20
20
|
require 'System.Data'
|
21
21
|
raise ArgumentError, 'Missing :database configuration.' unless config.has_key?(:database)
|
22
22
|
when :ado
|
23
|
-
raise NotImplementedError, 'Please use version 2.3.1 of the adapter for ADO connections. Future versions
|
23
|
+
raise NotImplementedError, 'Please use version 2.3.1 of the adapter for ADO connections. Future versions support ADO.NET.'
|
24
24
|
raise ArgumentError, 'Missing :database configuration.' unless config.has_key?(:database)
|
25
25
|
else
|
26
26
|
raise ArgumentError, "Unknown connection mode in #{config.inspect}."
|
@@ -45,7 +45,7 @@ module ActiveRecord
|
|
45
45
|
class SQLServerColumn < Column
|
46
46
|
|
47
47
|
def initialize(name, default, sql_type = nil, null = true, sqlserver_options = {})
|
48
|
-
@sqlserver_options = sqlserver_options
|
48
|
+
@sqlserver_options = sqlserver_options.symbolize_keys
|
49
49
|
super(name, default, sql_type, null)
|
50
50
|
end
|
51
51
|
|
@@ -88,12 +88,15 @@ module ActiveRecord
|
|
88
88
|
end
|
89
89
|
|
90
90
|
def is_special?
|
91
|
-
|
92
|
-
sql_type =~ /^text|ntext|image$/
|
91
|
+
@sql_type =~ /^text|ntext|image$/
|
93
92
|
end
|
94
93
|
|
95
94
|
def is_utf8?
|
96
|
-
sql_type =~ /nvarchar|ntext|nchar/i
|
95
|
+
@sql_type =~ /nvarchar|ntext|nchar/i
|
96
|
+
end
|
97
|
+
|
98
|
+
def default_function
|
99
|
+
@sqlserver_options[:default_function]
|
97
100
|
end
|
98
101
|
|
99
102
|
def table_name
|
@@ -170,10 +173,11 @@ module ActiveRecord
|
|
170
173
|
class SQLServerAdapter < AbstractAdapter
|
171
174
|
|
172
175
|
ADAPTER_NAME = 'SQLServer'.freeze
|
173
|
-
VERSION = '2.3.
|
176
|
+
VERSION = '2.3.9'.freeze
|
174
177
|
DATABASE_VERSION_REGEXP = /Microsoft SQL Server\s+(\d{4})/
|
175
178
|
SUPPORTED_VERSIONS = [2000,2005,2008].freeze
|
176
|
-
LIMITABLE_TYPES = ['string','integer','float','char','nchar','varchar','nvarchar'].freeze
|
179
|
+
LIMITABLE_TYPES = ['string','integer','float','char','nchar','varchar','nvarchar'].to_set.freeze
|
180
|
+
QUOTED_TRUE, QUOTED_FALSE = '1', '0'
|
177
181
|
LOST_CONNECTION_EXCEPTIONS = {
|
178
182
|
:odbc => ['ODBC::Error'],
|
179
183
|
:adonet => ['TypeError','System::Data::SqlClient::SqlException']
|
@@ -183,6 +187,8 @@ module ActiveRecord
|
|
183
187
|
:adonet => [/current state is closed/, /network-related/]
|
184
188
|
}
|
185
189
|
|
190
|
+
attr_reader :database_version, :database_year,
|
191
|
+
:connection_supports_native_types
|
186
192
|
cattr_accessor :native_text_database_type, :native_binary_database_type, :native_string_database_type,
|
187
193
|
:log_info_schema_queries, :enable_default_unicode_types, :auto_connect
|
188
194
|
|
@@ -197,10 +203,13 @@ module ActiveRecord
|
|
197
203
|
def initialize(logger,config)
|
198
204
|
@connection_options = config
|
199
205
|
connect
|
200
|
-
super(
|
206
|
+
super(@connection, logger)
|
207
|
+
@database_version = info_schema_query { select_value('SELECT @@version') }
|
208
|
+
@database_year = DATABASE_VERSION_REGEXP.match(@database_version)[1].to_i rescue 0
|
209
|
+
initialize_native_database_types
|
201
210
|
initialize_sqlserver_caches
|
202
211
|
use_database
|
203
|
-
unless SUPPORTED_VERSIONS.include?(database_year)
|
212
|
+
unless SUPPORTED_VERSIONS.include?(@database_year)
|
204
213
|
raise NotImplementedError, "Currently, only #{SUPPORTED_VERSIONS.to_sentence} are supported."
|
205
214
|
end
|
206
215
|
end
|
@@ -223,28 +232,20 @@ module ActiveRecord
|
|
223
232
|
true
|
224
233
|
end
|
225
234
|
|
226
|
-
def database_version
|
227
|
-
@database_version ||= info_schema_query { select_value('SELECT @@version') }
|
228
|
-
end
|
229
|
-
|
230
|
-
def database_year
|
231
|
-
DATABASE_VERSION_REGEXP.match(database_version)[1].to_i
|
232
|
-
end
|
233
|
-
|
234
235
|
def sqlserver?
|
235
236
|
true
|
236
237
|
end
|
237
238
|
|
238
239
|
def sqlserver_2000?
|
239
|
-
database_year == 2000
|
240
|
+
@database_year == 2000
|
240
241
|
end
|
241
242
|
|
242
243
|
def sqlserver_2005?
|
243
|
-
database_year == 2005
|
244
|
+
@database_year == 2005
|
244
245
|
end
|
245
246
|
|
246
247
|
def sqlserver_2008?
|
247
|
-
database_year == 2008
|
248
|
+
@database_year == 2008
|
248
249
|
end
|
249
250
|
|
250
251
|
def version
|
@@ -252,7 +253,7 @@ module ActiveRecord
|
|
252
253
|
end
|
253
254
|
|
254
255
|
def inspect
|
255
|
-
"#<#{self.class} version: #{version}, year: #{database_year}, connection_options: #{@connection_options.inspect}>"
|
256
|
+
"#<#{self.class} version: #{version}, year: #{@database_year}, connection_options: #{@connection_options.inspect}>"
|
256
257
|
end
|
257
258
|
|
258
259
|
def auto_connect
|
@@ -306,21 +307,21 @@ module ActiveRecord
|
|
306
307
|
string.to_s.gsub(/\'/, "''")
|
307
308
|
end
|
308
309
|
|
309
|
-
def quote_column_name(
|
310
|
-
|
310
|
+
def quote_column_name(name)
|
311
|
+
@sqlserver_quoted_column_and_table_names[name] ||=
|
312
|
+
name.to_s.split('.').map{ |n| n =~ /^\[.*\]$/ ? n : "[#{n}]" }.join('.')
|
311
313
|
end
|
312
314
|
|
313
|
-
def quote_table_name(
|
314
|
-
|
315
|
-
quote_column_name(table_name)
|
315
|
+
def quote_table_name(name)
|
316
|
+
quote_column_name(name)
|
316
317
|
end
|
317
318
|
|
318
319
|
def quoted_true
|
319
|
-
|
320
|
+
QUOTED_TRUE
|
320
321
|
end
|
321
322
|
|
322
323
|
def quoted_false
|
323
|
-
|
324
|
+
QUOTED_FALSE
|
324
325
|
end
|
325
326
|
|
326
327
|
def quoted_date(value)
|
@@ -360,11 +361,11 @@ module ActiveRecord
|
|
360
361
|
end
|
361
362
|
|
362
363
|
def disconnect!
|
363
|
-
case
|
364
|
+
case @connection_options[:mode]
|
364
365
|
when :odbc
|
365
|
-
|
366
|
+
@connection.disconnect rescue nil
|
366
367
|
else :adonet
|
367
|
-
|
368
|
+
@connection.close rescue nil
|
368
369
|
end
|
369
370
|
end
|
370
371
|
|
@@ -394,8 +395,22 @@ module ActiveRecord
|
|
394
395
|
end if block_given?
|
395
396
|
end
|
396
397
|
|
398
|
+
def select_one(sql, name = nil)
|
399
|
+
result = raw_select sql, name, :fetch => :one
|
400
|
+
(result && result.first.present?) ? result.first : nil
|
401
|
+
end
|
402
|
+
|
403
|
+
def select_one_with_query_cache(*args)
|
404
|
+
if @query_cache_enabled
|
405
|
+
cache_sql(args.first) { select_one_without_query_cache(*args) }
|
406
|
+
else
|
407
|
+
select_one_without_query_cache(*args)
|
408
|
+
end
|
409
|
+
end
|
410
|
+
alias_method_chain :select_one, :query_cache
|
411
|
+
|
397
412
|
def select_rows(sql, name = nil)
|
398
|
-
raw_select
|
413
|
+
raw_select sql, name, :fetch => :rows
|
399
414
|
end
|
400
415
|
|
401
416
|
def execute(sql, name = nil, skip_logging = false)
|
@@ -409,13 +424,21 @@ module ActiveRecord
|
|
409
424
|
def execute_procedure(proc_name, *variables)
|
410
425
|
vars = variables.map{ |v| quote(v) }.join(', ')
|
411
426
|
sql = "EXEC #{proc_name} #{vars}".strip
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
427
|
+
results = []
|
428
|
+
log(sql,'Execute Procedure') do
|
429
|
+
raw_connection_run(sql) do |handle|
|
430
|
+
get_rows = lambda {
|
431
|
+
rows = handle_to_names_and_values handle, :fetch => :all
|
432
|
+
rows.each_with_index { |r,i| rows[i] = r.with_indifferent_access }
|
433
|
+
results << rows
|
434
|
+
}
|
435
|
+
get_rows.call
|
436
|
+
while handle_more_results?(handle)
|
437
|
+
get_rows.call
|
438
|
+
end
|
417
439
|
end
|
418
440
|
end
|
441
|
+
results.many? ? results : results.first
|
419
442
|
end
|
420
443
|
|
421
444
|
def use_database(database=nil)
|
@@ -537,30 +560,18 @@ module ActiveRecord
|
|
537
560
|
"WHERE #{quoted_primary_key} IN (SELECT #{limit} #{quoted_primary_key} FROM #{quoted_table_name} #{where_sql})"
|
538
561
|
end
|
539
562
|
|
563
|
+
def newid_function
|
564
|
+
select_value "SELECT NEWID()"
|
565
|
+
end
|
566
|
+
|
567
|
+
def newsequentialid_function
|
568
|
+
select_value "SELECT NEWSEQUENTIALID()"
|
569
|
+
end
|
570
|
+
|
540
571
|
# SCHEMA STATEMENTS ========================================#
|
541
572
|
|
542
573
|
def native_database_types
|
543
|
-
|
544
|
-
:primary_key => "int NOT NULL IDENTITY(1, 1) PRIMARY KEY",
|
545
|
-
:string => { :name => native_string_database_type, :limit => 255 },
|
546
|
-
:text => { :name => native_text_database_type },
|
547
|
-
:integer => { :name => "int", :limit => 4 },
|
548
|
-
:float => { :name => "float", :limit => 8 },
|
549
|
-
:decimal => { :name => "decimal" },
|
550
|
-
:datetime => { :name => "datetime" },
|
551
|
-
:timestamp => { :name => "datetime" },
|
552
|
-
:time => { :name => native_time_database_type },
|
553
|
-
:date => { :name => native_date_database_type },
|
554
|
-
:binary => { :name => native_binary_database_type },
|
555
|
-
:boolean => { :name => "bit"},
|
556
|
-
# These are custom types that may move somewhere else for good schema_dumper.rb hacking to output them.
|
557
|
-
:char => { :name => 'char' },
|
558
|
-
:varchar_max => { :name => 'varchar(max)' },
|
559
|
-
:nchar => { :name => "nchar" },
|
560
|
-
:nvarchar => { :name => "nvarchar", :limit => 255 },
|
561
|
-
:nvarchar_max => { :name => "nvarchar(max)" },
|
562
|
-
:ntext => { :name => "ntext" }
|
563
|
-
}
|
574
|
+
ActiveRecord::ConnectionAdapters::SQLServerAdapter::NATIVE_DATABASE_TYPES
|
564
575
|
end
|
565
576
|
|
566
577
|
def table_alias_length
|
@@ -583,8 +594,9 @@ module ActiveRecord
|
|
583
594
|
@sqlserver_view_information_cache[table_name] ||= begin
|
584
595
|
view_info = info_schema_query { select_one("SELECT * FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME = '#{table_name}'") }
|
585
596
|
if view_info
|
586
|
-
|
587
|
-
|
597
|
+
view_info = view_info.with_indifferent_access
|
598
|
+
if view_info[:VIEW_DEFINITION].blank? || view_info[:VIEW_DEFINITION].length == 4000
|
599
|
+
view_info[:VIEW_DEFINITION] = info_schema_query { select_values("EXEC sp_helptext #{table_name}").join }
|
588
600
|
end
|
589
601
|
end
|
590
602
|
view_info
|
@@ -603,12 +615,13 @@ module ActiveRecord
|
|
603
615
|
def indexes(table_name, name = nil)
|
604
616
|
unquoted_table_name = unqualify_table_name(table_name)
|
605
617
|
select("EXEC sp_helpindex #{quote_table_name(unquoted_table_name)}",name).inject([]) do |indexes,index|
|
606
|
-
|
618
|
+
index = index.with_indifferent_access
|
619
|
+
if index[:index_description] =~ /primary key/
|
607
620
|
indexes
|
608
621
|
else
|
609
|
-
name = index[
|
610
|
-
unique = index[
|
611
|
-
columns = index[
|
622
|
+
name = index[:index_name]
|
623
|
+
unique = index[:index_description] =~ /unique/
|
624
|
+
columns = index[:index_keys].split(',').map do |column|
|
612
625
|
column.strip!
|
613
626
|
column.gsub! '(-)', '' if column.ends_with?('(-)')
|
614
627
|
column
|
@@ -647,6 +660,7 @@ module ActiveRecord
|
|
647
660
|
end
|
648
661
|
|
649
662
|
def remove_column(table_name, *column_names)
|
663
|
+
raise ArgumentError.new("You must specify at least one column name. Example: remove_column(:people, :first_name)") if column_names.empty?
|
650
664
|
column_names.flatten.each do |column_name|
|
651
665
|
remove_check_constraints(table_name, column_name)
|
652
666
|
remove_default_constraint(table_name, column_name)
|
@@ -798,9 +812,23 @@ module ActiveRecord
|
|
798
812
|
|
799
813
|
def connect
|
800
814
|
config = @connection_options
|
801
|
-
@connection = case
|
815
|
+
@connection = case @connection_options[:mode]
|
802
816
|
when :odbc
|
803
|
-
|
817
|
+
if config[:dsn].include?(';')
|
818
|
+
driver = ODBC::Driver.new.tap do |d|
|
819
|
+
d.name = config[:dsn_name] || 'Driver1'
|
820
|
+
driver.attrs = dsn.split(';').map{ |atr| atr.split('=') }.reject{ |kv| kv.size != 2 }.inject({}){ |h,kv| k,v = kv ; h[k] = v ; h }
|
821
|
+
end
|
822
|
+
ODBC::Database.new.drvconnect(driver)
|
823
|
+
else
|
824
|
+
ODBC.connect config[:dsn], config[:username], config[:password]
|
825
|
+
end.tap do |c|
|
826
|
+
if c.respond_to?(:use_time)
|
827
|
+
c.use_time = true
|
828
|
+
c.use_utc = ActiveRecord::Base.default_timezone == :utc
|
829
|
+
@connection_supports_native_types = true
|
830
|
+
end
|
831
|
+
end
|
804
832
|
when :adonet
|
805
833
|
System::Data::SqlClient::SqlConnection.new.tap do |connection|
|
806
834
|
connection.connection_string = System::Data::SqlClient::SqlConnectionStringBuilder.new.tap do |cs|
|
@@ -822,17 +850,13 @@ module ActiveRecord
|
|
822
850
|
raise unless @auto_connecting
|
823
851
|
end
|
824
852
|
|
825
|
-
def connection_mode
|
826
|
-
@connection_options[:mode]
|
827
|
-
end
|
828
|
-
|
829
853
|
def lost_connection_exceptions
|
830
|
-
exceptions = LOST_CONNECTION_EXCEPTIONS[
|
854
|
+
exceptions = LOST_CONNECTION_EXCEPTIONS[@connection_options[:mode]]
|
831
855
|
@lost_connection_exceptions ||= exceptions ? exceptions.map(&:constantize) : []
|
832
856
|
end
|
833
857
|
|
834
858
|
def lost_connection_messages
|
835
|
-
LOST_CONNECTION_MESSAGES[
|
859
|
+
LOST_CONNECTION_MESSAGES[@connection_options[:mode]]
|
836
860
|
end
|
837
861
|
|
838
862
|
def with_auto_reconnect
|
@@ -864,26 +888,26 @@ module ActiveRecord
|
|
864
888
|
|
865
889
|
def raw_connection_run(sql)
|
866
890
|
with_auto_reconnect do
|
867
|
-
case
|
891
|
+
case @connection_options[:mode]
|
868
892
|
when :odbc
|
869
|
-
block_given? ?
|
893
|
+
block_given? ? @connection.run_block(sql) { |handle| yield(handle) } : @connection.run(sql)
|
870
894
|
else :adonet
|
871
|
-
|
895
|
+
@connection.create_command.tap{ |cmd| cmd.command_text = sql }.execute_reader
|
872
896
|
end
|
873
897
|
end
|
874
898
|
end
|
875
899
|
|
876
900
|
def raw_connection_do(sql)
|
877
|
-
case
|
901
|
+
case @connection_options[:mode]
|
878
902
|
when :odbc
|
879
|
-
|
903
|
+
@connection.do(sql)
|
880
904
|
else :adonet
|
881
|
-
|
905
|
+
@connection.create_command.tap{ |cmd| cmd.command_text = sql }.execute_non_query
|
882
906
|
end
|
883
907
|
end
|
884
908
|
|
885
909
|
def finish_statement_handle(handle)
|
886
|
-
case
|
910
|
+
case @connection_options[:mode]
|
887
911
|
when :odbc
|
888
912
|
handle.drop if handle && handle.respond_to?(:drop) && !handle.finished?
|
889
913
|
when :adonet
|
@@ -895,24 +919,8 @@ module ActiveRecord
|
|
895
919
|
|
896
920
|
# DATABASE STATEMENTS ======================================
|
897
921
|
|
898
|
-
def select(sql, name = nil
|
899
|
-
|
900
|
-
fields_and_row_sets = raw_select(sql,name)
|
901
|
-
final_result_set = fields_and_row_sets.inject([]) do |rs,fields_and_rows|
|
902
|
-
fields, rows = fields_and_rows
|
903
|
-
rs << zip_fields_and_rows(fields,rows)
|
904
|
-
end
|
905
|
-
final_result_set.many? ? final_result_set : final_result_set.first
|
906
|
-
end
|
907
|
-
|
908
|
-
def zip_fields_and_rows(fields, rows)
|
909
|
-
rows.inject([]) do |results,row|
|
910
|
-
row_hash = {}
|
911
|
-
fields.each_with_index do |f, i|
|
912
|
-
row_hash[f] = row[i]
|
913
|
-
end
|
914
|
-
results << row_hash
|
915
|
-
end
|
922
|
+
def select(sql, name = nil)
|
923
|
+
raw_select sql, name, :fetch => :all
|
916
924
|
end
|
917
925
|
|
918
926
|
def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
|
@@ -934,30 +942,19 @@ module ActiveRecord
|
|
934
942
|
end
|
935
943
|
end
|
936
944
|
|
937
|
-
def raw_select(sql, name =
|
938
|
-
fields_and_row_sets = []
|
945
|
+
def raw_select(sql, name=nil, options={})
|
939
946
|
log(sql,name) do
|
940
947
|
begin
|
941
948
|
handle = raw_connection_run(sql)
|
942
|
-
|
943
|
-
fields_and_rows = case connection_mode
|
944
|
-
when :odbc
|
945
|
-
handle_to_fields_and_rows_odbc(handle)
|
946
|
-
when :adonet
|
947
|
-
handle_to_fields_and_rows_adonet(handle)
|
948
|
-
end
|
949
|
-
fields_and_row_sets << fields_and_rows
|
950
|
-
break unless handle_more_results?(handle)
|
951
|
-
end
|
949
|
+
handle_to_names_and_values(handle, options)
|
952
950
|
ensure
|
953
951
|
finish_statement_handle(handle)
|
954
952
|
end
|
955
953
|
end
|
956
|
-
fields_and_row_sets
|
957
954
|
end
|
958
955
|
|
959
956
|
def handle_more_results?(handle)
|
960
|
-
case
|
957
|
+
case @connection_options[:mode]
|
961
958
|
when :odbc
|
962
959
|
handle.more_results
|
963
960
|
when :adonet
|
@@ -965,50 +962,109 @@ module ActiveRecord
|
|
965
962
|
end
|
966
963
|
end
|
967
964
|
|
968
|
-
def
|
969
|
-
|
970
|
-
|
971
|
-
|
965
|
+
def handle_to_names_and_values(handle, options={})
|
966
|
+
case @connection_options[:mode]
|
967
|
+
when :odbc
|
968
|
+
handle_to_names_and_values_odbc(handle, options)
|
969
|
+
when :adonet
|
970
|
+
handle_to_names_and_values_adonet(handle, options)
|
972
971
|
end
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
|
972
|
+
end
|
973
|
+
|
974
|
+
def handle_to_names_and_values_odbc(handle, options={})
|
975
|
+
@connection.use_utc = ActiveRecord::Base.default_timezone == :utc if @connection_supports_native_types
|
976
|
+
case options[:fetch]
|
977
|
+
when :all, :one
|
978
|
+
if @connection_supports_native_types
|
979
|
+
if options[:fetch] == :all
|
980
|
+
handle.each_hash || []
|
981
|
+
else
|
982
|
+
row = handle.fetch_hash
|
983
|
+
rows = row ? [row] : [[]]
|
984
|
+
end
|
985
|
+
else
|
986
|
+
rows = if options[:fetch] == :all
|
987
|
+
handle.fetch_all || []
|
988
|
+
else
|
989
|
+
row = handle.fetch
|
990
|
+
row ? [row] : [[]]
|
991
|
+
end
|
992
|
+
names = handle.columns(true).map{ |c| c.name }
|
993
|
+
names_and_values = []
|
994
|
+
rows.each do |row|
|
995
|
+
h = {}
|
996
|
+
i = 0
|
997
|
+
while i < row.size
|
998
|
+
v = row[i]
|
999
|
+
h[names[i]] = v.respond_to?(:to_sqlserver_string) ? v.to_sqlserver_string : v
|
1000
|
+
i += 1
|
1001
|
+
end
|
1002
|
+
names_and_values << h
|
1003
|
+
end
|
1004
|
+
names_and_values
|
1005
|
+
end
|
1006
|
+
when :rows
|
1007
|
+
rows = handle.fetch_all || []
|
1008
|
+
return rows if @connection_supports_native_types
|
1009
|
+
rows.each do |row|
|
1010
|
+
i = 0
|
1011
|
+
while i < row.size
|
1012
|
+
v = row[i]
|
1013
|
+
row[i] = v.to_sqlserver_string if v.respond_to?(:to_sqlserver_string)
|
1014
|
+
i += 1
|
977
1015
|
end
|
978
1016
|
end
|
979
|
-
rows
|
1017
|
+
rows
|
980
1018
|
end
|
981
|
-
[fields,rows]
|
982
1019
|
end
|
983
|
-
|
984
|
-
def
|
1020
|
+
|
1021
|
+
def handle_to_names_and_values_adonet(handle, options={})
|
985
1022
|
if handle.has_rows
|
986
|
-
|
1023
|
+
names = []
|
987
1024
|
rows = []
|
988
|
-
fields_named =
|
1025
|
+
fields_named = options[:fetch] == :rows
|
1026
|
+
one_row_only = options[:fetch] == :one
|
989
1027
|
while handle.read
|
990
1028
|
row = []
|
991
1029
|
handle.visible_field_count.times do |row_index|
|
992
1030
|
value = handle.get_value(row_index)
|
993
|
-
value =
|
1031
|
+
value = case value
|
1032
|
+
when System::String
|
994
1033
|
value.to_s
|
995
|
-
|
1034
|
+
when System::DBNull
|
996
1035
|
nil
|
997
|
-
|
998
|
-
value.to_string("yyyy-MM-dd HH:
|
1036
|
+
when System::DateTime
|
1037
|
+
value.to_string("yyyy-MM-dd HH:mm:ss.fff").to_s
|
1038
|
+
when @@array_of_bytes ||= System::Array[System::Byte]
|
1039
|
+
String.new(value)
|
999
1040
|
else
|
1000
1041
|
value
|
1001
1042
|
end
|
1002
1043
|
row << value
|
1003
|
-
|
1044
|
+
names << handle.get_name(row_index).to_s unless fields_named
|
1045
|
+
break if one_row_only
|
1004
1046
|
end
|
1005
1047
|
rows << row
|
1006
1048
|
fields_named = true
|
1007
1049
|
end
|
1008
1050
|
else
|
1009
|
-
|
1051
|
+
rows = []
|
1052
|
+
end
|
1053
|
+
if options[:fetch] != :rows
|
1054
|
+
names_and_values = []
|
1055
|
+
rows.each do |row|
|
1056
|
+
h = {}
|
1057
|
+
i = 0
|
1058
|
+
while i < row.size
|
1059
|
+
h[names[i]] = row[i]
|
1060
|
+
i += 1
|
1061
|
+
end
|
1062
|
+
names_and_values << h
|
1063
|
+
end
|
1064
|
+
names_and_values
|
1065
|
+
else
|
1066
|
+
rows
|
1010
1067
|
end
|
1011
|
-
[fields,rows]
|
1012
1068
|
end
|
1013
1069
|
|
1014
1070
|
def add_limit_offset_for_association_limiting!(sql, options)
|
@@ -1129,7 +1185,7 @@ module ActiveRecord
|
|
1129
1185
|
end
|
1130
1186
|
|
1131
1187
|
def views_real_column_name(table_name,column_name)
|
1132
|
-
view_definition = view_information(table_name)[
|
1188
|
+
view_definition = view_information(table_name)[:VIEW_DEFINITION]
|
1133
1189
|
match_data = view_definition.match(/([\w-]*)\s+as\s+#{column_name}/im)
|
1134
1190
|
match_data ? match_data[1] : column_name
|
1135
1191
|
end
|
@@ -1158,6 +1214,32 @@ module ActiveRecord
|
|
1158
1214
|
@sqlserver_columns_cache = {} if reset_columns
|
1159
1215
|
@sqlserver_views_cache = nil
|
1160
1216
|
@sqlserver_view_information_cache = {}
|
1217
|
+
@sqlserver_quoted_column_and_table_names = {}
|
1218
|
+
end
|
1219
|
+
|
1220
|
+
def initialize_native_database_types
|
1221
|
+
return if defined?(ActiveRecord::ConnectionAdapters::SQLServerAdapter::NATIVE_DATABASE_TYPES)
|
1222
|
+
ActiveRecord::ConnectionAdapters::SQLServerAdapter.const_set(:NATIVE_DATABASE_TYPES,{
|
1223
|
+
:primary_key => "int NOT NULL IDENTITY(1,1) PRIMARY KEY",
|
1224
|
+
:string => { :name => native_string_database_type, :limit => 255 },
|
1225
|
+
:text => { :name => native_text_database_type },
|
1226
|
+
:integer => { :name => "int", :limit => 4 },
|
1227
|
+
:float => { :name => "float", :limit => 8 },
|
1228
|
+
:decimal => { :name => "decimal" },
|
1229
|
+
:datetime => { :name => "datetime" },
|
1230
|
+
:timestamp => { :name => "datetime" },
|
1231
|
+
:time => { :name => native_time_database_type },
|
1232
|
+
:date => { :name => native_date_database_type },
|
1233
|
+
:binary => { :name => native_binary_database_type },
|
1234
|
+
:boolean => { :name => "bit"},
|
1235
|
+
# These are custom types that may move somewhere else for good schema_dumper.rb hacking to output them.
|
1236
|
+
:char => { :name => 'char' },
|
1237
|
+
:varchar_max => { :name => 'varchar(max)' },
|
1238
|
+
:nchar => { :name => "nchar" },
|
1239
|
+
:nvarchar => { :name => "nvarchar", :limit => 255 },
|
1240
|
+
:nvarchar_max => { :name => "nvarchar(max)" },
|
1241
|
+
:ntext => { :name => "ntext" }
|
1242
|
+
})
|
1161
1243
|
end
|
1162
1244
|
|
1163
1245
|
def column_definitions(table_name)
|
@@ -1179,7 +1261,7 @@ module ActiveRecord
|
|
1179
1261
|
CASE
|
1180
1262
|
WHEN columns.IS_NULLABLE = 'YES' THEN 1
|
1181
1263
|
ELSE NULL
|
1182
|
-
|
1264
|
+
END as is_nullable,
|
1183
1265
|
CASE
|
1184
1266
|
WHEN COLUMNPROPERTY(OBJECT_ID(columns.TABLE_SCHEMA+'.'+columns.TABLE_NAME), columns.COLUMN_NAME, 'IsIdentity') = 0 THEN NULL
|
1185
1267
|
ELSE 1
|
@@ -1188,9 +1270,9 @@ module ActiveRecord
|
|
1188
1270
|
WHERE columns.TABLE_NAME = '#{table_name}'
|
1189
1271
|
ORDER BY columns.ordinal_position
|
1190
1272
|
}.gsub(/[ \t\r\n]+/,' ')
|
1191
|
-
results = info_schema_query { select(sql,nil
|
1273
|
+
results = info_schema_query { select(sql,nil) }
|
1192
1274
|
results.collect do |ci|
|
1193
|
-
ci.symbolize_keys
|
1275
|
+
ci = ci.symbolize_keys
|
1194
1276
|
ci[:type] = case ci[:type]
|
1195
1277
|
when /^bit|image|text|ntext|datetime$/
|
1196
1278
|
ci[:type]
|
@@ -1210,6 +1292,9 @@ module ActiveRecord
|
|
1210
1292
|
ci[:default_value] = case ci[:default_value]
|
1211
1293
|
when nil, '(null)', '(NULL)'
|
1212
1294
|
nil
|
1295
|
+
when /\A\((\w+\(\))\)\Z/
|
1296
|
+
ci[:default_function] = $1
|
1297
|
+
nil
|
1213
1298
|
else
|
1214
1299
|
match_data = ci[:default_value].match(/\A\(+N?'?(.*?)'?\)+\Z/m)
|
1215
1300
|
match_data ? match_data[1] : nil
|
@@ -71,21 +71,6 @@ class AdapterTestSqlserver < ActiveRecord::TestCase
|
|
71
71
|
assert_contains @supported_version, @connection.database_year
|
72
72
|
end
|
73
73
|
|
74
|
-
should 'return true to #sqlserver_2000?' do
|
75
|
-
@connection.stubs(:database_version).returns(@sqlserver_2000_string)
|
76
|
-
assert @connection.sqlserver_2000?
|
77
|
-
end
|
78
|
-
|
79
|
-
should 'return true to #sqlserver_2005?' do
|
80
|
-
@connection.stubs(:database_version).returns(@sqlserver_2005_string)
|
81
|
-
assert @connection.sqlserver_2005?
|
82
|
-
end
|
83
|
-
|
84
|
-
should 'return true to #sqlserver_2008?' do
|
85
|
-
@connection.stubs(:database_version).returns(@sqlserver_2008_string)
|
86
|
-
assert @connection.sqlserver_2008?
|
87
|
-
end
|
88
|
-
|
89
74
|
end
|
90
75
|
|
91
76
|
context 'for #unqualify_table_name and #unqualify_db_name' do
|
@@ -303,13 +288,13 @@ class AdapterTestSqlserver < ActiveRecord::TestCase
|
|
303
288
|
|
304
289
|
should 'find 003 millisecond in the DB with before and after casting' do
|
305
290
|
existing_003 = SqlServerChronic.find_by_datetime!(@db_datetime_003)
|
306
|
-
assert_equal @db_datetime_003, existing_003.datetime_before_type_cast
|
291
|
+
assert_equal @db_datetime_003, existing_003.datetime_before_type_cast if existing_003.datetime_before_type_cast.is_a?(String)
|
307
292
|
assert_equal 3000, existing_003.datetime.usec, 'A 003 millisecond in SQL Server is 3000 microseconds'
|
308
293
|
end
|
309
294
|
|
310
295
|
should 'find 123 millisecond in the DB with before and after casting' do
|
311
296
|
existing_123 = SqlServerChronic.find_by_datetime!(@db_datetime_123)
|
312
|
-
assert_equal @db_datetime_123, existing_123.datetime_before_type_cast
|
297
|
+
assert_equal @db_datetime_123, existing_123.datetime_before_type_cast if existing_123.datetime_before_type_cast.is_a?(String)
|
313
298
|
assert_equal 123000, existing_123.datetime.usec, 'A 123 millisecond in SQL Server is 123000 microseconds'
|
314
299
|
end
|
315
300
|
|
@@ -320,14 +305,14 @@ class AdapterTestSqlserver < ActiveRecord::TestCase
|
|
320
305
|
should 'truncate 123456 usec to just 123 in the DB cast back to 123000' do
|
321
306
|
@time.stubs(:usec).returns(123456)
|
322
307
|
saved = SqlServerChronic.create!(:datetime => @time).reload
|
323
|
-
assert_equal '123', saved.datetime_before_type_cast.split('.')[1]
|
308
|
+
assert_equal '123', saved.datetime_before_type_cast.split('.')[1] if saved.datetime_before_type_cast.is_a?(String)
|
324
309
|
assert_equal 123000, saved.datetime.usec
|
325
310
|
end
|
326
311
|
|
327
312
|
should 'truncate 3001 usec to just 003 in the DB cast back to 3000' do
|
328
313
|
@time.stubs(:usec).returns(3001)
|
329
314
|
saved = SqlServerChronic.create!(:datetime => @time).reload
|
330
|
-
assert_equal '003', saved.datetime_before_type_cast.split('.')[1]
|
315
|
+
assert_equal '003', saved.datetime_before_type_cast.split('.')[1] if saved.datetime_before_type_cast.is_a?(String)
|
331
316
|
assert_equal 3000, saved.datetime.usec
|
332
317
|
end
|
333
318
|
|
@@ -14,7 +14,9 @@ class BasicsTest < ActiveRecord::TestCase
|
|
14
14
|
|
15
15
|
def test_coerced_test_read_attributes_before_type_cast_on_datetime
|
16
16
|
developer = Developer.find(:first)
|
17
|
-
|
17
|
+
if developer.created_at_before_type_cast.is_a?(String)
|
18
|
+
assert_equal developer.created_at.to_s(:db)+'.000' , developer.attributes_before_type_cast["created_at"]
|
19
|
+
end
|
18
20
|
end
|
19
21
|
|
20
22
|
|
@@ -20,15 +20,6 @@ class ExecuteProcedureTestSqlserver < ActiveRecord::TestCase
|
|
20
20
|
assert_equal 'TABLE', table_info[:TABLE_TYPE], "Table Info: #{table_info.inspect}"
|
21
21
|
end
|
22
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? || sqlserver_2008?
|
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
23
|
should 'allow multiple result sets to be returned' do
|
33
24
|
results1, results2 = @klass.execute_procedure('sp_helpconstraint','accounts')
|
34
25
|
assert_instance_of Array, results1
|
@@ -84,40 +84,3 @@ class MigrationTest < ActiveRecord::TestCase
|
|
84
84
|
|
85
85
|
end
|
86
86
|
|
87
|
-
class ChangeTableMigrationsTest < ActiveRecord::TestCase
|
88
|
-
|
89
|
-
COERCED_TESTS = [:test_string_creates_string_column]
|
90
|
-
|
91
|
-
include SqlserverCoercedTest
|
92
|
-
|
93
|
-
def setup
|
94
|
-
@connection = Person.connection
|
95
|
-
@connection.create_table :delete_me, :force => true do |t|
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
def teardown
|
100
|
-
@connection.drop_table :delete_me rescue nil
|
101
|
-
end
|
102
|
-
|
103
|
-
def test_coerced_string_creates_string_column
|
104
|
-
with_sqlserver_change_table do |t|
|
105
|
-
@connection.expects(:add_column).with(:delete_me, :foo, sqlserver_string_column, {})
|
106
|
-
@connection.expects(:add_column).with(:delete_me, :bar, sqlserver_string_column, {})
|
107
|
-
t.string :foo, :bar
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
protected
|
112
|
-
|
113
|
-
def with_sqlserver_change_table
|
114
|
-
@connection.change_table :delete_me do |t|
|
115
|
-
yield t
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
def sqlserver_string_column
|
120
|
-
"#{@connection.native_string_database_type}(255)"
|
121
|
-
end
|
122
|
-
|
123
|
-
end
|
@@ -1,7 +1,15 @@
|
|
1
1
|
require 'cases/sqlserver_helper'
|
2
2
|
|
3
3
|
class StringDefault < ActiveRecord::Base; end;
|
4
|
-
class SqlServerEdgeSchema < ActiveRecord::Base
|
4
|
+
class SqlServerEdgeSchema < ActiveRecord::Base
|
5
|
+
attr_accessor :new_id_setting
|
6
|
+
before_create :set_new_id
|
7
|
+
protected
|
8
|
+
def set_new_id
|
9
|
+
self[:guid_newid] ||= connection.newid_function if new_id_setting
|
10
|
+
true
|
11
|
+
end
|
12
|
+
end
|
5
13
|
|
6
14
|
class SpecificSchemaTestSqlserver < ActiveRecord::TestCase
|
7
15
|
|
@@ -91,7 +99,47 @@ class SpecificSchemaTestSqlserver < ActiveRecord::TestCase
|
|
91
99
|
|
92
100
|
end
|
93
101
|
|
102
|
+
context 'with uniqueidentifier column' do
|
103
|
+
|
104
|
+
setup do
|
105
|
+
@newid = ActiveRecord::Base.connection.newid_function
|
106
|
+
assert_guid @newid
|
107
|
+
end
|
108
|
+
|
109
|
+
should 'allow a simple insert and read of a column without a default function' do
|
110
|
+
obj = @edge_class.create! :guid => @newid
|
111
|
+
assert_equal @newid, @edge_class.find(obj.id).guid
|
112
|
+
end
|
113
|
+
|
114
|
+
should 'record the default function name in the column definition but still show a nil real default, will use one day for insert/update' do
|
115
|
+
newid_column = @edge_class.columns_hash['guid_newid']
|
116
|
+
assert newid_column.default_function.present?
|
117
|
+
assert_nil newid_column.default
|
118
|
+
assert_equal 'newid()', newid_column.default_function
|
119
|
+
unless ActiveRecord::Base.connection.sqlserver_2000?
|
120
|
+
newseqid_column = @edge_class.columns_hash['guid_newseqid']
|
121
|
+
assert newseqid_column.default_function.present?
|
122
|
+
assert_nil newseqid_column.default
|
123
|
+
assert_equal 'newsequentialid()', newseqid_column.default_function
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
should 'use model callback to set get a new guid' do
|
128
|
+
obj = @edge_class.new
|
129
|
+
obj.new_id_setting = true
|
130
|
+
obj.save!
|
131
|
+
assert_guid obj.guid_newid
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
|
94
136
|
end
|
95
137
|
|
96
138
|
|
139
|
+
protected
|
140
|
+
|
141
|
+
def assert_guid(guid)
|
142
|
+
assert_match %r|\w{8}-\w{4}-\w{4}-\w{4}-\w{12}|, guid
|
143
|
+
end
|
144
|
+
|
97
145
|
end
|
@@ -1,20 +1,26 @@
|
|
1
|
+
|
2
|
+
SQLSERVER_TEST_ROOT = File.expand_path(File.join(File.dirname(__FILE__),'..'))
|
3
|
+
SQLSERVER_ASSETS_ROOT = File.expand_path(File.join(SQLSERVER_TEST_ROOT,'assets'))
|
4
|
+
SQLSERVER_FIXTURES_ROOT = File.expand_path(File.join(SQLSERVER_TEST_ROOT,'fixtures'))
|
5
|
+
SQLSERVER_MIGRATIONS_ROOT = File.expand_path(File.join(SQLSERVER_TEST_ROOT,'migrations'))
|
6
|
+
SQLSERVER_SCHEMA_ROOT = File.expand_path(File.join(SQLSERVER_TEST_ROOT,'schema'))
|
7
|
+
ACTIVERECORD_TEST_ROOT = File.expand_path(File.join(ENV['RAILS_SOURCE'],'activerecord','test'))
|
8
|
+
|
1
9
|
require 'rubygems'
|
10
|
+
require 'bundler'
|
11
|
+
Bundler.setup
|
2
12
|
require 'shoulda'
|
3
13
|
require 'mocha'
|
14
|
+
begin ; require 'ruby-debug' ; rescue LoadError ; end
|
4
15
|
[ File.expand_path(File.join(File.dirname(__FILE__),'..','..','test')),
|
5
16
|
File.expand_path(File.join(File.dirname(__FILE__),'..','..','test','connections','native_sqlserver_odbc')),
|
6
|
-
File.expand_path(File.join(
|
17
|
+
File.expand_path(File.join(ENV['RAILS_SOURCE'],'activerecord','test'))
|
7
18
|
].each{ |lib| $:.unshift(lib) unless $:.include?(lib) } if ENV['TM_DIRECTORY']
|
8
19
|
require 'cases/helper'
|
9
20
|
require 'models/topic'
|
10
21
|
require 'active_record/version'
|
11
22
|
|
12
|
-
|
13
|
-
SQLSERVER_ASSETS_ROOT = SQLSERVER_TEST_ROOT + "/assets"
|
14
|
-
SQLSERVER_FIXTURES_ROOT = SQLSERVER_TEST_ROOT + "/fixtures"
|
15
|
-
SQLSERVER_MIGRATIONS_ROOT = SQLSERVER_TEST_ROOT + "/migrations"
|
16
|
-
SQLSERVER_SCHEMA_ROOT = SQLSERVER_TEST_ROOT + "/schema"
|
17
|
-
ACTIVERECORD_TEST_ROOT = File.expand_path(SQLSERVER_TEST_ROOT + "/../../../../rails/activerecord/test/")
|
23
|
+
GC.copy_on_write_friendly = true if GC.respond_to?(:copy_on_write_friendly?)
|
18
24
|
|
19
25
|
ActiveRecord::Migration.verbose = false
|
20
26
|
|
@@ -63,7 +69,7 @@ end
|
|
63
69
|
|
64
70
|
# Set weather to test unicode string defaults or not. Used from rake task.
|
65
71
|
|
66
|
-
if ENV['ENABLE_DEFAULT_UNICODE_TYPES']
|
72
|
+
if ENV['ENABLE_DEFAULT_UNICODE_TYPES'] != 'false'
|
67
73
|
puts "With enabled unicode string types"
|
68
74
|
ActiveRecord::ConnectionAdapters::SQLServerAdapter.enable_default_unicode_types = true
|
69
75
|
end
|
@@ -87,10 +93,10 @@ ActiveRecord::Base.connection.class.class_eval do
|
|
87
93
|
end
|
88
94
|
|
89
95
|
ActiveRecord::ConnectionAdapters::SQLServerAdapter.class_eval do
|
90
|
-
def raw_select_with_query_record(sql, name =
|
96
|
+
def raw_select_with_query_record(sql, name=nil, options={})
|
91
97
|
$queries_executed ||= []
|
92
98
|
$queries_executed << sql unless IGNORED_SQL.any? { |r| sql =~ r }
|
93
|
-
raw_select_without_query_record(sql,name)
|
99
|
+
raw_select_without_query_record(sql,name,options)
|
94
100
|
end
|
95
101
|
alias_method_chain :raw_select, :query_record
|
96
102
|
end
|
@@ -98,6 +104,7 @@ end
|
|
98
104
|
module ActiveRecord
|
99
105
|
class TestCase < ActiveSupport::TestCase
|
100
106
|
class << self
|
107
|
+
def connection_mode_odbc? ; ActiveRecord::Base.connection.instance_variable_get(:@connection_options)[:mode] == :odbc ; end
|
101
108
|
def sqlserver_2000? ; ActiveRecord::Base.connection.sqlserver_2000? ; end
|
102
109
|
def sqlserver_2005? ; ActiveRecord::Base.connection.sqlserver_2005? ; end
|
103
110
|
def sqlserver_2008? ; ActiveRecord::Base.connection.sqlserver_2008? ; end
|
@@ -67,7 +67,10 @@ ActiveRecord::Schema.define do
|
|
67
67
|
t.string :description
|
68
68
|
t.column :bigint, :bigint
|
69
69
|
t.column :tinyint, :tinyint
|
70
|
+
t.column :guid, :uniqueidentifier
|
70
71
|
end
|
72
|
+
execute %|ALTER TABLE [sql_server_edge_schemas] ADD [guid_newid] uniqueidentifier DEFAULT NEWID();|
|
73
|
+
execute %|ALTER TABLE [sql_server_edge_schemas] ADD [guid_newseqid] uniqueidentifier DEFAULT NEWSEQUENTIALID();| unless ActiveRecord::Base.connection.sqlserver_2000?
|
71
74
|
|
72
75
|
execute "IF EXISTS (SELECT TABLE_NAME FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME = 'customers_view') DROP VIEW customers_view"
|
73
76
|
execute <<-CUSTOMERSVIEW
|
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-sqlserver-adapter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
hash: 17
|
4
5
|
prerelease: false
|
5
6
|
segments:
|
6
7
|
- 2
|
7
8
|
- 3
|
8
|
-
-
|
9
|
-
version: 2.3.
|
9
|
+
- 9
|
10
|
+
version: 2.3.9
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Ken Collins
|
@@ -18,10 +19,24 @@ autorequire:
|
|
18
19
|
bindir: bin
|
19
20
|
cert_chain: []
|
20
21
|
|
21
|
-
date: 2010-
|
22
|
+
date: 2010-09-15 00:00:00 -04:00
|
22
23
|
default_executable:
|
23
|
-
dependencies:
|
24
|
-
|
24
|
+
dependencies:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: activerecord
|
27
|
+
prerelease: false
|
28
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
hash: 5
|
34
|
+
segments:
|
35
|
+
- 2
|
36
|
+
- 3
|
37
|
+
version: "2.3"
|
38
|
+
type: :runtime
|
39
|
+
version_requirements: *id001
|
25
40
|
description: SQL Server 2000, 2005 and 2008 Adapter For Rails.
|
26
41
|
email: ken@metaskills.net
|
27
42
|
executables: []
|
@@ -36,13 +51,37 @@ files:
|
|
36
51
|
- Rakefile
|
37
52
|
- README.rdoc
|
38
53
|
- RUNNING_UNIT_TESTS
|
39
|
-
- autotest/discover.rb
|
40
|
-
- autotest/railssqlserver.rb
|
41
|
-
- autotest/sqlserver.rb
|
42
54
|
- lib/activerecord-sqlserver-adapter.rb
|
43
55
|
- lib/active_record/connection_adapters/sqlserver_adapter.rb
|
44
56
|
- lib/active_record/connection_adapters/sqlserver_adapter/core_ext/active_record.rb
|
45
57
|
- lib/active_record/connection_adapters/sqlserver_adapter/core_ext/odbc.rb
|
58
|
+
- test/cases/aaaa_create_tables_test_sqlserver.rb
|
59
|
+
- test/cases/adapter_test_sqlserver.rb
|
60
|
+
- test/cases/attribute_methods_test_sqlserver.rb
|
61
|
+
- test/cases/basics_test_sqlserver.rb
|
62
|
+
- test/cases/calculations_test_sqlserver.rb
|
63
|
+
- test/cases/column_test_sqlserver.rb
|
64
|
+
- test/cases/connection_test_sqlserver.rb
|
65
|
+
- test/cases/eager_association_test_sqlserver.rb
|
66
|
+
- test/cases/execute_procedure_test_sqlserver.rb
|
67
|
+
- test/cases/inheritance_test_sqlserver.rb
|
68
|
+
- test/cases/method_scoping_test_sqlserver.rb
|
69
|
+
- test/cases/migration_test_sqlserver.rb
|
70
|
+
- test/cases/named_scope_test_sqlserver.rb
|
71
|
+
- test/cases/offset_and_limit_test_sqlserver.rb
|
72
|
+
- test/cases/pessimistic_locking_test_sqlserver.rb
|
73
|
+
- test/cases/query_cache_test_sqlserver.rb
|
74
|
+
- test/cases/schema_dumper_test_sqlserver.rb
|
75
|
+
- test/cases/specific_schema_test_sqlserver.rb
|
76
|
+
- test/cases/sqlserver_helper.rb
|
77
|
+
- test/cases/table_name_test_sqlserver.rb
|
78
|
+
- test/cases/transaction_test_sqlserver.rb
|
79
|
+
- test/cases/unicode_test_sqlserver.rb
|
80
|
+
- test/cases/validations_test_sqlserver.rb
|
81
|
+
- test/connections/native_sqlserver/connection.rb
|
82
|
+
- test/connections/native_sqlserver_odbc/connection.rb
|
83
|
+
- test/migrations/transaction_table/1_table_will_never_be_created.rb
|
84
|
+
- test/schema/sqlserver_specific_schema.rb
|
46
85
|
has_rdoc: true
|
47
86
|
homepage: http://github.com/rails-sqlserver
|
48
87
|
licenses: []
|
@@ -56,23 +95,27 @@ rdoc_options:
|
|
56
95
|
require_paths:
|
57
96
|
- lib
|
58
97
|
required_ruby_version: !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
59
99
|
requirements:
|
60
100
|
- - ">="
|
61
101
|
- !ruby/object:Gem::Version
|
102
|
+
hash: 3
|
62
103
|
segments:
|
63
104
|
- 0
|
64
105
|
version: "0"
|
65
106
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
107
|
+
none: false
|
66
108
|
requirements:
|
67
109
|
- - ">="
|
68
110
|
- !ruby/object:Gem::Version
|
111
|
+
hash: 3
|
69
112
|
segments:
|
70
113
|
- 0
|
71
114
|
version: "0"
|
72
115
|
requirements: []
|
73
116
|
|
74
117
|
rubyforge_project:
|
75
|
-
rubygems_version: 1.3.
|
118
|
+
rubygems_version: 1.3.7
|
76
119
|
signing_key:
|
77
120
|
specification_version: 3
|
78
121
|
summary: SQL Server 2000, 2005 and 2008 Adapter For Rails.
|
data/autotest/discover.rb
DELETED
data/autotest/railssqlserver.rb
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
require 'autotest/sqlserver'
|
2
|
-
|
3
|
-
class Autotest::Railssqlserver < Autotest::Sqlserver
|
4
|
-
|
5
|
-
def initialize
|
6
|
-
super
|
7
|
-
self.libs << "#{File::PATH_SEPARATOR}../../../rails/activerecord/test/"
|
8
|
-
self.extra_files = ['../../../rails/activerecord/test/']
|
9
|
-
self.add_mapping %r%../../../rails/activerecord/test/.*/.*_test.rb$% do |filename, _|
|
10
|
-
filename
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
|
15
|
-
end
|
16
|
-
|
data/autotest/sqlserver.rb
DELETED
@@ -1,54 +0,0 @@
|
|
1
|
-
require 'autotest'
|
2
|
-
require 'active_support'
|
3
|
-
|
4
|
-
class Autotest::Sqlserver < Autotest
|
5
|
-
|
6
|
-
def initialize
|
7
|
-
super
|
8
|
-
|
9
|
-
odbc_mode = true
|
10
|
-
|
11
|
-
clear_mappings
|
12
|
-
|
13
|
-
self.libs = [
|
14
|
-
"lib",
|
15
|
-
"test",
|
16
|
-
"test/connections/native_sqlserver#{odbc_mode ? '_odbc' : ''}",
|
17
|
-
"../../../rails/activerecord/test/"
|
18
|
-
].join(File::PATH_SEPARATOR)
|
19
|
-
|
20
|
-
@test_sqlserver_file_match = %r%^test/cases/.*_test_sqlserver\.rb$%
|
21
|
-
|
22
|
-
add_exception %r%^\./(?:autotest)%
|
23
|
-
add_exception %r%^\./(.*LICENSE|debug.log|README.*|CHANGELOG.*)$%i
|
24
|
-
|
25
|
-
# Any *_test_sqlserver file saved runs that file
|
26
|
-
self.add_mapping @test_sqlserver_file_match do |filename, matchs|
|
27
|
-
filename
|
28
|
-
end
|
29
|
-
|
30
|
-
# If any the adapter changes
|
31
|
-
# the test directory, ofcourse having _test.rb at the end, will run that test.
|
32
|
-
self.add_mapping(%r%^lib/(.*)\.rb$%) do |filename, matchs|
|
33
|
-
files_matching @test_sqlserver_file_match
|
34
|
-
end
|
35
|
-
|
36
|
-
# If any core file like the test helper, connections, fixtures, migratinos,
|
37
|
-
# and other support files, then run all matching *_test_sqlserver files.
|
38
|
-
add_mapping %r%^test/(cases/(sqlserver_helper)\.rb|connections|fixtures|migrations|schema/.*)% do
|
39
|
-
files_matching @test_sqlserver_file_match
|
40
|
-
end
|
41
|
-
|
42
|
-
end
|
43
|
-
|
44
|
-
# Have to use a custom reorder method since the normal :alpha for Autotest would put the
|
45
|
-
# files with ../ in the path before others.
|
46
|
-
def reorder(files_to_test)
|
47
|
-
ar_tests, sqlsvr_tests = files_to_test.partition { |k,v| k.starts_with?('../../../') }
|
48
|
-
ar_tests.sort! { |a,b| a[0] <=> b[0] }
|
49
|
-
sqlsvr_tests.sort! { |a,b| a[0] <=> b[0] }
|
50
|
-
sqlsvr_tests + ar_tests
|
51
|
-
end
|
52
|
-
|
53
|
-
end
|
54
|
-
|