Skip to content

Instantly share code, notes, and snippets.

@gnarfle
Created October 27, 2011 17:22
Show Gist options
  • Save gnarfle/1320194 to your computer and use it in GitHub Desktop.
Save gnarfle/1320194 to your computer and use it in GitHub Desktop.
MonkeyPatch sqlserver adapter to allow inserts on primary key columns
module ActiveRecord
module ConnectionAdapters
module Sqlserver
module SchemaStatements
def identity_column(table_name)
columns(table_name).detect(&:is_identity?)
end
def column_definitions(table_name)
db_name = unqualify_db_name(table_name)
db_name_with_period = "#{db_name}." if db_name
table_schema = unqualify_table_schema(table_name)
table_name = unqualify_table_name(table_name)
sql = %{
SELECT DISTINCT
#{lowercase_schema_reflection_sql('columns.TABLE_NAME')} AS table_name,
#{lowercase_schema_reflection_sql('columns.COLUMN_NAME')} AS name,
columns.DATA_TYPE AS type,
columns.COLUMN_DEFAULT AS default_value,
columns.NUMERIC_SCALE AS numeric_scale,
columns.NUMERIC_PRECISION AS numeric_precision,
columns.ordinal_position,
CASE
WHEN columns.DATA_TYPE IN ('nchar','nvarchar') THEN columns.CHARACTER_MAXIMUM_LENGTH
ELSE COL_LENGTH(columns.TABLE_SCHEMA+'.'+columns.TABLE_NAME, columns.COLUMN_NAME)
END AS [length],
CASE
WHEN columns.IS_NULLABLE = 'YES' THEN 1
ELSE NULL
END AS [is_nullable],
CASE
WHEN COLUMNPROPERTY(OBJECT_ID(columns.TABLE_SCHEMA+'.'+columns.TABLE_NAME), columns.COLUMN_NAME, 'IsIdentity') = 1 THEN 1
ELSE NULL
END AS [is_identity]
FROM #{db_name_with_period}INFORMATION_SCHEMA.COLUMNS columns
LEFT OUTER JOIN #{db_name_with_period}INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS TC ON TC.TABLE_NAME = columns.TABLE_NAME AND TC.CONSTRAINT_TYPE = N'PRIMARY KEY'
LEFT OUTER JOIN #{db_name_with_period}INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS CCU ON TC.CONSTRAINT_NAME = CCU.CONSTRAINT_NAME AND CCU.COLUMN_NAME = columns.COLUMN_NAME
WHERE columns.TABLE_NAME = @0
AND columns.TABLE_SCHEMA = #{table_schema.blank? ? "schema_name()" : "@1"}
ORDER BY columns.ordinal_position
}.gsub(/[ \t\r\n]+/,' ')
binds = [['table_name', table_name]]
binds << ['table_schema',table_schema] unless table_schema.blank?
results = info_schema_query { do_exec_query(sql, 'InfoSchema::ColumnDefinitions', binds) }
results.collect do |ci|
ci = ci.symbolize_keys
ci[:type] = case ci[:type]
when /^bit|image|text|ntext|datetime$/
ci[:type]
when /^numeric|decimal$/i
"#{ci[:type]}(#{ci[:numeric_precision]},#{ci[:numeric_scale]})"
when /^float|real$/i
"#{ci[:type]}(#{ci[:numeric_precision]})"
when /^char|nchar|varchar|nvarchar|varbinary|bigint|int|smallint$/
ci[:length].to_i == -1 ? "#{ci[:type]}(max)" : "#{ci[:type]}(#{ci[:length]})"
else
ci[:type]
end
if ci[:default_value].nil? && views.include?(table_name)
real_table_name = table_name_or_views_table_name(table_name)
real_column_name = views_real_column_name(table_name,ci[:name])
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}'"
ci[:default_value] = info_schema_query { select_value(col_default_sql) }
end
ci[:default_value] = case ci[:default_value]
when nil, '(null)', '(NULL)'
nil
when /\A\((\w+\(\))\)\Z/
ci[:default_function] = $1
nil
else
match_data = ci[:default_value].match(/\A\(+N?'?(.*?)'?\)+\Z/m)
match_data ? match_data[1] : nil
end
ci[:null] = ci[:is_nullable].to_i == 1 ; ci.delete(:is_nullable)
ci[:is_identity] = ci[:is_identity].to_i == 1
ci
end
end
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment