activerecord-sqlserver-adapter 2.3.4 → 2.3.5
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +23 -0
- data/README.rdoc +16 -2
- data/RUNNING_UNIT_TESTS +4 -3
- data/Rakefile +23 -23
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +151 -60
- data/lib/active_record/connection_adapters/sqlserver_adapter/core_ext/odbc.rb +0 -1
- data/test/cases/connection_test_sqlserver.rb +3 -9
- data/test/cases/execute_procedure_test_sqlserver.rb +11 -0
- data/test/cases/migration_test_sqlserver.rb +13 -1
- data/test/cases/sqlserver_helper.rb +4 -0
- data/test/connections/native_sqlserver/connection.rb +3 -1
- data/test/connections/native_sqlserver_odbc/connection.rb +1 -1
- metadata +11 -4
data/CHANGELOG
CHANGED
@@ -2,6 +2,29 @@
|
|
2
2
|
MASTER
|
3
3
|
|
4
4
|
|
5
|
+
* 2.3.5
|
6
|
+
|
7
|
+
* Initial IronRuby ADONET connection mode support baked right in. Removed most &block
|
8
|
+
parameters, no handle/request object yielded anymore. Better abstraction and compliance
|
9
|
+
per the ActiveRecord abstract adapter to not yielding handles for #execute and only for
|
10
|
+
low level #select. Better wrapping of all queries at lowest level in #log so exceptions
|
11
|
+
at anytime can be handled correctly by core AR. Critical for System::Data's command
|
12
|
+
readers. Better abstraction for introspecting on #connection_mode. Added support for
|
13
|
+
running singular test cases via TextMate's Command-R. [Ken Collins]
|
14
|
+
|
15
|
+
* Force a binary encoding on values coming in and out of those columns for ruby 1.9.
|
16
|
+
Fixes ticket #33 [Jeroen Zwartepoorte]
|
17
|
+
|
18
|
+
* Using change_column will leave default if the type does not change or a new default
|
19
|
+
is not included. Fixes issue #22. [Ransom Briggs]
|
20
|
+
|
21
|
+
* Use correct SP name for sp_MSforeachtable so any collation can get to it. [7to3]
|
22
|
+
|
23
|
+
* Qualify INFORMATION_SCHEMA.COLUMNS with a correct period DB name if present.
|
24
|
+
|
25
|
+
* Allow adapter to return multipe results sets, for example from stored procedures. [Chris Hall]
|
26
|
+
|
27
|
+
|
5
28
|
* 2.3.4
|
6
29
|
|
7
30
|
* For tables that named with schema(ex. rails.users), they could not get length of column.
|
data/README.rdoc
CHANGED
@@ -6,7 +6,8 @@ The SQL Server adapter for rails is back for ActiveRecord 2.2 and up! We are cur
|
|
6
6
|
|
7
7
|
== What's New
|
8
8
|
|
9
|
-
*
|
9
|
+
* IronRuby support using ADONET connection mode.
|
10
|
+
* Direct ODBC mode. No DBI anymore, means around 20% faster!
|
10
11
|
* Now supports SQL Server 2008 too!
|
11
12
|
* Fully tested under 1.9!!! Correctly encodes/decodes UTF-8 types in ruby 1.9 too.
|
12
13
|
* Now supports both rails 2.2 & 2.3!!!
|
@@ -129,7 +130,7 @@ It is our goal to match the adapter version with each version of rails. However
|
|
129
130
|
|
130
131
|
== Installation
|
131
132
|
|
132
|
-
You will need Ruby ODBC. If you are using the adapter under 1.9, then you need at least ruby-odbc version 0.9996.
|
133
|
+
You will need Ruby ODBC. If you are using the adapter under 1.9, then you need at least ruby-odbc version 0.9996. ODBC is the preferred mode, however if you are using IronRuby you can use the ADONET connection mode which uses native System.Data connection. Other connection modes may be supported, possibly a straight FreeTDS layer. The sky is the limit now and we have a code that can be accept these optional transports. If you are interested in helping, open a ticket and submit a patch. Or start a conversation on the Google Group.
|
133
134
|
|
134
135
|
$ gem install activerecord-sqlserver-adapter
|
135
136
|
|
@@ -142,6 +143,19 @@ Here are some external links for libraries and/or tutorials on how to install an
|
|
142
143
|
* http://www.ch-werner.de/rubyodbc/
|
143
144
|
|
144
145
|
|
146
|
+
== IronRuby ADONET Mode
|
147
|
+
|
148
|
+
A few details on this implementation. All that is needed in your database.yml configuration file is "mode: adonet" vs "odbc" and if you are running IronRuby, the connection will be native. You can also specify an "integrated_security: true" option in your configuration, remember to remove the username/password options too. To use this adapter, you will not need need ANY DBI middle layer or special extension gems to the adapter.
|
149
|
+
|
150
|
+
This adapter is opinionated in regards to IronRuby on types going in and out of the DB. For example strings will be String, not System::String and DateTime vs System::Datetime. There are many more examples but the rule of thumb is that the types will be simple types that correlate to a standard Ruby implementation. We enforce this basic rule because it is necessary to pass the tests and let the framework do its job. We recommend sticking to native Ruby types in your application code too.
|
151
|
+
|
152
|
+
The adapter establishes a System::Data::SqlClient connection that has both MultipleActiveResultSets (MARS) and Pooling turned off. There are good reasons for this one because the connection would not work otherwise for all the code issued by ActiveRecord. Remember too that ActiveRecord has it's own connection pooling and these underlying features like MARS/Pooling work against the adapter code.
|
153
|
+
|
154
|
+
Currently IronRuby is passing most of the ActiveRecord and Adapter tests. Here is a list of the ones remaining. Some are in the adapter's realm and some are in Marshaling area of IronRuby's core to fix. Feel like helping knock these out? Submit a patch to github issues.
|
155
|
+
|
156
|
+
http://gist.github.com/381101
|
157
|
+
|
158
|
+
|
145
159
|
== Contributing
|
146
160
|
|
147
161
|
If you’d like to contribute a feature or bugfix, thanks! To make sure your fix/feature has a high chance of being added, please read the following guidelines. First, ask on the Google list, IRC, or post a ticket on github issues. Second, make sure there are tests! We will not accept any patch that is not tested. Please read the RUNNING_UNIT_TESTS file for the details of how to run the unit tests.
|
data/RUNNING_UNIT_TESTS
CHANGED
@@ -34,9 +34,10 @@ test databases. Use an empty password for said user.
|
|
34
34
|
|
35
35
|
== Running with Rake
|
36
36
|
|
37
|
-
The easiest way to run the unit tests is through Rake. Either run "rake
|
38
|
-
|
39
|
-
|
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"
|
40
41
|
|
41
42
|
Rake can be found at http://rake.rubyforge.org
|
42
43
|
|
data/Rakefile
CHANGED
@@ -4,38 +4,38 @@ require 'rake/rdoctask'
|
|
4
4
|
|
5
5
|
|
6
6
|
namespace :sqlserver do
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
7
|
+
|
8
|
+
namespace :test do
|
9
|
+
|
10
|
+
['odbc','adonet'].each do |mode|
|
11
|
+
|
12
|
+
Rake::TestTask.new(mode) do |t|
|
13
|
+
t.libs << "test"
|
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
|
+
|
18
22
|
end
|
19
23
|
|
20
|
-
|
21
|
-
|
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
|
22
29
|
end
|
23
|
-
|
24
|
-
end
|
25
|
-
|
26
|
-
desc 'Test with unicode types enabled.'
|
27
|
-
task :test_unicode_types do
|
28
|
-
ENV['ENABLE_DEFAULT_UNICODE_TYPES'] = 'true'
|
29
|
-
test = Rake::Task['sqlserver:test_sqlserver_odbc']
|
30
|
-
test.invoke
|
30
|
+
|
31
31
|
end
|
32
32
|
|
33
33
|
end
|
34
34
|
|
35
35
|
|
36
|
-
desc '
|
36
|
+
desc 'Default runs tests for the adapters ODBC mode.'
|
37
37
|
task :test do
|
38
|
-
test = Rake::Task['sqlserver:
|
38
|
+
test = Rake::Task['sqlserver:test:odbc']
|
39
39
|
test.invoke
|
40
40
|
end
|
41
41
|
|
@@ -16,7 +16,9 @@ module ActiveRecord
|
|
16
16
|
require_library_or_gem 'odbc' unless defined?(ODBC)
|
17
17
|
require 'active_record/connection_adapters/sqlserver_adapter/core_ext/odbc'
|
18
18
|
raise ArgumentError, 'Missing :dsn configuration.' unless config.has_key?(:dsn)
|
19
|
-
|
19
|
+
when :adonet
|
20
|
+
require 'System.Data'
|
21
|
+
raise ArgumentError, 'Missing :database configuration.' unless config.has_key?(:database)
|
20
22
|
when :ado
|
21
23
|
raise NotImplementedError, 'Please use version 2.3.1 of the adapter for ADO connections. Future versions may support ADO.NET.'
|
22
24
|
raise ArgumentError, 'Missing :database configuration.' unless config.has_key?(:database)
|
@@ -54,10 +56,12 @@ module ActiveRecord
|
|
54
56
|
end
|
55
57
|
|
56
58
|
def string_to_binary(value)
|
59
|
+
value = value.dup.force_encoding(Encoding::BINARY) if value.respond_to?(:force_encoding)
|
57
60
|
"0x#{value.unpack("H*")[0]}"
|
58
61
|
end
|
59
62
|
|
60
63
|
def binary_to_string(value)
|
64
|
+
value = value.dup.force_encoding(Encoding::BINARY) if value.respond_to?(:force_encoding)
|
61
65
|
value =~ /[^[:xdigit:]]/ ? value : [value].pack('H*')
|
62
66
|
end
|
63
67
|
|
@@ -159,17 +163,17 @@ module ActiveRecord
|
|
159
163
|
class SQLServerAdapter < AbstractAdapter
|
160
164
|
|
161
165
|
ADAPTER_NAME = 'SQLServer'.freeze
|
162
|
-
VERSION = '2.3.
|
166
|
+
VERSION = '2.3.5'.freeze
|
163
167
|
DATABASE_VERSION_REGEXP = /Microsoft SQL Server\s+(\d{4})/
|
164
168
|
SUPPORTED_VERSIONS = [2000,2005,2008].freeze
|
165
169
|
LIMITABLE_TYPES = ['string','integer','float','char','nchar','varchar','nvarchar'].freeze
|
166
170
|
LOST_CONNECTION_EXCEPTIONS = {
|
167
|
-
:odbc
|
168
|
-
:
|
171
|
+
:odbc => ['ODBC::Error'],
|
172
|
+
:adonet => ['TypeError','System::Data::SqlClient::SqlException']
|
169
173
|
}
|
170
174
|
LOST_CONNECTION_MESSAGES = {
|
171
|
-
:odbc
|
172
|
-
:
|
175
|
+
:odbc => [/link failure/, /server failed/, /connection was already closed/, /invalid handle/i],
|
176
|
+
:adonet => [/current state is closed/, /network-related/]
|
173
177
|
}
|
174
178
|
|
175
179
|
cattr_accessor :native_text_database_type, :native_binary_database_type, :native_string_database_type,
|
@@ -316,11 +320,11 @@ module ActiveRecord
|
|
316
320
|
|
317
321
|
# REFERENTIAL INTEGRITY ====================================#
|
318
322
|
|
319
|
-
def disable_referential_integrity
|
320
|
-
do_execute "EXEC
|
323
|
+
def disable_referential_integrity
|
324
|
+
do_execute "EXEC sp_MSforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'"
|
321
325
|
yield
|
322
326
|
ensure
|
323
|
-
do_execute "EXEC
|
327
|
+
do_execute "EXEC sp_MSforeachtable 'ALTER TABLE ? CHECK CONSTRAINT ALL'"
|
324
328
|
end
|
325
329
|
|
326
330
|
# CONNECTION MANAGEMENT ====================================#
|
@@ -339,34 +343,14 @@ module ActiveRecord
|
|
339
343
|
end
|
340
344
|
|
341
345
|
def disconnect!
|
342
|
-
raw_connection.disconnect rescue nil
|
343
|
-
end
|
344
|
-
|
345
|
-
def raw_connection_run(sql)
|
346
|
-
with_auto_reconnect do
|
347
|
-
case connection_mode
|
348
|
-
when :odbc
|
349
|
-
block_given? ? raw_connection.run_block(sql) { |handle| yield(handle) } : raw_connection.run(sql)
|
350
|
-
else :ado
|
351
|
-
|
352
|
-
end
|
353
|
-
end
|
354
|
-
end
|
355
|
-
|
356
|
-
def raw_connection_do(sql)
|
357
346
|
case connection_mode
|
358
347
|
when :odbc
|
359
|
-
raw_connection.
|
360
|
-
else :
|
361
|
-
|
348
|
+
raw_connection.disconnect rescue nil
|
349
|
+
else :adonet
|
350
|
+
raw_connection.close rescue nil
|
362
351
|
end
|
363
352
|
end
|
364
353
|
|
365
|
-
def finish_statement_handle(handle)
|
366
|
-
handle.drop if handle && handle.respond_to?(:drop) && !handle.finished?
|
367
|
-
handle
|
368
|
-
end
|
369
|
-
|
370
354
|
# DATABASE STATEMENTS ======================================#
|
371
355
|
|
372
356
|
def user_options
|
@@ -394,23 +378,26 @@ module ActiveRecord
|
|
394
378
|
end
|
395
379
|
|
396
380
|
def select_rows(sql, name = nil)
|
397
|
-
raw_select(sql,name).last
|
381
|
+
raw_select(sql,name).first.last
|
398
382
|
end
|
399
383
|
|
400
|
-
def execute(sql, name = nil,
|
384
|
+
def execute(sql, name = nil, skip_logging = false)
|
401
385
|
if table_name = query_requires_identity_insert?(sql)
|
402
|
-
|
386
|
+
with_identity_insert_enabled(table_name) { do_execute(sql,name) }
|
403
387
|
else
|
404
|
-
|
388
|
+
do_execute(sql,name)
|
405
389
|
end
|
406
|
-
finish_statement_handle(handle)
|
407
390
|
end
|
408
391
|
|
409
392
|
def execute_procedure(proc_name, *variables)
|
410
393
|
vars = variables.map{ |v| quote(v) }.join(', ')
|
411
394
|
sql = "EXEC #{proc_name} #{vars}".strip
|
412
395
|
select(sql,'Execute Procedure',true).inject([]) do |results,row|
|
413
|
-
|
396
|
+
if row.kind_of?(Array)
|
397
|
+
results << row.inject([]) { |rs,r| rs << r.with_indifferent_access }
|
398
|
+
else
|
399
|
+
results << row.with_indifferent_access
|
400
|
+
end
|
414
401
|
end
|
415
402
|
end
|
416
403
|
|
@@ -649,10 +636,13 @@ module ActiveRecord
|
|
649
636
|
|
650
637
|
def change_column(table_name, column_name, type, options = {})
|
651
638
|
sql_commands = []
|
652
|
-
|
639
|
+
column_object = columns(table_name).detect { |c| c.name.to_s == column_name.to_s }
|
653
640
|
change_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
|
654
641
|
change_column_sql << " NOT NULL" if options[:null] == false
|
655
642
|
sql_commands << change_column_sql
|
643
|
+
if options_include_default?(options) || (column_object && column_object.type != type.to_sym)
|
644
|
+
remove_default_constraint(table_name,column_name)
|
645
|
+
end
|
656
646
|
if options_include_default?(options)
|
657
647
|
remove_sqlserver_columns_cache_for(table_name)
|
658
648
|
sql_commands << "ALTER TABLE #{quote_table_name(table_name)} ADD CONSTRAINT #{default_name(table_name,column_name)} DEFAULT #{quote(options[:default])} FOR #{quote_column_name(column_name)}"
|
@@ -773,8 +763,19 @@ module ActiveRecord
|
|
773
763
|
@connection = case connection_mode
|
774
764
|
when :odbc
|
775
765
|
ODBC.connect config[:dsn], config[:username], config[:password]
|
776
|
-
when :
|
777
|
-
|
766
|
+
when :adonet
|
767
|
+
System::Data::SqlClient::SqlConnection.new.tap do |connection|
|
768
|
+
connection.connection_string = System::Data::SqlClient::SqlConnectionStringBuilder.new.tap do |cs|
|
769
|
+
cs.user_i_d = config[:username] if config[:username]
|
770
|
+
cs.password = config[:password] if config[:password]
|
771
|
+
cs.integrated_security = true if config[:integrated_security] == 'true'
|
772
|
+
cs.add 'Server', config[:host].to_clr_string
|
773
|
+
cs.initial_catalog = config[:database]
|
774
|
+
cs.multiple_active_result_sets = false
|
775
|
+
cs.pooling = false
|
776
|
+
end.to_s
|
777
|
+
connection.open
|
778
|
+
end
|
778
779
|
end
|
779
780
|
rescue
|
780
781
|
raise unless @auto_connecting
|
@@ -820,11 +821,50 @@ module ActiveRecord
|
|
820
821
|
@auto_connecting = false
|
821
822
|
end
|
822
823
|
|
824
|
+
def raw_connection_run(sql)
|
825
|
+
with_auto_reconnect do
|
826
|
+
case connection_mode
|
827
|
+
when :odbc
|
828
|
+
block_given? ? raw_connection.run_block(sql) { |handle| yield(handle) } : raw_connection.run(sql)
|
829
|
+
else :adonet
|
830
|
+
raw_connection.create_command.tap{ |cmd| cmd.command_text = sql }.execute_reader
|
831
|
+
end
|
832
|
+
end
|
833
|
+
end
|
834
|
+
|
835
|
+
def raw_connection_do(sql)
|
836
|
+
case connection_mode
|
837
|
+
when :odbc
|
838
|
+
raw_connection.do(sql)
|
839
|
+
else :adonet
|
840
|
+
raw_connection.create_command.tap{ |cmd| cmd.command_text = sql }.execute_non_query
|
841
|
+
end
|
842
|
+
end
|
843
|
+
|
844
|
+
def finish_statement_handle(handle)
|
845
|
+
case connection_mode
|
846
|
+
when :odbc
|
847
|
+
handle.drop if handle && handle.respond_to?(:drop) && !handle.finished?
|
848
|
+
when :adonet
|
849
|
+
handle.close if handle && handle.respond_to?(:close) && !handle.is_closed
|
850
|
+
handle.dispose if handle && handle.respond_to?(:dispose)
|
851
|
+
end
|
852
|
+
handle
|
853
|
+
end
|
854
|
+
|
823
855
|
# DATABASE STATEMENTS ======================================
|
824
856
|
|
825
857
|
def select(sql, name = nil, ignore_special_columns = false)
|
826
858
|
repair_special_columns(sql) unless ignore_special_columns
|
827
|
-
|
859
|
+
fields_and_row_sets = raw_select(sql,name)
|
860
|
+
final_result_set = fields_and_row_sets.inject([]) do |rs,fields_and_rows|
|
861
|
+
fields, rows = fields_and_rows
|
862
|
+
rs << zip_fields_and_rows(fields,rows)
|
863
|
+
end
|
864
|
+
final_result_set.many? ? final_result_set : final_result_set.first
|
865
|
+
end
|
866
|
+
|
867
|
+
def zip_fields_and_rows(fields, rows)
|
828
868
|
rows.inject([]) do |results,row|
|
829
869
|
row_hash = {}
|
830
870
|
fields.each_with_index do |f, i|
|
@@ -847,10 +887,6 @@ module ActiveRecord
|
|
847
887
|
log_info_schema_queries ? yield : ActiveRecord::Base.silence{ yield }
|
848
888
|
end
|
849
889
|
|
850
|
-
def raw_execute(sql, name = nil, &block)
|
851
|
-
log(sql,name) { raw_connection_run(sql) }
|
852
|
-
end
|
853
|
-
|
854
890
|
def do_execute(sql,name=nil)
|
855
891
|
log(sql, name || 'EXECUTE') do
|
856
892
|
with_auto_reconnect { raw_connection_do(sql) }
|
@@ -858,9 +894,41 @@ module ActiveRecord
|
|
858
894
|
end
|
859
895
|
|
860
896
|
def raw_select(sql, name = nil)
|
861
|
-
|
862
|
-
|
863
|
-
|
897
|
+
fields_and_row_sets = []
|
898
|
+
log(sql,name) do
|
899
|
+
begin
|
900
|
+
handle = raw_connection_run(sql)
|
901
|
+
loop do
|
902
|
+
fields_and_rows = case connection_mode
|
903
|
+
when :odbc
|
904
|
+
handle_to_fields_and_rows_odbc(handle)
|
905
|
+
when :adonet
|
906
|
+
handle_to_fields_and_rows_adonet(handle)
|
907
|
+
end
|
908
|
+
fields_and_row_sets << fields_and_rows
|
909
|
+
break unless handle_more_results?(handle)
|
910
|
+
end
|
911
|
+
ensure
|
912
|
+
finish_statement_handle(handle)
|
913
|
+
end
|
914
|
+
end
|
915
|
+
fields_and_row_sets
|
916
|
+
end
|
917
|
+
|
918
|
+
def handle_more_results?(handle)
|
919
|
+
case connection_mode
|
920
|
+
when :odbc
|
921
|
+
handle.more_results
|
922
|
+
when :adonet
|
923
|
+
handle.next_result
|
924
|
+
end
|
925
|
+
end
|
926
|
+
|
927
|
+
def handle_to_fields_and_rows_odbc(handle)
|
928
|
+
fields = handle.columns(true).map { |c| c.name }
|
929
|
+
results = handle.inject([]) do |rows,row|
|
930
|
+
rows << row.inject([]) { |values,value| values << value }
|
931
|
+
end
|
864
932
|
rows = results.inject([]) do |rows,row|
|
865
933
|
row.each_with_index do |value, i|
|
866
934
|
if value.is_a? ODBC::TimeStamp
|
@@ -869,15 +937,37 @@ module ActiveRecord
|
|
869
937
|
end
|
870
938
|
rows << row
|
871
939
|
end
|
872
|
-
|
873
|
-
end
|
874
|
-
|
875
|
-
def
|
876
|
-
|
877
|
-
|
940
|
+
[fields,rows]
|
941
|
+
end
|
942
|
+
|
943
|
+
def handle_to_fields_and_rows_adonet(handle)
|
944
|
+
if handle.has_rows
|
945
|
+
fields = []
|
946
|
+
rows = []
|
947
|
+
fields_named = false
|
948
|
+
while handle.read
|
949
|
+
row = []
|
950
|
+
handle.visible_field_count.times do |row_index|
|
951
|
+
value = handle.get_value(row_index)
|
952
|
+
value = if value.is_a? System::String
|
953
|
+
value.to_s
|
954
|
+
elsif value.is_a? System::DBNull
|
955
|
+
nil
|
956
|
+
elsif value.is_a? System::DateTime
|
957
|
+
value.to_string("yyyy-MM-dd HH:MM:ss.fff").to_s
|
958
|
+
else
|
959
|
+
value
|
960
|
+
end
|
961
|
+
row << value
|
962
|
+
fields << handle.get_name(row_index).to_s unless fields_named
|
963
|
+
end
|
964
|
+
rows << row
|
965
|
+
fields_named = true
|
966
|
+
end
|
967
|
+
else
|
968
|
+
fields, rows = [], []
|
878
969
|
end
|
879
|
-
|
880
|
-
array
|
970
|
+
[fields,rows]
|
881
971
|
end
|
882
972
|
|
883
973
|
def add_limit_offset_for_association_limiting!(sql, options)
|
@@ -924,7 +1014,7 @@ module ActiveRecord
|
|
924
1014
|
|
925
1015
|
# IDENTITY INSERTS =========================================#
|
926
1016
|
|
927
|
-
def with_identity_insert_enabled(table_name
|
1017
|
+
def with_identity_insert_enabled(table_name)
|
928
1018
|
table_name = quote_table_name(table_name_or_views_table_name(table_name))
|
929
1019
|
set_identity_insert(table_name, true)
|
930
1020
|
yield
|
@@ -1031,6 +1121,7 @@ module ActiveRecord
|
|
1031
1121
|
|
1032
1122
|
def column_definitions(table_name)
|
1033
1123
|
db_name = unqualify_db_name(table_name)
|
1124
|
+
db_name_with_period = "#{db_name}." if db_name
|
1034
1125
|
table_name = unqualify_table_name(table_name)
|
1035
1126
|
sql = %{
|
1036
1127
|
SELECT
|
@@ -1052,7 +1143,7 @@ module ActiveRecord
|
|
1052
1143
|
WHEN COLUMNPROPERTY(OBJECT_ID(columns.TABLE_SCHEMA+'.'+columns.TABLE_NAME), columns.COLUMN_NAME, 'IsIdentity') = 0 THEN NULL
|
1053
1144
|
ELSE 1
|
1054
1145
|
END as is_identity
|
1055
|
-
FROM #{
|
1146
|
+
FROM #{db_name_with_period}INFORMATION_SCHEMA.COLUMNS columns
|
1056
1147
|
WHERE columns.TABLE_NAME = '#{table_name}'
|
1057
1148
|
ORDER BY columns.ordinal_position
|
1058
1149
|
}.gsub(/[ \t\r\n]+/,' ')
|
@@ -1072,7 +1163,7 @@ module ActiveRecord
|
|
1072
1163
|
if ci[:default_value].nil? && views.include?(table_name)
|
1073
1164
|
real_table_name = table_name_or_views_table_name(table_name)
|
1074
1165
|
real_column_name = views_real_column_name(table_name,ci[:name])
|
1075
|
-
col_default_sql = "SELECT c.COLUMN_DEFAULT FROM INFORMATION_SCHEMA.COLUMNS c WHERE c.TABLE_NAME = '#{real_table_name}' AND c.COLUMN_NAME = '#{real_column_name}'"
|
1166
|
+
col_default_sql = "SELECT c.COLUMN_DEFAULT FROM #{db_name_with_period}INFORMATION_SCHEMA.COLUMNS c WHERE c.TABLE_NAME = '#{real_table_name}' AND c.COLUMN_NAME = '#{real_column_name}'"
|
1076
1167
|
ci[:default_value] = info_schema_query { select_value(col_default_sql) }
|
1077
1168
|
end
|
1078
1169
|
ci[:default_value] = case ci[:default_value]
|
@@ -13,9 +13,9 @@ class ConnectionTestSqlserver < ActiveRecord::TestCase
|
|
13
13
|
|
14
14
|
|
15
15
|
should 'return finished ODBC statment handle from #execute without block' do
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
assert_all_statements_used_are_closed do
|
17
|
+
@connection.execute('SELECT * FROM [topics]')
|
18
|
+
end
|
19
19
|
end
|
20
20
|
|
21
21
|
should 'finish ODBC statment handle from #execute with block' do
|
@@ -24,12 +24,6 @@ class ConnectionTestSqlserver < ActiveRecord::TestCase
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
should 'return an unfinished ODBC statement handler from #raw_execute' do
|
28
|
-
handle = @connection.send(:raw_execute,'SELECT * FROM [topics]')
|
29
|
-
assert_instance_of ODBC::Statement, handle
|
30
|
-
assert !handle.finished?
|
31
|
-
end
|
32
|
-
|
33
27
|
should 'finish connection from #raw_select' do
|
34
28
|
assert_all_statements_used_are_closed do
|
35
29
|
@connection.send(:raw_select,'SELECT * FROM [topics]')
|
@@ -29,5 +29,16 @@ class ExecuteProcedureTestSqlserver < ActiveRecord::TestCase
|
|
29
29
|
end if sqlserver_2000?
|
30
30
|
end
|
31
31
|
|
32
|
+
should 'allow multiple result sets to be returned' do
|
33
|
+
results1, results2 = @klass.execute_procedure('sp_helpconstraint','accounts')
|
34
|
+
assert_instance_of Array, results1
|
35
|
+
assert_instance_of HashWithIndifferentAccess, results1.first
|
36
|
+
assert results1.first['Object Name']
|
37
|
+
assert_instance_of Array, results2
|
38
|
+
assert_instance_of HashWithIndifferentAccess, results2.first
|
39
|
+
assert results2.first['constraint_name']
|
40
|
+
assert results2.first['constraint_type']
|
41
|
+
end
|
42
|
+
|
32
43
|
|
33
44
|
end
|
@@ -46,9 +46,21 @@ class MigrationTestSqlserver < ActiveRecord::TestCase
|
|
46
46
|
assert lock_version_column.default.nil?
|
47
47
|
end
|
48
48
|
|
49
|
+
should 'not drop the default contraint if just renaming' do
|
50
|
+
find_default = lambda do
|
51
|
+
@connection.select_all("EXEC sp_helpconstraint 'defaults','nomsg'").select do |row|
|
52
|
+
row['constraint_type'] == "DEFAULT on column decimal_number"
|
53
|
+
end.last
|
54
|
+
end
|
55
|
+
default_before = find_default.call
|
56
|
+
@connection.change_column :defaults, :decimal_number, :decimal, :precision => 4
|
57
|
+
default_after = find_default.call
|
58
|
+
assert default_after
|
59
|
+
assert_equal default_before['constraint_keys'], default_after['constraint_keys']
|
60
|
+
end
|
61
|
+
|
49
62
|
end
|
50
63
|
|
51
|
-
|
52
64
|
end
|
53
65
|
|
54
66
|
|
@@ -1,6 +1,10 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'shoulda'
|
3
3
|
require 'mocha'
|
4
|
+
[ File.expand_path(File.join(File.dirname(__FILE__),'..','..','test')),
|
5
|
+
File.expand_path(File.join(File.dirname(__FILE__),'..','..','test','connections','native_sqlserver_odbc')),
|
6
|
+
File.expand_path(File.join(File.dirname(__FILE__),'..','..','..','..','..','rails','activerecord','test'))
|
7
|
+
].each{ |lib| $:.unshift(lib) unless $:.include?(lib) } if ENV['TM_DIRECTORY']
|
4
8
|
require 'cases/helper'
|
5
9
|
require 'models/topic'
|
6
10
|
require 'active_record/version'
|
@@ -1,4 +1,4 @@
|
|
1
|
-
print "Using
|
1
|
+
print "Using SQLServer via ADONET\n"
|
2
2
|
require_dependency 'models/course'
|
3
3
|
require 'logger'
|
4
4
|
|
@@ -7,12 +7,14 @@ ActiveRecord::Base.logger = Logger.new("debug.log")
|
|
7
7
|
ActiveRecord::Base.configurations = {
|
8
8
|
'arunit' => {
|
9
9
|
:adapter => 'sqlserver',
|
10
|
+
:mode => 'ADONET',
|
10
11
|
:host => 'localhost',
|
11
12
|
:username => 'rails',
|
12
13
|
:database => 'activerecord_unittest'
|
13
14
|
},
|
14
15
|
'arunit2' => {
|
15
16
|
:adapter => 'sqlserver',
|
17
|
+
:mode => 'ADONET',
|
16
18
|
:host => 'localhost',
|
17
19
|
:username => 'rails',
|
18
20
|
:database => 'activerecord_unittest2'
|
metadata
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-sqlserver-adapter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 2
|
7
|
+
- 3
|
8
|
+
- 5
|
9
|
+
version: 2.3.5
|
5
10
|
platform: ruby
|
6
11
|
authors:
|
7
12
|
- Ken Collins
|
@@ -54,18 +59,20 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
54
59
|
requirements:
|
55
60
|
- - ">="
|
56
61
|
- !ruby/object:Gem::Version
|
62
|
+
segments:
|
63
|
+
- 0
|
57
64
|
version: "0"
|
58
|
-
version:
|
59
65
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
66
|
requirements:
|
61
67
|
- - ">="
|
62
68
|
- !ruby/object:Gem::Version
|
69
|
+
segments:
|
70
|
+
- 0
|
63
71
|
version: "0"
|
64
|
-
version:
|
65
72
|
requirements: []
|
66
73
|
|
67
74
|
rubyforge_project:
|
68
|
-
rubygems_version: 1.3.
|
75
|
+
rubygems_version: 1.3.6
|
69
76
|
signing_key:
|
70
77
|
specification_version: 3
|
71
78
|
summary: SQL Server 2000, 2005 and 2008 Adapter For Rails.
|