Skip to content

Commit

Permalink
Added a log_info_schema_queries class attribute and make all queries …
Browse files Browse the repository at this point in the history
…to INFORMATION_SCHEMA silent by default.
  • Loading branch information
metaskills committed Jan 5, 2009
1 parent e576fcc commit 2a76eea
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 13 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG
@@ -1,6 +1,9 @@

MASTER

* Added a log_info_schema_queries class attribute and make all queries to INFORMATION_SCHEMA silent by
default. [Ken Collins]

* Fix millisecond support in datetime columns. ODBC::Timestamp incorrectly takes SQL Server milliseconds
and applies them as nanoseconds. We cope with this at the DBI layer by using SQLServerDBI::Type::SqlserverTimestamp
class to parse the before type cast value appropriately. Also update the adapters #quoted_date method
Expand Down
9 changes: 8 additions & 1 deletion README.rdoc
Expand Up @@ -58,7 +58,7 @@ To pass the ActiveRecord tests we had to implement an class accessor for the nat
* SQL Server 2000 is 'text'
* SQL Server 2005 is 'varchar(max)'

During testing this type is set to 'varchar(8000)' for both versions. The reason is that rails expects to be able to use SQL = operators on text data types and this is not possible with a native 'text' data type in SQL Server. The default 'varchar(max)' for SQL Server 2005 can be queried using the SQL = operator and has plenty of storage space which is why we made it the default for 2005. If for some reason you want to change the data type created during migrations for any SQL Server version, you can configure this line to your liking in a config/initializer file.
During testing this type is set to 'varchar(8000)' for both versions. The reason is that rails expects to be able to use SQL = operators on text data types and this is not possible with a native 'text' data type in SQL Server. The default 'varchar(max)' for SQL Server 2005 can be queried using the SQL = operator and has plenty of storage space which is why we made it the default for 2005. If for some reason you want to change the data type created during migrations for any SQL Server version, you can configure this line to your liking in a config/initializers file.

ActiveRecord::ConnectionAdapters::SQLServerAdapter.native_text_database_type = 'varchar(8000)'

Expand All @@ -68,6 +68,13 @@ By default any :binary column created by migrations will create these native typ
* SQL Server 2005 is 'varbinary(max)'


== Schema Information Logging

By default all queries to the INFORMATION_SCHEMA table is silenced. If you think logging these queries are useful, you can enable it by adding this like to a config/initializers file.

ActiveRecord::ConnectionAdapters::SQLServerAdapter.log_info_schema_queries = true


== Versions

It is our goal to match the adapter version with each version of rails. However we will track our own tiny version independent of ActiveRecord. For example, an adapter version of 2.2.x will work on any 2.2.x version of ActiveRecord. This convention will be used in both the Git tags as well as the Rubygems versioning.
Expand Down
22 changes: 14 additions & 8 deletions lib/active_record/connection_adapters/sqlserver_adapter.rb
Expand Up @@ -155,7 +155,7 @@ class SQLServerAdapter < AbstractAdapter
SUPPORTED_VERSIONS = [2000,2005].freeze
LIMITABLE_TYPES = ['string','integer','float','char','nchar','varchar','nvarchar'].freeze

cattr_accessor :native_text_database_type, :native_binary_database_type
cattr_accessor :native_text_database_type, :native_binary_database_type, :log_info_schema_queries

class << self

Expand Down Expand Up @@ -189,7 +189,7 @@ def supports_ddl_transactions?
end

def database_version
@database_version ||= select_value('SELECT @@version')
@database_version ||= info_schema_query { select_value('SELECT @@version') }
end

def database_year
Expand Down Expand Up @@ -452,18 +452,20 @@ def table_alias_length
end

def tables(name = nil)
select_values "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME <> 'dtproperties'"
info_schema_query do
select_values "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME <> 'dtproperties'"
end
end

def views(name = nil)
@sqlserver_views_cache ||=
select_values "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME NOT IN ('sysconstraints','syssegments')"
info_schema_query { select_values("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME NOT IN ('sysconstraints','syssegments')") }
end

def view_information(table_name)
table_name = unqualify_table_name(table_name)
@sqlserver_view_information_cache[table_name] ||=
select_one "SELECT * FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME = '#{table_name}'"
info_schema_query { select_one("SELECT * FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME = '#{table_name}'") }
end

def view_table_name(table_name)
Expand Down Expand Up @@ -671,6 +673,10 @@ def update_sql(sql, name = nil)
select_value('SELECT @@ROWCOUNT AS AffectedRows')
end

def info_schema_query
log_info_schema_queries ? yield : ActiveRecord::Base.silence{ yield }
end

def raw_execute(sql, name = nil, &block)
log(sql, name) do
if block_given?
Expand Down Expand Up @@ -736,7 +742,7 @@ def add_limit_offset_for_association_limiting!(sql, options)
# SCHEMA STATEMENTS ========================================#

def remove_check_constraints(table_name, column_name)
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)}'")
constraints = info_schema_query { 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)}'") }
constraints.each do |constraint|
do_execute "ALTER TABLE #{quote_table_name(table_name)} DROP CONSTRAINT #{quote_column_name(constraint)}"
end
Expand Down Expand Up @@ -892,7 +898,7 @@ def column_definitions(table_name)
WHERE columns.TABLE_NAME = '#{table_name}'
ORDER BY columns.ordinal_position
}.gsub(/[ \t\r\n]+/,' ')
results = without_type_conversion { select(sql,nil,true) }
results = info_schema_query { without_type_conversion{ select(sql,nil,true) } }
results.collect do |ci|
ci.symbolize_keys!
ci[:type] = case ci[:type]
Expand All @@ -909,7 +915,7 @@ def column_definitions(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 INFORMATION_SCHEMA.COLUMNS c WHERE c.TABLE_NAME = '#{real_table_name}' AND c.COLUMN_NAME = '#{real_column_name}'"
ci[:default_value] = without_type_conversion { select_value(col_default_sql) }
ci[:default_value] = info_schema_query { without_type_conversion{ select_value(col_default_sql) } }
end
ci[:default_value] = case ci[:default_value]
when nil, '(null)', '(NULL)'
Expand Down
4 changes: 0 additions & 4 deletions test/cases/adapter_test_sqlserver.rb
Expand Up @@ -473,10 +473,6 @@ def setup
end

should 'find default values' do
# col_default_sql = "SELECT c.COLUMN_DEFAULT FROM INFORMATION_SCHEMA.COLUMNS c WHERE c.TABLE_NAME = 'string_defaults' AND c.COLUMN_NAME = 'string_with_pretend_null_one'"
# raise @connection.select_value(col_default_sql).inspect
# raise @connection.without_type_conversion{ @connection.select_value(col_default_sql) }.inspect

assert_equal 'null', StringDefaultsView.new.pretend_null,
StringDefaultsView.columns_hash['pretend_null'].inspect
end
Expand Down

0 comments on commit 2a76eea

Please sign in to comment.