Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Add MSSQL support for :cascade option in drop_column #518

Merged
merged 1 commit into from

2 participants

@munkyboy

When :cascade option is given to #drop_column, the MSSQL adapter will attempt to remove the default value constraint before dropping the column.

@jeremyevans
Owner

I think it's probably best to not require a separate :cascade option. Anytime you are dropping the column, you are going to want to drop the constraint. On all other databases, dropping a column with default does not require a separate option, so I don't think it should require one on MSSQL.

This is going to conflict with one of my local patches that I'm currently testing, but I'll merge it and fix the conflicts.

Thanks for the help!

@munkyboy

I agree. I felt weird writing this test

@jeremyevans

These lines use Symbol#[]. That is part of the core extensions, which should not be used internally. Even then, it only works on ruby 1.8 (as ruby 1.9 adds Symbol#[] and Sequel doesn't override it).

I've made some post 3.37.0 changes so that the specs aren't run with the core extensions, which will make it easier to catch internal usage.

@jeremyevans jeremyevans merged commit c956375 into jeremyevans:master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jul 16, 2012
This page is out of date. Refresh to see the latest.
Showing with 65 additions and 11 deletions.
  1. +18 −11 lib/sequel/adapters/shared/mssql.rb
  2. +47 −0 spec/adapters/mssql_spec.rb
View
29 lib/sequel/adapters/shared/mssql.rb
@@ -93,7 +93,7 @@ def tables(opts={})
def views(opts={})
information_schema_tables('VIEW', opts)
end
-
+
private
# MSSQL uses the IDENTITY(1,1) column for autoincrementing columns.
@@ -106,6 +106,13 @@ def alter_table_sql(table, op)
case op[:op]
when :add_column
"ALTER TABLE #{quote_schema_table(table)} ADD #{column_definition_sql(op)}"
+ when :drop_column
+ sqls = []
+ if op[:cascade] && constraint_name = default_constraint_name(table, op[:name])
+ sqls << alter_table_sql(table, :op => :drop_constraint, :name => constraint_name)
+ end
+ sqls << "ALTER TABLE #{quote_schema_table(table)} DROP COLUMN #{quote_identifier(op[:name])}"
+ sqls
when :rename_column
"sp_rename #{literal("#{quote_schema_table(table)}.#{quote_identifier(op[:name])}")}, #{literal(op[:new_name].to_s)}, 'COLUMN'"
when :set_column_type
@@ -114,7 +121,7 @@ def alter_table_sql(table, op)
if cs = sch.each{|k, v| break v if k == op[:name]; nil}
cs = cs.dup
if constraint = default_constraint_name(table, op[:name])
- sqls << "ALTER TABLE #{quote_schema_table(table)} DROP CONSTRAINT #{constraint}"
+ sqls << alter_table_sql(table, :op => :drop_constraint, :name => constraint_name)
end
cs[:default] = cs[:ruby_default]
op = cs.merge!(op)
@@ -176,15 +183,15 @@ def create_table_as(name, ds, options)
end
# The name of the constraint for setting the default value on the table and column.
- def default_constraint_name(table, column)
- from(:sysobjects___c_obj).
- join(:syscomments___com, :id=>:id).
- join(:sysobjects___t_obj, :id=>:c_obj__parent_obj).
- join(:sysconstraints___con, :constid=>:c_obj__id).
- join(:syscolumns___col, :id=>:t_obj__id, :colid=>:colid).
- where{{c_obj__uid=>user_id{}}}.
- where(:c_obj__xtype=>'D', :t_obj__name=>table.to_s, :col__name=>column.to_s).
- get(:c_obj__name)
+ # The SQL used to select default constraints utilizes MSSQL catalog views which were introduced in 2005.
+ # This method intentionally does not support MSSQL 2000.
+ def default_constraint_name(table, column_name)
+ return nil unless server_version >= 9000000
+ table_name = schema_and_table(table).compact.join('.')
+ self[:sys__default_constraints].
+ where(:parent_object_id => :object_id[table_name]).
+ and(:col_name[:parent_object_id, :parent_column_id] => column_name.to_s).
+ get(:name)
end
# The SQL to drop an index for the table.
View
47 spec/adapters/mssql_spec.rb
@@ -542,3 +542,50 @@ def transaction(opts={})
@db.indexes(@table_name).should have_key("#{@table_name}_col1_index".to_sym)
end
end
+
+describe "MSSQL::Database#drop_column" do
+ let(:table_name) { :items }
+
+ after do
+ MSSQL_DB.drop_table(table_name)
+ end
+
+ context "when using the :cascade option" do
+ specify "drops columns with a default value" do
+ MSSQL_DB.create_table!(table_name){ Integer :id; String :name, :default => 'widget' }
+ expect { MSSQL_DB.drop_column(table_name, :name, :cascade => true) }.to_not raise_error
+ MSSQL_DB[table_name].columns.should_not include(:name)
+ end
+
+ specify "drops columns without a default value" do
+ MSSQL_DB.create_table!(table_name){ Integer :id; String :name }
+ expect { MSSQL_DB.drop_column(table_name, :name, :cascade => true) }.to_not raise_error
+ MSSQL_DB[table_name].columns.should_not include(:name)
+ end
+
+ context "with a schema namespace" do
+ before(:all) do
+ MSSQL_DB.execute_ddl "create schema test"
+ end
+ after(:all) do
+ MSSQL_DB.execute_ddl "drop schema test"
+ end
+
+ let(:table_name) { :test__items }
+
+ specify "drops columns with a default value" do
+ MSSQL_DB.create_table!(table_name){ Integer :id; String :name, :default => 'widget' }
+ expect { MSSQL_DB.drop_column(table_name, :name, :cascade => true) }.to_not raise_error
+ MSSQL_DB[table_name].columns.should_not include(:name)
+ end
+ end
+ end
+
+ context "when not using the :cascade option" do
+ specify "can not drop columns with a default value" do
+ MSSQL_DB.create_table!(table_name){ Integer :id; String :name, :default => 'widget' }
+ expect { MSSQL_DB.drop_column(table_name, :name) }.to raise_error
+ MSSQL_DB[table_name].columns.should include(:name)
+ end
+ end
+end
Something went wrong with that request. Please try again.