activerecord-sqlserver-adapter_new 4.2.15
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.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/CHANGELOG.md +212 -0
- data/CODE_OF_CONDUCT.md +31 -0
- data/Gemfile +61 -0
- data/Guardfile +29 -0
- data/MIT-LICENSE +20 -0
- data/README.md +201 -0
- data/RUNNING_UNIT_TESTS.md +121 -0
- data/Rakefile +48 -0
- data/VERSION +1 -0
- data/activerecord-sqlserver-adapter_new.gemspec +20 -0
- data/appveyor.yml +39 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/active_record.rb +27 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb +25 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +40 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain_subscriber.rb +4 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/odbc.rb +34 -0
- data/lib/active_record/connection_adapters/sqlserver/database_limits.rb +49 -0
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +386 -0
- data/lib/active_record/connection_adapters/sqlserver/database_tasks.rb +68 -0
- data/lib/active_record/connection_adapters/sqlserver/errors.rb +7 -0
- data/lib/active_record/connection_adapters/sqlserver/quoting.rb +69 -0
- data/lib/active_record/connection_adapters/sqlserver/schema_cache.rb +114 -0
- data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +52 -0
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +473 -0
- data/lib/active_record/connection_adapters/sqlserver/showplan.rb +66 -0
- data/lib/active_record/connection_adapters/sqlserver/showplan/printer_table.rb +66 -0
- data/lib/active_record/connection_adapters/sqlserver/showplan/printer_xml.rb +22 -0
- data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +76 -0
- data/lib/active_record/connection_adapters/sqlserver/transaction.rb +57 -0
- data/lib/active_record/connection_adapters/sqlserver/type.rb +46 -0
- data/lib/active_record/connection_adapters/sqlserver/type/big_integer.rb +15 -0
- data/lib/active_record/connection_adapters/sqlserver/type/binary.rb +15 -0
- data/lib/active_record/connection_adapters/sqlserver/type/boolean.rb +12 -0
- data/lib/active_record/connection_adapters/sqlserver/type/char.rb +38 -0
- data/lib/active_record/connection_adapters/sqlserver/type/date.rb +21 -0
- data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +41 -0
- data/lib/active_record/connection_adapters/sqlserver/type/datetime2.rb +17 -0
- data/lib/active_record/connection_adapters/sqlserver/type/datetimeoffset.rb +31 -0
- data/lib/active_record/connection_adapters/sqlserver/type/decimal.rb +12 -0
- data/lib/active_record/connection_adapters/sqlserver/type/float.rb +15 -0
- data/lib/active_record/connection_adapters/sqlserver/type/integer.rb +12 -0
- data/lib/active_record/connection_adapters/sqlserver/type/money.rb +21 -0
- data/lib/active_record/connection_adapters/sqlserver/type/real.rb +15 -0
- data/lib/active_record/connection_adapters/sqlserver/type/small_integer.rb +13 -0
- data/lib/active_record/connection_adapters/sqlserver/type/small_money.rb +21 -0
- data/lib/active_record/connection_adapters/sqlserver/type/smalldatetime.rb +22 -0
- data/lib/active_record/connection_adapters/sqlserver/type/string.rb +12 -0
- data/lib/active_record/connection_adapters/sqlserver/type/text.rb +15 -0
- data/lib/active_record/connection_adapters/sqlserver/type/time.rb +40 -0
- data/lib/active_record/connection_adapters/sqlserver/type/time_value_fractional.rb +76 -0
- data/lib/active_record/connection_adapters/sqlserver/type/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/sqlserver/type/tiny_integer.rb +22 -0
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_char.rb +15 -0
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_string.rb +12 -0
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_text.rb +15 -0
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar.rb +20 -0
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar_max.rb +20 -0
- data/lib/active_record/connection_adapters/sqlserver/type/uuid.rb +23 -0
- data/lib/active_record/connection_adapters/sqlserver/type/varbinary.rb +20 -0
- data/lib/active_record/connection_adapters/sqlserver/type/varbinary_max.rb +20 -0
- data/lib/active_record/connection_adapters/sqlserver/type/varchar.rb +20 -0
- data/lib/active_record/connection_adapters/sqlserver/type/varchar_max.rb +20 -0
- data/lib/active_record/connection_adapters/sqlserver/utils.rb +136 -0
- data/lib/active_record/connection_adapters/sqlserver/version.rb +11 -0
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +405 -0
- data/lib/active_record/connection_adapters/sqlserver_column.rb +53 -0
- data/lib/active_record/sqlserver_base.rb +20 -0
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +131 -0
- data/lib/activerecord-sqlserver-adapter.rb +1 -0
- data/lib/arel/visitors/sqlserver.rb +214 -0
- data/lib/arel_sqlserver.rb +3 -0
- data/test/appveyor/dbsetup.ps1 +27 -0
- data/test/appveyor/dbsetup.sql +11 -0
- data/test/cases/adapter_test_sqlserver.rb +444 -0
- data/test/cases/coerced_tests.rb +713 -0
- data/test/cases/column_test_sqlserver.rb +780 -0
- data/test/cases/connection_test_sqlserver.rb +142 -0
- data/test/cases/execute_procedure_test_sqlserver.rb +44 -0
- data/test/cases/fetch_test_sqlserver.rb +57 -0
- data/test/cases/fully_qualified_identifier_test_sqlserver.rb +76 -0
- data/test/cases/helper_sqlserver.rb +54 -0
- data/test/cases/migration_test_sqlserver.rb +61 -0
- data/test/cases/order_test_sqlserver.rb +147 -0
- data/test/cases/pessimistic_locking_test_sqlserver.rb +90 -0
- data/test/cases/rake_test_sqlserver.rb +163 -0
- data/test/cases/schema_dumper_test_sqlserver.rb +198 -0
- data/test/cases/schema_test_sqlserver.rb +54 -0
- data/test/cases/scratchpad_test_sqlserver.rb +9 -0
- data/test/cases/showplan_test_sqlserver.rb +65 -0
- data/test/cases/specific_schema_test_sqlserver.rb +167 -0
- data/test/cases/transaction_test_sqlserver.rb +66 -0
- data/test/cases/utils_test_sqlserver.rb +129 -0
- data/test/cases/uuid_test_sqlserver.rb +48 -0
- data/test/config.yml +41 -0
- data/test/debug.rb +14 -0
- data/test/fixtures/1px.gif +0 -0
- data/test/migrations/transaction_table/1_table_will_never_be_created.rb +11 -0
- data/test/models/sqlserver/booking.rb +3 -0
- data/test/models/sqlserver/customers_view.rb +3 -0
- data/test/models/sqlserver/datatype.rb +3 -0
- data/test/models/sqlserver/datatype_migration.rb +3 -0
- data/test/models/sqlserver/dollar_table_name.rb +3 -0
- data/test/models/sqlserver/dot_table_name.rb +3 -0
- data/test/models/sqlserver/edge_schema.rb +13 -0
- data/test/models/sqlserver/fk_has_fk.rb +3 -0
- data/test/models/sqlserver/fk_has_pk.rb +3 -0
- data/test/models/sqlserver/natural_pk_data.rb +4 -0
- data/test/models/sqlserver/natural_pk_int_data.rb +3 -0
- data/test/models/sqlserver/no_pk_data.rb +3 -0
- data/test/models/sqlserver/object_default.rb +3 -0
- data/test/models/sqlserver/quoted_table.rb +7 -0
- data/test/models/sqlserver/quoted_view_1.rb +3 -0
- data/test/models/sqlserver/quoted_view_2.rb +3 -0
- data/test/models/sqlserver/string_default.rb +3 -0
- data/test/models/sqlserver/string_defaults_big_view.rb +3 -0
- data/test/models/sqlserver/string_defaults_view.rb +3 -0
- data/test/models/sqlserver/tinyint_pk.rb +3 -0
- data/test/models/sqlserver/upper.rb +3 -0
- data/test/models/sqlserver/uppered.rb +3 -0
- data/test/models/sqlserver/uuid.rb +3 -0
- data/test/schema/datatypes/2012.sql +55 -0
- data/test/schema/sqlserver_specific_schema.rb +207 -0
- data/test/support/coerceable_test_sqlserver.rb +45 -0
- data/test/support/connection_reflection.rb +37 -0
- data/test/support/load_schema_sqlserver.rb +29 -0
- data/test/support/minitest_sqlserver.rb +1 -0
- data/test/support/paths_sqlserver.rb +50 -0
- data/test/support/rake_helpers.rb +41 -0
- data/test/support/sql_counter_sqlserver.rb +32 -0
- metadata +253 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
module ActiveRecord
|
|
2
|
+
module ConnectionAdapters
|
|
3
|
+
class SQLServerColumn < Column
|
|
4
|
+
|
|
5
|
+
def initialize(name, default, cast_type, sql_type = nil, null = true, sqlserver_options = {})
|
|
6
|
+
super(name, default, cast_type, sql_type, null)
|
|
7
|
+
@sqlserver_options = sqlserver_options.symbolize_keys
|
|
8
|
+
@default_function = @sqlserver_options[:default_function]
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def sql_type_for_statement
|
|
12
|
+
if is_integer? || is_real?
|
|
13
|
+
sql_type.sub(/\((\d+)?\)/, '')
|
|
14
|
+
else
|
|
15
|
+
sql_type
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def table_name
|
|
20
|
+
@sqlserver_options[:table_name]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def is_identity?
|
|
24
|
+
@sqlserver_options[:is_identity]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def is_primary?
|
|
28
|
+
@sqlserver_options[:is_primary]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def is_utf8?
|
|
32
|
+
@sql_type =~ /nvarchar|ntext|nchar/i
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def is_integer?
|
|
36
|
+
@sql_type =~ /int/i
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def is_real?
|
|
40
|
+
@sql_type =~ /real/i
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def collation
|
|
44
|
+
@sqlserver_options[:collation]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def case_sensitive?
|
|
48
|
+
collation && !collation.match(/_CI/)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module ActiveRecord
|
|
2
|
+
module ConnectionHandling
|
|
3
|
+
def sqlserver_connection(config) #:nodoc:
|
|
4
|
+
config = config.symbolize_keys
|
|
5
|
+
config.reverse_merge! mode: :dblib
|
|
6
|
+
mode = config[:mode].to_s.downcase.underscore.to_sym
|
|
7
|
+
case mode
|
|
8
|
+
when :dblib
|
|
9
|
+
require 'tiny_tds'
|
|
10
|
+
when :odbc
|
|
11
|
+
raise ArgumentError, 'Missing :dsn configuration.' unless config.key?(:dsn)
|
|
12
|
+
require 'odbc'
|
|
13
|
+
require 'active_record/connection_adapters/sqlserver/core_ext/odbc'
|
|
14
|
+
else
|
|
15
|
+
raise ArgumentError, "Unknown connection mode in #{config.inspect}."
|
|
16
|
+
end
|
|
17
|
+
ConnectionAdapters::SQLServerAdapter.new(nil, logger, nil, config.merge(mode: mode))
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
require 'active_record/tasks/database_tasks'
|
|
2
|
+
require 'shellwords'
|
|
3
|
+
require 'ipaddr'
|
|
4
|
+
require 'socket'
|
|
5
|
+
|
|
6
|
+
module ActiveRecord
|
|
7
|
+
module Tasks
|
|
8
|
+
|
|
9
|
+
class SQLServerDatabaseTasks
|
|
10
|
+
|
|
11
|
+
DEFAULT_COLLATION = 'SQL_Latin1_General_CP1_CI_AS'
|
|
12
|
+
|
|
13
|
+
delegate :connection, :establish_connection, :clear_active_connections!,
|
|
14
|
+
to: ActiveRecord::Base
|
|
15
|
+
|
|
16
|
+
def initialize(configuration)
|
|
17
|
+
@configuration = configuration
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def create(master_established = false)
|
|
21
|
+
establish_master_connection unless master_established
|
|
22
|
+
connection.create_database configuration['database'], configuration.merge('collation' => default_collation)
|
|
23
|
+
establish_connection configuration
|
|
24
|
+
rescue ActiveRecord::StatementInvalid => error
|
|
25
|
+
if /database .* already exists/i === error.message
|
|
26
|
+
raise DatabaseAlreadyExists
|
|
27
|
+
else
|
|
28
|
+
raise
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def drop
|
|
33
|
+
establish_master_connection
|
|
34
|
+
connection.drop_database configuration['database']
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def charset
|
|
38
|
+
connection.charset
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def collation
|
|
42
|
+
connection.collation
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def purge
|
|
46
|
+
clear_active_connections!
|
|
47
|
+
drop
|
|
48
|
+
create true
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def structure_dump(filename)
|
|
52
|
+
command = [
|
|
53
|
+
"defncopy",
|
|
54
|
+
"-S #{Shellwords.escape(configuration['host'])}",
|
|
55
|
+
"-D #{Shellwords.escape(configuration['database'])}",
|
|
56
|
+
"-U #{Shellwords.escape(configuration['username'])}",
|
|
57
|
+
"-P #{Shellwords.escape(configuration['password'])}",
|
|
58
|
+
"-o #{Shellwords.escape(filename)}",
|
|
59
|
+
]
|
|
60
|
+
table_args = connection.tables.map { |t| Shellwords.escape(t) }
|
|
61
|
+
command.concat(table_args)
|
|
62
|
+
view_args = connection.views.map { |v| Shellwords.escape(v) }
|
|
63
|
+
command.concat(view_args)
|
|
64
|
+
raise 'Error dumping database' unless Kernel.system(command.join(' '))
|
|
65
|
+
dump = File.read(filename)
|
|
66
|
+
dump.gsub!(/^USE .*$\nGO\n/, '') # Strip db USE statements
|
|
67
|
+
dump.gsub!(/^GO\n/, '') # Strip db GO statements
|
|
68
|
+
dump.gsub!(/nvarchar\(8000\)/, 'nvarchar(4000)') # Fix nvarchar(8000) column defs
|
|
69
|
+
dump.gsub!(/nvarchar\(-1\)/, 'nvarchar(max)') # Fix nvarchar(-1) column defs
|
|
70
|
+
dump.gsub!(/text\(\d+\)/, 'text') # Fix text(16) column defs
|
|
71
|
+
File.open(filename, "w") { |file| file.puts dump }
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def structure_load(filename)
|
|
75
|
+
connection.execute File.read(filename)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
private
|
|
80
|
+
|
|
81
|
+
def configuration
|
|
82
|
+
@configuration
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def default_collation
|
|
86
|
+
configuration['collation'] || DEFAULT_COLLATION
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def establish_master_connection
|
|
90
|
+
establish_connection configuration.merge('database' => 'master')
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
module DatabaseTasksSQLServer
|
|
96
|
+
|
|
97
|
+
extend ActiveSupport::Concern
|
|
98
|
+
|
|
99
|
+
module ClassMethods
|
|
100
|
+
|
|
101
|
+
LOCAL_IPADDR = [
|
|
102
|
+
IPAddr.new('192.168.0.0/16'),
|
|
103
|
+
IPAddr.new('10.0.0.0/8'),
|
|
104
|
+
IPAddr.new('172.16.0.0/12')
|
|
105
|
+
]
|
|
106
|
+
|
|
107
|
+
private
|
|
108
|
+
|
|
109
|
+
def local_database?(configuration)
|
|
110
|
+
super || local_ipaddr?(configuration_host_ip(configuration))
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def configuration_host_ip(configuration)
|
|
114
|
+
return nil unless configuration['host']
|
|
115
|
+
Socket::getaddrinfo(configuration['host'], 'echo', Socket::AF_INET)[0][3]
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def local_ipaddr?(host_ip)
|
|
119
|
+
return false unless host_ip
|
|
120
|
+
LOCAL_IPADDR.any? { |ip| ip.include?(host_ip) }
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
DatabaseTasks.register_task %r{sqlserver}, SQLServerDatabaseTasks
|
|
128
|
+
DatabaseTasks.send :include, DatabaseTasksSQLServer
|
|
129
|
+
|
|
130
|
+
end
|
|
131
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'active_record/connection_adapters/sqlserver_adapter'
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
module Arel
|
|
2
|
+
module Visitors
|
|
3
|
+
class SQLServer < Arel::Visitors::ToSql
|
|
4
|
+
|
|
5
|
+
OFFSET = " OFFSET "
|
|
6
|
+
ROWS = " ROWS"
|
|
7
|
+
FETCH = " FETCH NEXT "
|
|
8
|
+
FETCH0 = " FETCH FIRST (SELECT 0) "
|
|
9
|
+
ROWS_ONLY = " ROWS ONLY"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
# SQLServer ToSql/Visitor (Overides)
|
|
15
|
+
|
|
16
|
+
def visit_Arel_Nodes_BindParam o, collector
|
|
17
|
+
collector.add_bind(o) { |i| "@#{i-1}" }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def visit_Arel_Nodes_Bin o, collector
|
|
21
|
+
visit o.expr, collector
|
|
22
|
+
if o.expr.val.is_a? Numeric
|
|
23
|
+
collector
|
|
24
|
+
else
|
|
25
|
+
collector << " #{ActiveRecord::ConnectionAdapters::SQLServerAdapter.cs_equality_operator} "
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def visit_Arel_Nodes_UpdateStatement(o, a)
|
|
30
|
+
if o.orders.any? && o.limit.nil?
|
|
31
|
+
o.limit = Nodes::Limit.new(9_223_372_036_854_775_807)
|
|
32
|
+
end
|
|
33
|
+
super
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def visit_Arel_Nodes_Lock o, collector
|
|
37
|
+
o.expr = Arel.sql('WITH(UPDLOCK)') if o.expr.to_s =~ /FOR UPDATE/
|
|
38
|
+
collector << SPACE
|
|
39
|
+
visit o.expr, collector
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def visit_Arel_Nodes_Offset o, collector
|
|
43
|
+
collector << OFFSET
|
|
44
|
+
visit o.expr, collector
|
|
45
|
+
collector << ROWS
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def visit_Arel_Nodes_Limit o, collector
|
|
49
|
+
if node_value(o) == 0
|
|
50
|
+
collector << FETCH0
|
|
51
|
+
collector << ROWS_ONLY
|
|
52
|
+
else
|
|
53
|
+
collector << FETCH
|
|
54
|
+
visit o.expr, collector
|
|
55
|
+
collector << ROWS_ONLY
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def visit_Arel_Nodes_SelectStatement o, collector
|
|
60
|
+
@select_statement = o
|
|
61
|
+
distinct_One_As_One_Is_So_Not_Fetch o
|
|
62
|
+
if o.with
|
|
63
|
+
collector = visit o.with, collector
|
|
64
|
+
collector << SPACE
|
|
65
|
+
end
|
|
66
|
+
collector = o.cores.inject(collector) { |c,x|
|
|
67
|
+
visit_Arel_Nodes_SelectCore(x, c)
|
|
68
|
+
}
|
|
69
|
+
collector = visit_Orders_And_Let_Fetch_Happen o, collector
|
|
70
|
+
collector = visit_Make_Fetch_Happen o, collector
|
|
71
|
+
collector
|
|
72
|
+
ensure
|
|
73
|
+
@select_statement = nil
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def visit_Arel_Table o, collector
|
|
77
|
+
# Apparently, o.engine.connection can actually be a different adapter
|
|
78
|
+
# than sqlserver. Can be removed if fixed in ActiveRecord. See:
|
|
79
|
+
# github.com/rails-sqlserver/activerecord-sqlserver-adapter/issues/450
|
|
80
|
+
table_name = if o.engine.connection.respond_to?(:sqlserver?) && o.engine.connection.database_prefix_remote_server?
|
|
81
|
+
remote_server_table_name(o)
|
|
82
|
+
else
|
|
83
|
+
quote_table_name(o.name)
|
|
84
|
+
end
|
|
85
|
+
if o.table_alias
|
|
86
|
+
collector << "#{table_name} #{quote_table_name o.table_alias}"
|
|
87
|
+
else
|
|
88
|
+
collector << table_name
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def visit_Arel_Nodes_JoinSource o, collector
|
|
93
|
+
if o.left
|
|
94
|
+
collector = visit o.left, collector
|
|
95
|
+
collector = visit_Arel_Nodes_SelectStatement_SQLServer_Lock collector
|
|
96
|
+
end
|
|
97
|
+
if o.right.any?
|
|
98
|
+
collector << " " if o.left
|
|
99
|
+
collector = inject_join o.right, collector, ' '
|
|
100
|
+
end
|
|
101
|
+
collector
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def visit_Arel_Nodes_OuterJoin o, collector
|
|
105
|
+
collector << "LEFT OUTER JOIN "
|
|
106
|
+
collector = visit o.left, collector
|
|
107
|
+
collector = visit_Arel_Nodes_SelectStatement_SQLServer_Lock collector, space: true
|
|
108
|
+
collector << " "
|
|
109
|
+
visit o.right, collector
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# SQLServer ToSql/Visitor (Additions)
|
|
113
|
+
|
|
114
|
+
def visit_Arel_Nodes_SelectStatement_SQLServer_Lock collector, options = {}
|
|
115
|
+
if select_statement_lock?
|
|
116
|
+
collector = visit @select_statement.lock, collector
|
|
117
|
+
collector << SPACE if options[:space]
|
|
118
|
+
end
|
|
119
|
+
collector
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def visit_Orders_And_Let_Fetch_Happen o, collector
|
|
123
|
+
make_Fetch_Possible_And_Deterministic o
|
|
124
|
+
unless o.orders.empty?
|
|
125
|
+
collector << SPACE
|
|
126
|
+
collector << ORDER_BY
|
|
127
|
+
len = o.orders.length - 1
|
|
128
|
+
o.orders.each_with_index { |x, i|
|
|
129
|
+
collector = visit(x, collector)
|
|
130
|
+
collector << COMMA unless len == i
|
|
131
|
+
}
|
|
132
|
+
end
|
|
133
|
+
collector
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def visit_Make_Fetch_Happen o, collector
|
|
137
|
+
o.offset = Nodes::Offset.new(0) if o.limit && !o.offset
|
|
138
|
+
collector = visit o.offset, collector if o.offset
|
|
139
|
+
collector = visit o.limit, collector if o.limit
|
|
140
|
+
collector
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# SQLServer Helpers
|
|
144
|
+
|
|
145
|
+
def node_value(node)
|
|
146
|
+
return nil unless node
|
|
147
|
+
case node.expr
|
|
148
|
+
when NilClass then nil
|
|
149
|
+
when Numeric then node.expr
|
|
150
|
+
when Arel::Nodes::Unary then node.expr.expr
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def select_statement_lock?
|
|
155
|
+
@select_statement && @select_statement.lock
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def make_Fetch_Possible_And_Deterministic o
|
|
159
|
+
return if o.limit.nil? && o.offset.nil?
|
|
160
|
+
t = table_From_Statement o
|
|
161
|
+
pk = primary_Key_From_Table t
|
|
162
|
+
return unless pk
|
|
163
|
+
if o.orders.empty?
|
|
164
|
+
# Prefer deterministic vs a simple `(SELECT NULL)` expr.
|
|
165
|
+
o.orders = [pk.asc]
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def distinct_One_As_One_Is_So_Not_Fetch o
|
|
170
|
+
core = o.cores.first
|
|
171
|
+
distinct = Nodes::Distinct === core.set_quantifier
|
|
172
|
+
oneasone = core.projections.all? { |x| x == ActiveRecord::FinderMethods::ONE_AS_ONE }
|
|
173
|
+
limitone = node_value(o.limit) == 1
|
|
174
|
+
if distinct && oneasone && limitone && !o.offset
|
|
175
|
+
core.projections = [Arel.sql("TOP(1) 1 AS [one]")]
|
|
176
|
+
o.limit = nil
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def table_From_Statement o
|
|
181
|
+
core = o.cores.first
|
|
182
|
+
if Arel::Table === core.from
|
|
183
|
+
core.from
|
|
184
|
+
elsif Arel::Nodes::SqlLiteral === core.from
|
|
185
|
+
Arel::Table.new(core.from)
|
|
186
|
+
elsif Arel::Nodes::JoinSource === core.source
|
|
187
|
+
Arel::Nodes::SqlLiteral === core.source.left ? Arel::Table.new(core.source.left, @engine) : core.source.left
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def primary_Key_From_Table t
|
|
192
|
+
return unless t
|
|
193
|
+
return t.primary_key if t.primary_key
|
|
194
|
+
if engine_pk = t.engine.primary_key
|
|
195
|
+
pk = t.engine.arel_table[engine_pk]
|
|
196
|
+
return pk if pk
|
|
197
|
+
end
|
|
198
|
+
pk = t.engine.connection.schema_cache.primary_keys(t.engine.table_name)
|
|
199
|
+
return pk if pk
|
|
200
|
+
column_name = t.engine.columns.first.try(:name)
|
|
201
|
+
column_name ? t[column_name] : nil
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def remote_server_table_name o
|
|
205
|
+
ActiveRecord::ConnectionAdapters::SQLServer::Utils.extract_identifiers(
|
|
206
|
+
"#{o.engine.connection.database_prefix}#{o.name}"
|
|
207
|
+
).quoted
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
Arel::Visitors::VISITORS['sqlserver'] = Arel::Visitors::SQLServer
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
|
|
2
|
+
Write-Output "Setting up..."
|
|
3
|
+
[reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | Out-Null
|
|
4
|
+
[reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.SqlWmiManagement") | Out-Null
|
|
5
|
+
|
|
6
|
+
Write-Output "Setting variables..."
|
|
7
|
+
$serverName = $env:COMPUTERNAME
|
|
8
|
+
$instances = @('SQL2012SP1', 'SQL2014')
|
|
9
|
+
$smo = 'Microsoft.SqlServer.Management.Smo.'
|
|
10
|
+
$wmi = new-object ($smo + 'Wmi.ManagedComputer')
|
|
11
|
+
|
|
12
|
+
Write-Output "Configure Instances..."
|
|
13
|
+
foreach ($instance in $instances) {
|
|
14
|
+
Write-Output "Instance $instance ..."
|
|
15
|
+
Write-Output "Enable TCP/IP and port 1433..."
|
|
16
|
+
$uri = "ManagedComputer[@Name='$serverName']/ServerInstance[@Name='$instance']/ServerProtocol[@Name='Tcp']"
|
|
17
|
+
$tcp = $wmi.GetSmoObject($uri)
|
|
18
|
+
$tcp.IsEnabled = $true
|
|
19
|
+
foreach ($ipAddress in $Tcp.IPAddresses) {
|
|
20
|
+
$ipAddress.IPAddressProperties["TcpDynamicPorts"].Value = ""
|
|
21
|
+
$ipAddress.IPAddressProperties["TcpPort"].Value = "1433"
|
|
22
|
+
}
|
|
23
|
+
$tcp.Alter()
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
Set-Service SQLBrowser -StartupType Manual
|
|
27
|
+
Start-Service SQLBrowser
|