activerecord-sqlserver-adapter 2.3.8 → 2.3.9
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 +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
|
-
|