activerecord-sqlserver-adapter 5.2.1 → 6.0.2

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.
Files changed (153) hide show
  1. checksums.yaml +4 -4
  2. data/.editorconfig +9 -0
  3. data/.github/issue_template.md +23 -0
  4. data/.github/workflows/ci.yml +26 -0
  5. data/.gitignore +1 -0
  6. data/.rubocop.yml +29 -0
  7. data/CHANGELOG.md +58 -20
  8. data/{Dockerfile → Dockerfile.ci} +1 -1
  9. data/Gemfile +48 -41
  10. data/Guardfile +9 -8
  11. data/README.md +28 -31
  12. data/RUNNING_UNIT_TESTS.md +3 -0
  13. data/Rakefile +14 -16
  14. data/VERSION +1 -1
  15. data/activerecord-sqlserver-adapter.gemspec +25 -14
  16. data/appveyor.yml +24 -17
  17. data/docker-compose.ci.yml +7 -5
  18. data/guides/RELEASING.md +11 -0
  19. data/lib/active_record/connection_adapters/sqlserver/core_ext/active_record.rb +2 -4
  20. data/lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb +3 -4
  21. data/lib/active_record/connection_adapters/sqlserver/core_ext/calculations.rb +5 -4
  22. data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +3 -3
  23. data/lib/active_record/connection_adapters/sqlserver/core_ext/explain_subscriber.rb +2 -0
  24. data/lib/active_record/connection_adapters/sqlserver/core_ext/finder_methods.rb +8 -7
  25. data/lib/active_record/connection_adapters/sqlserver/core_ext/preloader.rb +36 -0
  26. data/lib/active_record/connection_adapters/sqlserver/core_ext/query_methods.rb +6 -4
  27. data/lib/active_record/connection_adapters/sqlserver/database_limits.rb +9 -0
  28. data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +88 -44
  29. data/lib/active_record/connection_adapters/sqlserver/database_tasks.rb +9 -12
  30. data/lib/active_record/connection_adapters/sqlserver/errors.rb +2 -3
  31. data/lib/active_record/connection_adapters/sqlserver/quoting.rb +46 -8
  32. data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +16 -5
  33. data/lib/active_record/connection_adapters/sqlserver/schema_dumper.rb +9 -7
  34. data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +210 -163
  35. data/lib/active_record/connection_adapters/sqlserver/showplan.rb +8 -8
  36. data/lib/active_record/connection_adapters/sqlserver/showplan/printer_table.rb +4 -2
  37. data/lib/active_record/connection_adapters/sqlserver/showplan/printer_xml.rb +3 -1
  38. data/lib/active_record/connection_adapters/sqlserver/sql_type_metadata.rb +2 -2
  39. data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +43 -44
  40. data/lib/active_record/connection_adapters/sqlserver/transaction.rb +7 -9
  41. data/lib/active_record/connection_adapters/sqlserver/type.rb +38 -35
  42. data/lib/active_record/connection_adapters/sqlserver/type/big_integer.rb +3 -3
  43. data/lib/active_record/connection_adapters/sqlserver/type/binary.rb +5 -4
  44. data/lib/active_record/connection_adapters/sqlserver/type/boolean.rb +3 -3
  45. data/lib/active_record/connection_adapters/sqlserver/type/char.rb +7 -4
  46. data/lib/active_record/connection_adapters/sqlserver/type/data.rb +2 -2
  47. data/lib/active_record/connection_adapters/sqlserver/type/date.rb +4 -3
  48. data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +8 -8
  49. data/lib/active_record/connection_adapters/sqlserver/type/datetime2.rb +2 -2
  50. data/lib/active_record/connection_adapters/sqlserver/type/datetimeoffset.rb +2 -2
  51. data/lib/active_record/connection_adapters/sqlserver/type/decimal.rb +5 -4
  52. data/lib/active_record/connection_adapters/sqlserver/type/decimal_without_scale.rb +22 -0
  53. data/lib/active_record/connection_adapters/sqlserver/type/float.rb +3 -3
  54. data/lib/active_record/connection_adapters/sqlserver/type/integer.rb +3 -3
  55. data/lib/active_record/connection_adapters/sqlserver/type/json.rb +2 -1
  56. data/lib/active_record/connection_adapters/sqlserver/type/money.rb +4 -4
  57. data/lib/active_record/connection_adapters/sqlserver/type/real.rb +3 -3
  58. data/lib/active_record/connection_adapters/sqlserver/type/small_integer.rb +3 -3
  59. data/lib/active_record/connection_adapters/sqlserver/type/small_money.rb +4 -4
  60. data/lib/active_record/connection_adapters/sqlserver/type/smalldatetime.rb +3 -3
  61. data/lib/active_record/connection_adapters/sqlserver/type/string.rb +2 -2
  62. data/lib/active_record/connection_adapters/sqlserver/type/text.rb +3 -3
  63. data/lib/active_record/connection_adapters/sqlserver/type/time.rb +6 -6
  64. data/lib/active_record/connection_adapters/sqlserver/type/time_value_fractional.rb +8 -9
  65. data/lib/active_record/connection_adapters/sqlserver/type/timestamp.rb +3 -3
  66. data/lib/active_record/connection_adapters/sqlserver/type/tiny_integer.rb +3 -3
  67. data/lib/active_record/connection_adapters/sqlserver/type/unicode_char.rb +5 -4
  68. data/lib/active_record/connection_adapters/sqlserver/type/unicode_string.rb +2 -2
  69. data/lib/active_record/connection_adapters/sqlserver/type/unicode_text.rb +3 -3
  70. data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar.rb +6 -5
  71. data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar_max.rb +4 -4
  72. data/lib/active_record/connection_adapters/sqlserver/type/uuid.rb +4 -3
  73. data/lib/active_record/connection_adapters/sqlserver/type/varbinary.rb +6 -5
  74. data/lib/active_record/connection_adapters/sqlserver/type/varbinary_max.rb +4 -4
  75. data/lib/active_record/connection_adapters/sqlserver/type/varchar.rb +6 -5
  76. data/lib/active_record/connection_adapters/sqlserver/type/varchar_max.rb +4 -4
  77. data/lib/active_record/connection_adapters/sqlserver/utils.rb +10 -11
  78. data/lib/active_record/connection_adapters/sqlserver/version.rb +2 -2
  79. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +145 -94
  80. data/lib/active_record/connection_adapters/sqlserver_column.rb +9 -5
  81. data/lib/active_record/sqlserver_base.rb +9 -1
  82. data/lib/active_record/tasks/sqlserver_database_tasks.rb +28 -32
  83. data/lib/activerecord-sqlserver-adapter.rb +3 -1
  84. data/lib/arel/visitors/sqlserver.rb +108 -34
  85. data/lib/arel_sqlserver.rb +4 -2
  86. data/test/appveyor/dbsetup.ps1 +4 -4
  87. data/test/cases/adapter_test_sqlserver.rb +246 -171
  88. data/test/cases/change_column_null_test_sqlserver.rb +14 -12
  89. data/test/cases/coerced_tests.rb +722 -381
  90. data/test/cases/column_test_sqlserver.rb +287 -285
  91. data/test/cases/connection_test_sqlserver.rb +17 -20
  92. data/test/cases/execute_procedure_test_sqlserver.rb +20 -20
  93. data/test/cases/fetch_test_sqlserver.rb +16 -22
  94. data/test/cases/fully_qualified_identifier_test_sqlserver.rb +15 -19
  95. data/test/cases/helper_sqlserver.rb +15 -15
  96. data/test/cases/in_clause_test_sqlserver.rb +36 -0
  97. data/test/cases/index_test_sqlserver.rb +15 -15
  98. data/test/cases/json_test_sqlserver.rb +25 -25
  99. data/test/cases/lateral_test_sqlserver.rb +35 -0
  100. data/test/cases/migration_test_sqlserver.rb +67 -27
  101. data/test/cases/optimizer_hints_test_sqlserver.rb +72 -0
  102. data/test/cases/order_test_sqlserver.rb +53 -54
  103. data/test/cases/pessimistic_locking_test_sqlserver.rb +27 -33
  104. data/test/cases/rake_test_sqlserver.rb +33 -45
  105. data/test/cases/schema_dumper_test_sqlserver.rb +115 -109
  106. data/test/cases/schema_test_sqlserver.rb +20 -26
  107. data/test/cases/scratchpad_test_sqlserver.rb +4 -4
  108. data/test/cases/showplan_test_sqlserver.rb +28 -35
  109. data/test/cases/specific_schema_test_sqlserver.rb +68 -65
  110. data/test/cases/transaction_test_sqlserver.rb +18 -20
  111. data/test/cases/trigger_test_sqlserver.rb +14 -13
  112. data/test/cases/utils_test_sqlserver.rb +70 -70
  113. data/test/cases/uuid_test_sqlserver.rb +13 -14
  114. data/test/debug.rb +8 -6
  115. data/test/migrations/create_clients_and_change_column_null.rb +3 -1
  116. data/test/migrations/transaction_table/1_table_will_never_be_created.rb +4 -4
  117. data/test/models/sqlserver/booking.rb +3 -1
  118. data/test/models/sqlserver/customers_view.rb +3 -1
  119. data/test/models/sqlserver/datatype.rb +2 -0
  120. data/test/models/sqlserver/datatype_migration.rb +2 -0
  121. data/test/models/sqlserver/dollar_table_name.rb +3 -1
  122. data/test/models/sqlserver/edge_schema.rb +3 -3
  123. data/test/models/sqlserver/fk_has_fk.rb +3 -1
  124. data/test/models/sqlserver/fk_has_pk.rb +3 -1
  125. data/test/models/sqlserver/natural_pk_data.rb +4 -2
  126. data/test/models/sqlserver/natural_pk_int_data.rb +3 -1
  127. data/test/models/sqlserver/no_pk_data.rb +3 -1
  128. data/test/models/sqlserver/object_default.rb +3 -1
  129. data/test/models/sqlserver/quoted_table.rb +4 -2
  130. data/test/models/sqlserver/quoted_view_1.rb +3 -1
  131. data/test/models/sqlserver/quoted_view_2.rb +3 -1
  132. data/test/models/sqlserver/sst_memory.rb +3 -1
  133. data/test/models/sqlserver/string_default.rb +3 -1
  134. data/test/models/sqlserver/string_defaults_big_view.rb +3 -1
  135. data/test/models/sqlserver/string_defaults_view.rb +3 -1
  136. data/test/models/sqlserver/tinyint_pk.rb +3 -1
  137. data/test/models/sqlserver/trigger.rb +4 -2
  138. data/test/models/sqlserver/trigger_history.rb +3 -1
  139. data/test/models/sqlserver/upper.rb +3 -1
  140. data/test/models/sqlserver/uppered.rb +3 -1
  141. data/test/models/sqlserver/uuid.rb +3 -1
  142. data/test/schema/sqlserver_specific_schema.rb +31 -21
  143. data/test/support/coerceable_test_sqlserver.rb +15 -9
  144. data/test/support/connection_reflection.rb +3 -2
  145. data/test/support/core_ext/query_cache.rb +4 -1
  146. data/test/support/load_schema_sqlserver.rb +5 -5
  147. data/test/support/minitest_sqlserver.rb +3 -1
  148. data/test/support/paths_sqlserver.rb +11 -11
  149. data/test/support/rake_helpers.rb +13 -10
  150. data/test/support/sql_counter_sqlserver.rb +3 -4
  151. data/test/support/test_in_memory_oltp.rb +9 -7
  152. metadata +27 -12
  153. data/.travis.yml +0 -25
@@ -1,20 +1,32 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module SQLServer
4
6
  class SchemaCreation < AbstractAdapter::SchemaCreation
5
-
6
7
  private
7
8
 
8
9
  def visit_TableDefinition(o)
10
+ if_not_exists = o.if_not_exists
11
+
9
12
  if o.as
10
13
  table_name = quote_table_name(o.temporary ? "##{o.name}" : o.name)
11
14
  query = o.as.respond_to?(:to_sql) ? o.as.to_sql : o.as
12
15
  projections, source = query.match(%r{SELECT\s+(.*)?\s+FROM\s+(.*)?}).captures
13
- select_into = "SELECT #{projections} INTO #{table_name} FROM #{source}"
16
+ sql = "SELECT #{projections} INTO #{table_name} FROM #{source}"
14
17
  else
15
18
  o.instance_variable_set :@as, nil
16
- super
19
+ o.instance_variable_set :@if_not_exists, false
20
+ sql = super
17
21
  end
22
+
23
+ if if_not_exists
24
+ o.instance_variable_set :@if_not_exists, true
25
+ table_name = o.temporary ? "##{o.name}" : o.name
26
+ sql = "IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='#{table_name}' and xtype='U') #{sql}"
27
+ end
28
+
29
+ sql
18
30
  end
19
31
 
20
32
  def add_column_options!(sql, options)
@@ -34,7 +46,7 @@ module ActiveRecord
34
46
  def action_sql(action, dependency)
35
47
  case dependency
36
48
  when :restrict
37
- raise ArgumentError, <<-MSG.strip_heredoc
49
+ raise ArgumentError, <<~MSG.squish
38
50
  '#{dependency}' is not supported for :on_update or :on_delete.
39
51
  Supported values are: :nullify, :cascade
40
52
  MSG
@@ -50,7 +62,6 @@ module ActiveRecord
50
62
  def options_primary_key_with_nil_default?(options)
51
63
  options[:primary_key] && options.include?(:default) && options[:default].nil?
52
64
  end
53
-
54
65
  end
55
66
  end
56
67
  end
@@ -1,14 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module SQLServer
4
6
  class SchemaDumper < ConnectionAdapters::SchemaDumper
5
-
6
7
  SQLSEVER_NO_LIMIT_TYPES = [
7
- 'text',
8
- 'ntext',
9
- 'varchar(max)',
10
- 'nvarchar(max)',
11
- 'varbinary(max)'
8
+ "text",
9
+ "ntext",
10
+ "varchar(max)",
11
+ "nvarchar(max)",
12
+ "varbinary(max)"
12
13
  ].freeze
13
14
 
14
15
  private
@@ -19,18 +20,19 @@ module ActiveRecord
19
20
 
20
21
  def schema_limit(column)
21
22
  return if SQLSEVER_NO_LIMIT_TYPES.include?(column.sql_type)
23
+
22
24
  super
23
25
  end
24
26
 
25
27
  def schema_collation(column)
26
28
  return unless column.collation
29
+
27
30
  column.collation if column.collation != @connection.collation
28
31
  end
29
32
 
30
33
  def default_primary_key?(column)
31
34
  super && column.is_primary? && column.is_identity?
32
35
  end
33
-
34
36
  end
35
37
  end
36
38
  end
@@ -1,27 +1,28 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module SQLServer
4
6
  module SchemaStatements
5
-
6
7
  def native_database_types
7
8
  @native_database_types ||= initialize_native_database_types.freeze
8
9
  end
9
10
 
10
- def create_table(table_name, comment: nil, **options)
11
+ def create_table(table_name, **options)
11
12
  res = super
12
13
  clear_cache!
13
14
  res
14
15
  end
15
16
 
16
- def drop_table(table_name, options = {})
17
+ def drop_table(table_name, **options)
17
18
  # Mimic CASCADE option as best we can.
18
19
  if options[:force] == :cascade
19
20
  execute_procedure(:sp_fkeys, pktable_name: table_name).each do |fkdata|
20
- fktable = fkdata['FKTABLE_NAME']
21
- fkcolmn = fkdata['FKCOLUMN_NAME']
22
- pktable = fkdata['PKTABLE_NAME']
23
- pkcolmn = fkdata['PKCOLUMN_NAME']
24
- remove_foreign_key fktable, name: fkdata['FK_NAME']
21
+ fktable = fkdata["FKTABLE_NAME"]
22
+ fkcolmn = fkdata["FKCOLUMN_NAME"]
23
+ pktable = fkdata["PKTABLE_NAME"]
24
+ pkcolmn = fkdata["PKCOLUMN_NAME"]
25
+ remove_foreign_key fktable, name: fkdata["FK_NAME"]
25
26
  do_execute "DELETE FROM #{quote_table_name(fktable)} WHERE #{quote_column_name(fkcolmn)} IN ( SELECT #{quote_column_name(pkcolmn)} FROM #{quote_table_name(pktable)} )"
26
27
  end
27
28
  end
@@ -47,11 +48,11 @@ module ActiveRecord
47
48
  orders = {}
48
49
  columns = []
49
50
 
50
- index[:index_keys].split(',').each do |column|
51
+ index[:index_keys].split(",").each do |column|
51
52
  column.strip!
52
53
 
53
- if column.ends_with?('(-)')
54
- column.gsub! '(-)', ''
54
+ if column.ends_with?("(-)")
55
+ column.gsub! "(-)", ""
55
56
  orders[column] = :desc
56
57
  end
57
58
 
@@ -65,15 +66,15 @@ module ActiveRecord
65
66
 
66
67
  def columns(table_name)
67
68
  return [] if table_name.blank?
69
+
68
70
  column_definitions(table_name).map do |ci|
69
- sqlserver_options = ci.slice :ordinal_position, :is_primary, :is_identity
71
+ sqlserver_options = ci.slice :ordinal_position, :is_primary, :is_identity, :table_name
70
72
  sql_type_metadata = fetch_type_metadata ci[:type], sqlserver_options
71
73
  new_column(
72
74
  ci[:name],
73
75
  ci[:default_value],
74
76
  sql_type_metadata,
75
77
  ci[:null],
76
- ci[:table_name],
77
78
  ci[:default_function],
78
79
  ci[:collation],
79
80
  nil,
@@ -82,16 +83,16 @@ module ActiveRecord
82
83
  end
83
84
  end
84
85
 
85
- def new_column(name, default, sql_type_metadata, null, table_name, default_function = nil, collation = nil, comment = nil, sqlserver_options = {})
86
+ def new_column(name, default, sql_type_metadata, null, default_function = nil, collation = nil, comment = nil, sqlserver_options = {})
86
87
  SQLServerColumn.new(
87
88
  name,
88
89
  default,
89
90
  sql_type_metadata,
90
- null, table_name,
91
+ null,
91
92
  default_function,
92
- collation,
93
- comment,
94
- sqlserver_options
93
+ collation: collation,
94
+ comment: comment,
95
+ **sqlserver_options
95
96
  )
96
97
  end
97
98
 
@@ -104,7 +105,7 @@ module ActiveRecord
104
105
  identifier = database_prefix_identifier(table_name)
105
106
  database = identifier.fully_qualified_database_quoted
106
107
  sql = %{
107
- SELECT KCU.COLUMN_NAME AS [name]
108
+ SELECT #{lowercase_schema_reflection_sql('KCU.COLUMN_NAME')} AS [name]
108
109
  FROM #{database}.INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KCU
109
110
  LEFT OUTER JOIN #{database}.INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS TC
110
111
  ON KCU.CONSTRAINT_NAME = TC.CONSTRAINT_NAME
@@ -116,12 +117,12 @@ module ActiveRecord
116
117
  AND KCU.TABLE_SCHEMA = #{identifier.schema.blank? ? 'schema_name()' : (prepared_statements ? '@1' : quote(identifier.schema))}
117
118
  AND TC.CONSTRAINT_TYPE = N'PRIMARY KEY'
118
119
  ORDER BY KCU.ORDINAL_POSITION ASC
119
- }.gsub(/[[:space:]]/, ' ')
120
+ }.gsub(/[[:space:]]/, " ")
120
121
  binds = []
121
122
  nv128 = SQLServer::Type::UnicodeVarchar.new limit: 128
122
- binds << Relation::QueryAttribute.new('TABLE_NAME', identifier.object, nv128)
123
- binds << Relation::QueryAttribute.new('TABLE_SCHEMA', identifier.schema, nv128) unless identifier.schema.blank?
124
- sp_executesql(sql, 'SCHEMA', binds).map { |r| r['name'] }
123
+ binds << Relation::QueryAttribute.new("TABLE_NAME", identifier.object, nv128)
124
+ binds << Relation::QueryAttribute.new("TABLE_SCHEMA", identifier.schema, nv128) unless identifier.schema.blank?
125
+ sp_executesql(sql, "SCHEMA", binds).map { |r| r["name"] }
125
126
  end
126
127
 
127
128
  def rename_table(table_name, new_name)
@@ -130,7 +131,8 @@ module ActiveRecord
130
131
  end
131
132
 
132
133
  def remove_column(table_name, column_name, type = nil, options = {})
133
- raise ArgumentError.new('You must specify at least one column name. Example: remove_column(:people, :first_name)') if column_name.is_a? Array
134
+ raise ArgumentError.new("You must specify at least one column name. Example: remove_column(:people, :first_name)") if column_name.is_a? Array
135
+
134
136
  remove_check_constraints(table_name, column_name)
135
137
  remove_default_constraint(table_name, column_name)
136
138
  remove_indexes(table_name, column_name)
@@ -143,18 +145,19 @@ module ActiveRecord
143
145
  column_object = schema_cache.columns(table_name).find { |c| c.name.to_s == column_name.to_s }
144
146
  without_constraints = options.key?(:default) || options.key?(:limit)
145
147
  default = if !options.key?(:default) && column_object
146
- column_object.default
147
- else
148
- options[:default]
149
- end
148
+ column_object.default
149
+ else
150
+ options[:default]
151
+ end
150
152
  if without_constraints || (column_object && column_object.type != type.to_sym)
151
153
  remove_default_constraint(table_name, column_name)
152
154
  indexes = indexes(table_name).select { |index| index.columns.include?(column_name.to_s) }
153
155
  remove_indexes(table_name, column_name)
154
156
  end
155
157
  sql_commands << "UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote_default_expression(options[:default], column_object)} WHERE #{quote_column_name(column_name)} IS NULL" if !options[:null].nil? && options[:null] == false && !options[:default].nil?
156
- sql_commands << "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} #{type_to_sql(type, limit: options[:limit], precision: options[:precision], scale: options[:scale])}"
157
- sql_commands.last << ' NOT NULL' if !options[:null].nil? && options[:null] == false
158
+ alter_command = "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} #{type_to_sql(type, limit: options[:limit], precision: options[:precision], scale: options[:scale])}"
159
+ alter_command += " NOT NULL" if !options[:null].nil? && options[:null] == false
160
+ sql_commands << alter_command
158
161
  if without_constraints
159
162
  default = quote_default_expression(default, column_object || column_for(table_name, column_name))
160
163
  sql_commands << "ALTER TABLE #{quote_table_name(table_name)} ADD CONSTRAINT #{default_constraint_name(table_name, column_name)} DEFAULT #{default} FOR #{quote_column_name(column_name)}"
@@ -171,6 +174,7 @@ module ActiveRecord
171
174
  clear_cache!
172
175
  column = column_for(table_name, column_name)
173
176
  return unless column
177
+
174
178
  remove_default_constraint(table_name, column_name)
175
179
  default = extract_new_default_value(default_or_changes)
176
180
  do_execute "ALTER TABLE #{quote_table_name(table_name)} ADD CONSTRAINT #{default_constraint_name(table_name, column_name)} DEFAULT #{quote_default_expression(default, column)} FOR #{quote_column_name(column_name)}"
@@ -180,15 +184,16 @@ module ActiveRecord
180
184
  def rename_column(table_name, column_name, new_column_name)
181
185
  clear_cache!
182
186
  identifier = SQLServer::Utils.extract_identifiers("#{table_name}.#{column_name}")
183
- execute_procedure :sp_rename, identifier.quoted, new_column_name, 'COLUMN'
187
+ execute_procedure :sp_rename, identifier.quoted, new_column_name, "COLUMN"
184
188
  rename_column_indexes(table_name, column_name, new_column_name)
185
189
  clear_cache!
186
190
  end
187
191
 
188
192
  def rename_index(table_name, old_name, new_name)
189
193
  raise ArgumentError, "Index name '#{new_name}' on table '#{table_name}' is too long; the limit is #{allowed_index_name_length} characters" if new_name.length > allowed_index_name_length
194
+
190
195
  identifier = SQLServer::Utils.extract_identifiers("#{table_name}.#{old_name}")
191
- execute_procedure :sp_rename, identifier.quoted, new_name, 'INDEX'
196
+ execute_procedure :sp_rename, identifier.quoted, new_name, "INDEX"
192
197
  end
193
198
 
194
199
  def remove_index!(table_name, index_name)
@@ -200,13 +205,13 @@ module ActiveRecord
200
205
  fk_info = execute_procedure :sp_fkeys, nil, identifier.schema, nil, identifier.object, identifier.schema
201
206
  fk_info.map do |row|
202
207
  from_table = identifier.object
203
- to_table = row['PKTABLE_NAME']
208
+ to_table = row["PKTABLE_NAME"]
204
209
  options = {
205
- name: row['FK_NAME'],
206
- column: row['FKCOLUMN_NAME'],
207
- primary_key: row['PKCOLUMN_NAME'],
208
- on_update: extract_foreign_key_action('update', row['FK_NAME']),
209
- on_delete: extract_foreign_key_action('delete', row['FK_NAME'])
210
+ name: row["FK_NAME"],
211
+ column: row["FKCOLUMN_NAME"],
212
+ primary_key: row["PKCOLUMN_NAME"],
213
+ on_update: extract_foreign_key_action("update", row["FK_NAME"]),
214
+ on_delete: extract_foreign_key_action("delete", row["FK_NAME"])
210
215
  }
211
216
  ForeignKeyDefinition.new from_table, to_table, options
212
217
  end
@@ -214,8 +219,8 @@ module ActiveRecord
214
219
 
215
220
  def extract_foreign_key_action(action, fk_name)
216
221
  case select_value("SELECT #{action}_referential_action_desc FROM sys.foreign_keys WHERE name = '#{fk_name}'")
217
- when 'CASCADE' then :cascade
218
- when 'SET_NULL' then :nullify
222
+ when "CASCADE" then :cascade
223
+ when "SET_NULL" then :nullify
219
224
  end
220
225
  end
221
226
 
@@ -223,21 +228,21 @@ module ActiveRecord
223
228
  type_limitable = %w(string integer float char nchar varchar nvarchar).include?(type.to_s)
224
229
  limit = nil unless type_limitable
225
230
  case type.to_s
226
- when 'integer'
231
+ when "integer"
227
232
  case limit
228
- when 1 then 'tinyint'
229
- when 2 then 'smallint'
230
- when 3..4, nil then 'integer'
231
- when 5..8 then 'bigint'
233
+ when 1 then "tinyint"
234
+ when 2 then "smallint"
235
+ when 3..4, nil then "integer"
236
+ when 5..8 then "bigint"
232
237
  else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with precision 0 instead.")
233
238
  end
234
- when 'datetime2'
239
+ when "datetime2"
235
240
  column_type_sql = super
236
241
  if precision
237
242
  if (0..7) === precision
238
243
  column_type_sql << "(#{precision})"
239
244
  else
240
- raise(ActiveRecordError, "The dattime2 type has precision of #{precision}. The allowed range of precision is from 0 to 7")
245
+ raise(ActiveRecordError, "The datetime2 type has precision of #{precision}. The allowed range of precision is from 0 to 7")
241
246
  end
242
247
  end
243
248
  column_type_sql
@@ -247,11 +252,11 @@ module ActiveRecord
247
252
  end
248
253
 
249
254
  def columns_for_distinct(columns, orders)
250
- order_columns = orders.reject(&:blank?).map{ |s|
251
- s = s.to_sql unless s.is_a?(String)
252
- s.gsub(/\s+(?:ASC|DESC)\b/i, '')
253
- .gsub(/\s+NULLS\s+(?:FIRST|LAST)\b/i, '')
254
- }.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" }
255
+ order_columns = orders.reject(&:blank?).map { |s|
256
+ s = s.to_sql unless s.is_a?(String)
257
+ s.gsub(/\s+(?:ASC|DESC)\b/i, "")
258
+ .gsub(/\s+NULLS\s+(?:FIRST|LAST)\b/i, "")
259
+ }.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" }
255
260
 
256
261
  (order_columns << super).join(", ")
257
262
  end
@@ -268,7 +273,7 @@ module ActiveRecord
268
273
  do_execute("UPDATE #{table_id} SET #{column_id}=#{quote(default)} WHERE #{column_id} IS NULL")
269
274
  end
270
275
  sql = "ALTER TABLE #{table_id} ALTER COLUMN #{column_id} #{type_to_sql column.type, limit: column.limit, precision: column.precision, scale: column.scale}"
271
- sql << ' NOT NULL' if !allow_null.nil? && allow_null == false
276
+ sql += " NOT NULL" if !allow_null.nil? && allow_null == false
272
277
  do_execute sql
273
278
  end
274
279
 
@@ -276,25 +281,45 @@ module ActiveRecord
276
281
  SQLServer::SchemaDumper.create(self, options)
277
282
  end
278
283
 
284
+ def create_schema(schema_name, authorization = nil)
285
+ sql = "CREATE SCHEMA [#{schema_name}]"
286
+ sql += " AUTHORIZATION [#{authorization}]" if authorization
287
+
288
+ execute sql
289
+ end
290
+
291
+ def change_table_schema(schema_name, table_name)
292
+ execute "ALTER SCHEMA [#{schema_name}] TRANSFER [#{table_name}]"
293
+ end
294
+
295
+ def drop_schema(schema_name)
296
+ execute "DROP SCHEMA [#{schema_name}]"
297
+ end
298
+
279
299
  private
280
300
 
281
301
  def data_source_sql(name = nil, type: nil)
282
302
  scope = quoted_scope name, type: type
303
+
283
304
  table_name = lowercase_schema_reflection_sql 'TABLE_NAME'
305
+ database = scope[:database].present? ? "#{scope[:database]}." : ""
306
+ table_catalog = scope[:database].present? ? quote(scope[:database]) : "DB_NAME()"
307
+
284
308
  sql = "SELECT #{table_name}"
285
- sql << ' FROM INFORMATION_SCHEMA.TABLES WITH (NOLOCK)'
286
- sql << ' WHERE TABLE_CATALOG = DB_NAME()'
287
- sql << " AND TABLE_SCHEMA = #{quote(scope[:schema])}"
288
- sql << " AND TABLE_NAME = #{quote(scope[:name])}" if scope[:name]
289
- sql << " AND TABLE_TYPE = #{quote(scope[:type])}" if scope[:type]
290
- sql << " ORDER BY #{table_name}"
309
+ sql += " FROM #{database}INFORMATION_SCHEMA.TABLES WITH (NOLOCK)"
310
+ sql += " WHERE TABLE_CATALOG = #{table_catalog}"
311
+ sql += " AND TABLE_SCHEMA = #{quote(scope[:schema])}"
312
+ sql += " AND TABLE_NAME = #{quote(scope[:name])}" if scope[:name]
313
+ sql += " AND TABLE_TYPE = #{quote(scope[:type])}" if scope[:type]
314
+ sql += " ORDER BY #{table_name}"
291
315
  sql
292
316
  end
293
317
 
294
318
  def quoted_scope(name = nil, type: nil)
295
319
  identifier = SQLServer::Utils.extract_identifiers(name)
296
320
  {}.tap do |scope|
297
- scope[:schema] = identifier.schema || 'dbo'
321
+ scope[:database] = identifier.database if identifier.database
322
+ scope[:schema] = identifier.schema || "dbo"
298
323
  scope[:name] = identifier.object if identifier.object
299
324
  scope[:type] = type if type
300
325
  end
@@ -304,37 +329,37 @@ module ActiveRecord
304
329
 
305
330
  def initialize_native_database_types
306
331
  {
307
- primary_key: 'bigint NOT NULL IDENTITY(1,1) PRIMARY KEY',
308
- primary_key_nonclustered: 'int NOT NULL IDENTITY(1,1) PRIMARY KEY NONCLUSTERED',
309
- integer: { name: 'int', limit: 4 },
310
- bigint: { name: 'bigint' },
311
- boolean: { name: 'bit' },
312
- decimal: { name: 'decimal' },
313
- money: { name: 'money' },
314
- smallmoney: { name: 'smallmoney' },
315
- float: { name: 'float' },
316
- real: { name: 'real' },
317
- date: { name: 'date' },
318
- datetime: { name: 'datetime' },
319
- datetime2: { name: 'datetime2' },
320
- datetimeoffset: { name: 'datetimeoffset' },
321
- smalldatetime: { name: 'smalldatetime' },
322
- timestamp: { name: 'datetime' },
323
- time: { name: 'time' },
324
- char: { name: 'char' },
325
- varchar: { name: 'varchar', limit: 8000 },
326
- varchar_max: { name: 'varchar(max)' },
327
- text_basic: { name: 'text' },
328
- nchar: { name: 'nchar' },
329
- string: { name: 'nvarchar', limit: 4000 },
330
- text: { name: 'nvarchar(max)' },
331
- ntext: { name: 'ntext' },
332
- binary_basic: { name: 'binary' },
333
- varbinary: { name: 'varbinary', limit: 8000 },
334
- binary: { name: 'varbinary(max)' },
335
- uuid: { name: 'uniqueidentifier' },
336
- ss_timestamp: { name: 'timestamp' },
337
- json: { name: 'nvarchar(max)' }
332
+ primary_key: "bigint NOT NULL IDENTITY(1,1) PRIMARY KEY",
333
+ primary_key_nonclustered: "int NOT NULL IDENTITY(1,1) PRIMARY KEY NONCLUSTERED",
334
+ integer: { name: "int", limit: 4 },
335
+ bigint: { name: "bigint" },
336
+ boolean: { name: "bit" },
337
+ decimal: { name: "decimal" },
338
+ money: { name: "money" },
339
+ smallmoney: { name: "smallmoney" },
340
+ float: { name: "float" },
341
+ real: { name: "real" },
342
+ date: { name: "date" },
343
+ datetime: { name: "datetime" },
344
+ datetime2: { name: "datetime2" },
345
+ datetimeoffset: { name: "datetimeoffset" },
346
+ smalldatetime: { name: "smalldatetime" },
347
+ timestamp: { name: "datetime" },
348
+ time: { name: "time" },
349
+ char: { name: "char" },
350
+ varchar: { name: "varchar", limit: 8000 },
351
+ varchar_max: { name: "varchar(max)" },
352
+ text_basic: { name: "text" },
353
+ nchar: { name: "nchar" },
354
+ string: { name: "nvarchar", limit: 4000 },
355
+ text: { name: "nvarchar(max)" },
356
+ ntext: { name: "ntext" },
357
+ binary_basic: { name: "binary" },
358
+ varbinary: { name: "varbinary", limit: 8000 },
359
+ binary: { name: "varbinary(max)" },
360
+ uuid: { name: "uniqueidentifier" },
361
+ ss_timestamp: { name: "timestamp" },
362
+ json: { name: "nvarchar(max)" }
338
363
  }
339
364
  end
340
365
 
@@ -343,60 +368,14 @@ module ActiveRecord
343
368
  database = identifier.fully_qualified_database_quoted
344
369
  view_exists = view_exists?(table_name)
345
370
  view_tblnm = view_table_name(table_name) if view_exists
346
- sql = %{
347
- SELECT DISTINCT
348
- #{lowercase_schema_reflection_sql('columns.TABLE_NAME')} AS table_name,
349
- #{lowercase_schema_reflection_sql('columns.COLUMN_NAME')} AS name,
350
- columns.DATA_TYPE AS type,
351
- columns.COLUMN_DEFAULT AS default_value,
352
- columns.NUMERIC_SCALE AS numeric_scale,
353
- columns.NUMERIC_PRECISION AS numeric_precision,
354
- columns.DATETIME_PRECISION AS datetime_precision,
355
- columns.COLLATION_NAME AS [collation],
356
- columns.ordinal_position,
357
- CASE
358
- WHEN columns.DATA_TYPE IN ('nchar','nvarchar','char','varchar') THEN columns.CHARACTER_MAXIMUM_LENGTH
359
- ELSE COL_LENGTH('#{database}.'+columns.TABLE_SCHEMA+'.'+columns.TABLE_NAME, columns.COLUMN_NAME)
360
- END AS [length],
361
- CASE
362
- WHEN columns.IS_NULLABLE = 'YES' THEN 1
363
- ELSE NULL
364
- END AS [is_nullable],
365
- CASE
366
- WHEN KCU.COLUMN_NAME IS NOT NULL AND TC.CONSTRAINT_TYPE = N'PRIMARY KEY' THEN 1
367
- ELSE NULL
368
- END AS [is_primary],
369
- c.is_identity AS [is_identity]
370
- FROM #{database}.INFORMATION_SCHEMA.COLUMNS columns
371
- LEFT OUTER JOIN #{database}.INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS TC
372
- ON TC.TABLE_NAME = columns.TABLE_NAME
373
- AND TC.TABLE_SCHEMA = columns.TABLE_SCHEMA
374
- AND TC.CONSTRAINT_TYPE = N'PRIMARY KEY'
375
- LEFT OUTER JOIN #{database}.INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KCU
376
- ON KCU.COLUMN_NAME = columns.COLUMN_NAME
377
- AND KCU.CONSTRAINT_NAME = TC.CONSTRAINT_NAME
378
- AND KCU.CONSTRAINT_CATALOG = TC.CONSTRAINT_CATALOG
379
- AND KCU.CONSTRAINT_SCHEMA = TC.CONSTRAINT_SCHEMA
380
- INNER JOIN #{database}.sys.schemas AS s
381
- ON s.name = columns.TABLE_SCHEMA
382
- AND s.schema_id = s.schema_id
383
- INNER JOIN #{database}.sys.objects AS o
384
- ON s.schema_id = o.schema_id
385
- AND o.is_ms_shipped = 0
386
- AND o.type IN ('U', 'V')
387
- AND o.name = columns.TABLE_NAME
388
- INNER JOIN #{database}.sys.columns AS c
389
- ON o.object_id = c.object_id
390
- AND c.name = columns.COLUMN_NAME
391
- WHERE columns.TABLE_NAME = #{prepared_statements ? '@0' : quote(identifier.object)}
392
- AND columns.TABLE_SCHEMA = #{identifier.schema.blank? ? 'schema_name()' : (prepared_statements ? '@1' : quote(identifier.schema))}
393
- ORDER BY columns.ordinal_position
394
- }.gsub(/[ \t\r\n]+/, ' ').strip
371
+
372
+ sql = column_definitions_sql(database, identifier)
373
+
395
374
  binds = []
396
375
  nv128 = SQLServer::Type::UnicodeVarchar.new limit: 128
397
- binds << Relation::QueryAttribute.new('TABLE_NAME', identifier.object, nv128)
398
- binds << Relation::QueryAttribute.new('TABLE_SCHEMA', identifier.schema, nv128) unless identifier.schema.blank?
399
- results = sp_executesql(sql, 'SCHEMA', binds)
376
+ binds << Relation::QueryAttribute.new("TABLE_NAME", identifier.object, nv128)
377
+ binds << Relation::QueryAttribute.new("TABLE_SCHEMA", identifier.schema, nv128) unless identifier.schema.blank?
378
+ results = sp_executesql(sql, "SCHEMA", binds)
400
379
  results.map do |ci|
401
380
  ci = ci.symbolize_keys
402
381
  ci[:_type] = ci[:type]
@@ -427,7 +406,7 @@ module ActiveRecord
427
406
  WHERE
428
407
  c.TABLE_NAME = '#{view_tblnm}'
429
408
  AND c.COLUMN_NAME = '#{views_real_column_name(table_name, ci[:name])}'
430
- }.squish, 'SCHEMA'
409
+ }.squish, "SCHEMA"
431
410
  end
432
411
  case default
433
412
  when nil
@@ -446,7 +425,7 @@ module ActiveRecord
446
425
  else ci[:type]
447
426
  end
448
427
  value = default.match(/\A\((.*)\)\Z/m)[1]
449
- value = select_value("SELECT CAST(#{value} AS #{type}) AS value", 'SCHEMA')
428
+ value = select_value("SELECT CAST(#{value} AS #{type}) AS value", "SCHEMA")
450
429
  [value, nil]
451
430
  end
452
431
  end
@@ -458,8 +437,76 @@ module ActiveRecord
458
437
  end
459
438
  end
460
439
 
440
+ def column_definitions_sql(database, identifier)
441
+ object_name = prepared_statements ? "@0" : quote(identifier.object)
442
+ schema_name = if identifier.schema.blank?
443
+ "schema_name()"
444
+ else
445
+ prepared_statements ? "@1" : quote(identifier.schema)
446
+ end
447
+
448
+ %{
449
+ SELECT
450
+ #{lowercase_schema_reflection_sql('o.name')} AS [table_name],
451
+ #{lowercase_schema_reflection_sql('c.name')} AS [name],
452
+ t.name AS [type],
453
+ d.definition AS [default_value],
454
+ CASE
455
+ WHEN t.name IN ('decimal', 'bigint', 'int', 'money', 'numeric', 'smallint', 'smallmoney', 'tinyint')
456
+ THEN c.scale
457
+ END AS [numeric_scale],
458
+ CASE
459
+ WHEN t.name IN ('decimal', 'bigint', 'int', 'money', 'numeric', 'smallint', 'smallmoney', 'tinyint', 'real', 'float')
460
+ THEN c.precision
461
+ END AS [numeric_precision],
462
+ CASE
463
+ WHEN t.name IN ('date', 'datetime', 'datetime2', 'datetimeoffset', 'smalldatetime', 'time')
464
+ THEN c.scale
465
+ END AS [datetime_precision],
466
+ c.collation_name AS [collation],
467
+ ROW_NUMBER() OVER (ORDER BY c.column_id) AS [ordinal_position],
468
+ CASE
469
+ WHEN t.name IN ('nchar', 'nvarchar') AND c.max_length > 0
470
+ THEN c.max_length / 2
471
+ ELSE c.max_length
472
+ END AS [length],
473
+ CASE c.is_nullable
474
+ WHEN 1
475
+ THEN 1
476
+ END AS [is_nullable],
477
+ CASE
478
+ WHEN ic.object_id IS NOT NULL
479
+ THEN 1
480
+ END AS [is_primary],
481
+ c.is_identity AS [is_identity]
482
+ FROM #{database}.sys.columns c
483
+ INNER JOIN #{database}.sys.objects o
484
+ ON c.object_id = o.object_id
485
+ INNER JOIN #{database}.sys.schemas s
486
+ ON o.schema_id = s.schema_id
487
+ INNER JOIN #{database}.sys.types t
488
+ ON c.system_type_id = t.system_type_id
489
+ AND c.user_type_id = t.user_type_id
490
+ LEFT OUTER JOIN #{database}.sys.default_constraints d
491
+ ON c.object_id = d.parent_object_id
492
+ AND c.default_object_id = d.object_id
493
+ LEFT OUTER JOIN #{database}.sys.key_constraints k
494
+ ON c.object_id = k.parent_object_id
495
+ AND k.type = 'PK'
496
+ LEFT OUTER JOIN #{database}.sys.index_columns ic
497
+ ON k.parent_object_id = ic.object_id
498
+ AND k.unique_index_id = ic.index_id
499
+ AND c.column_id = ic.column_id
500
+ WHERE
501
+ o.name = #{object_name}
502
+ AND s.name = #{schema_name}
503
+ ORDER BY
504
+ c.column_id
505
+ }.gsub(/[ \t\r\n]+/, " ").strip
506
+ end
507
+
461
508
  def remove_check_constraints(table_name, column_name)
462
- constraints = select_values "SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE where TABLE_NAME = '#{quote_string(table_name)}' and COLUMN_NAME = '#{quote_string(column_name)}'", 'SCHEMA'
509
+ constraints = select_values "SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE where TABLE_NAME = '#{quote_string(table_name)}' and COLUMN_NAME = '#{quote_string(column_name)}'", "SCHEMA"
463
510
  constraints.each do |constraint|
464
511
  do_execute "ALTER TABLE #{quote_table_name(table_name)} DROP CONSTRAINT #{quote_column_name(constraint)}"
465
512
  end
@@ -467,8 +514,8 @@ module ActiveRecord
467
514
 
468
515
  def remove_default_constraint(table_name, column_name)
469
516
  # If their are foreign keys in this table, we could still get back a 2D array, so flatten just in case.
470
- execute_procedure(:sp_helpconstraint, table_name, 'nomsg').flatten.select do |row|
471
- row['constraint_type'] == "DEFAULT on column #{column_name}"
517
+ execute_procedure(:sp_helpconstraint, table_name, "nomsg").flatten.select do |row|
518
+ row["constraint_type"] == "DEFAULT on column #{column_name}"
472
519
  end.each do |row|
473
520
  do_execute "ALTER TABLE #{quote_table_name(table_name)} DROP CONSTRAINT #{row['constraint_name']}"
474
521
  end
@@ -484,12 +531,12 @@ module ActiveRecord
484
531
 
485
532
  def get_table_name(sql)
486
533
  tn = if sql =~ /^\s*(INSERT|EXEC sp_executesql N'INSERT)(\s+INTO)?\s+([^\(\s]+)\s*|^\s*update\s+([^\(\s]+)\s*/i
487
- Regexp.last_match[3] || Regexp.last_match[4]
488
- elsif sql =~ /FROM\s+([^\(\s]+)\s*/i
489
- Regexp.last_match[1]
490
- else
491
- nil
492
- end
534
+ Regexp.last_match[3] || Regexp.last_match[4]
535
+ elsif sql =~ /FROM\s+([^\(\s]+)\s*/i
536
+ Regexp.last_match[1]
537
+ else
538
+ nil
539
+ end
493
540
  SQLServer::Utils.extract_identifiers(tn).object
494
541
  end
495
542
 
@@ -505,22 +552,22 @@ module ActiveRecord
505
552
 
506
553
  def view_table_name(table_name)
507
554
  view_info = view_information(table_name)
508
- view_info ? get_table_name(view_info['VIEW_DEFINITION']) : table_name
555
+ view_info ? get_table_name(view_info["VIEW_DEFINITION"]) : table_name
509
556
  end
510
557
 
511
558
  def view_information(table_name)
512
559
  @view_information ||= {}
513
560
  @view_information[table_name] ||= begin
514
561
  identifier = SQLServer::Utils.extract_identifiers(table_name)
515
- view_info = select_one "SELECT * FROM INFORMATION_SCHEMA.VIEWS WITH (NOLOCK) WHERE TABLE_NAME = #{quote(identifier.object)}", 'SCHEMA'
562
+ view_info = select_one "SELECT * FROM INFORMATION_SCHEMA.VIEWS WITH (NOLOCK) WHERE TABLE_NAME = #{quote(identifier.object)}", "SCHEMA"
516
563
  if view_info
517
564
  view_info = view_info.with_indifferent_access
518
565
  if view_info[:VIEW_DEFINITION].blank? || view_info[:VIEW_DEFINITION].length == 4000
519
566
  view_info[:VIEW_DEFINITION] = begin
520
- select_values("EXEC sp_helptext #{identifier.object_quoted}", 'SCHEMA').join
521
- rescue
522
- warn "No view definition found, possible permissions problem.\nPlease run GRANT VIEW DEFINITION TO your_user;"
523
- nil
567
+ select_values("EXEC sp_helptext #{identifier.object_quoted}", "SCHEMA").join
568
+ rescue
569
+ warn "No view definition found, possible permissions problem.\nPlease run GRANT VIEW DEFINITION TO your_user;"
570
+ nil
524
571
  end
525
572
  end
526
573
  end
@@ -531,14 +578,14 @@ module ActiveRecord
531
578
  def views_real_column_name(table_name, column_name)
532
579
  view_definition = view_information(table_name)[:VIEW_DEFINITION]
533
580
  return column_name unless view_definition
581
+
534
582
  match_data = view_definition.match(/([\w-]*)\s+as\s+#{column_name}/im)
535
583
  match_data ? match_data[1] : column_name
536
584
  end
537
585
 
538
- def create_table_definition(*args)
539
- SQLServer::TableDefinition.new(*args)
586
+ def create_table_definition(*args, **options)
587
+ SQLServer::TableDefinition.new(self, *args, **options)
540
588
  end
541
-
542
589
  end
543
590
  end
544
591
  end