activerecord-sqlserver-adapter-schemas 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
|
2
|
+
== Schema support for Rails SQL Server 2000, 2005 and 2008 Adapter
|
3
|
+
|
4
|
+
Adds support for schemas to the activerecord-sqlserver-adapter gem
|
5
|
+
|
6
|
+
== Installation
|
7
|
+
|
8
|
+
$ gem install activerecord-sqlserver-adapter
|
9
|
+
$ gem install activerecord-sqlserver-adapter-schemas
|
10
|
+
|
11
|
+
Optionally configure your gem dependencies in your rails environment.rb file.
|
12
|
+
|
13
|
+
config.gem 'activerecord-sqlserver-adapter', :version => 'x.x.xx'
|
14
|
+
config.gem 'activerecord-sqlserver-adapter-schemas', :version => 'x.x.xx'
|
15
|
+
|
16
|
+
== Using Schemas with ActiveRecord
|
17
|
+
|
18
|
+
The simplest way to use schemas is to simply specify it as part of the table name
|
19
|
+
|
20
|
+
class FooBar < ActiveRecord::Base
|
21
|
+
set_table_name 'foo.bars'
|
22
|
+
end
|
23
|
+
|
24
|
+
To use any the following methods, you must first enable schema names:
|
25
|
+
|
26
|
+
ActiveRecord::Base.use_schema_names = true
|
27
|
+
|
28
|
+
With use_schema_names enabled, models in a module will use the module name as the schema name automatically. For example:
|
29
|
+
|
30
|
+
# the table name for this model would be assumed to be foo.bars
|
31
|
+
class Foo::Bar < ActiveRecord::Base
|
32
|
+
end
|
33
|
+
|
34
|
+
The schema name can also be set explicitly when use_schema_names is enabled:
|
35
|
+
|
36
|
+
class Bar < ActiveRecord::Base
|
37
|
+
set_schema_name 'foo'
|
38
|
+
end
|
39
|
+
|
40
|
+
== Migrations
|
41
|
+
|
42
|
+
It is possible to have separate schema_migrations tables in different schemas existing in the database at the same time. This is useful if you have multiple rails applications using the same database but different schemas.
|
43
|
+
|
44
|
+
To use this feature, use different users for each application with different default schemas set in the database. So if you have 2 rails applications, if they log in as different users with different default schemas, they each get their own schema_migrations table in that schema.
|
45
|
+
|
46
|
+
== License
|
47
|
+
|
48
|
+
Copyright 2010. It is free software, and may be redistributed under the terms specified in the MIT-LICENSE file.
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# This module is used to make it easier to deal with legacy char fields by trimming them automatically after a find.
|
2
|
+
module ActiveRecord
|
3
|
+
module Schemas
|
4
|
+
module Base
|
5
|
+
# returns true if schema names should be used. Default is false
|
6
|
+
def use_schema_names?
|
7
|
+
read_inheritable_attribute(:use_schema_names)
|
8
|
+
end
|
9
|
+
|
10
|
+
# sets if schema names should be used.
|
11
|
+
def use_schema_names=(value)
|
12
|
+
write_inheritable_attribute(:use_schema_names, value)
|
13
|
+
end
|
14
|
+
alias_method :set_use_schema_names, :use_schema_names=
|
15
|
+
|
16
|
+
# returns the schema name, either based on the module (via reset_schema_name) of an explicitly set value defined by the class
|
17
|
+
def schema_name
|
18
|
+
reset_schema_name
|
19
|
+
end
|
20
|
+
|
21
|
+
# calculates the schema name based on the class's module
|
22
|
+
def reset_schema_name
|
23
|
+
ar_descendant = class_of_active_record_descendant(self)
|
24
|
+
if ar_descendant == self
|
25
|
+
name = self.name.split('::').first.downcase
|
26
|
+
set_schema_name name
|
27
|
+
name
|
28
|
+
else
|
29
|
+
ar_descendant.schema_name
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# overrides the default schema based on the module
|
34
|
+
def schema_name=(value = nil, &block)
|
35
|
+
define_attr_method :schema_name, value, &block
|
36
|
+
end
|
37
|
+
alias_method :set_schema_name, :schema_name=
|
38
|
+
|
39
|
+
# sets the table name with the schema
|
40
|
+
def reset_table_name_with_schema
|
41
|
+
ar_descendant = class_of_active_record_descendant(self)
|
42
|
+
if self == ar_descendant
|
43
|
+
name = reset_table_name
|
44
|
+
if use_schema_names? && schema_name
|
45
|
+
name = "#{"#{schema_name}." if schema_name}#{name}"
|
46
|
+
set_table_name name
|
47
|
+
end
|
48
|
+
name
|
49
|
+
else
|
50
|
+
name = ar_descendant.table_name
|
51
|
+
set_table_name name
|
52
|
+
name
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Schemas
|
3
|
+
module ConnectionAdapters
|
4
|
+
|
5
|
+
module SqlserverAdapter
|
6
|
+
|
7
|
+
# When this module is included, the following methods are chained in order
|
8
|
+
# to strip off the schema names if the schema is the default schema
|
9
|
+
def self.included(base)
|
10
|
+
base.alias_method_chain :columns, :default_schema_check
|
11
|
+
base.alias_method_chain :table_exists?, :default_schema_check
|
12
|
+
base.alias_method_chain :table_name_or_views_table_name, :default_schema_check
|
13
|
+
end
|
14
|
+
|
15
|
+
def default_schema
|
16
|
+
unless sqlserver_2000?
|
17
|
+
@default_schema ||= select_values("SELECT default_schema_name FROM sys.database_principals WHERE type = 'S' and name = '#{self.quote_string(@connection_options[:username])}'").first
|
18
|
+
end
|
19
|
+
@default_schema ||= 'dbo'
|
20
|
+
end
|
21
|
+
attr_writer :default_schema
|
22
|
+
|
23
|
+
def table_name_or_views_table_name_with_default_schema_check(table_name)
|
24
|
+
table_name = unqualify_table_name_if_default_schema(table_name)
|
25
|
+
table_name_or_views_table_name_without_default_schema_check(table_name)
|
26
|
+
end
|
27
|
+
|
28
|
+
def table_exists_with_default_schema_check?(table_name)
|
29
|
+
table_name = unqualify_table_name_if_default_schema(table_name)
|
30
|
+
table_exists_without_default_schema_check?(table_name)
|
31
|
+
end
|
32
|
+
|
33
|
+
def columns_with_default_schema_check(table_name, column_name = nil)
|
34
|
+
table_name = unqualify_table_name_if_default_schema(table_name) if table_name
|
35
|
+
columns_without_default_schema_check(table_name, column_name)
|
36
|
+
end
|
37
|
+
|
38
|
+
def unqualify_schema_name(table_name)
|
39
|
+
parts = table_name.to_s.split('.')
|
40
|
+
parts.length == 1 ? default_schema : parts[parts.length - 2].gsub(/[\[\]]/,'')
|
41
|
+
end
|
42
|
+
|
43
|
+
def unqualify_table_name_if_default_schema(table_name)
|
44
|
+
schema = unqualify_schema_name(table_name)
|
45
|
+
schema == default_schema ? unqualify_table_name(table_name) : table_name
|
46
|
+
end
|
47
|
+
|
48
|
+
# override index name so that if there is a schema, rename it schema_table instead of schema.table
|
49
|
+
def index_name(table_name, options) #:nodoc:
|
50
|
+
super table_name.tr('.', '_'), options
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'active_record', 'schemas', 'base')
|
2
|
+
require File.join(File.dirname(__FILE__), 'active_record', 'schemas', 'connection_adapters', 'sqlserver_adapter')
|
3
|
+
|
4
|
+
class ActiveRecord::Base
|
5
|
+
extend ActiveRecord::Schemas::Base
|
6
|
+
|
7
|
+
def self.table_name
|
8
|
+
reset_table_name_with_schema
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class ActiveRecord::ConnectionAdapters::SQLServerAdapter
|
13
|
+
include ActiveRecord::Schemas::ConnectionAdapters::SqlserverAdapter
|
14
|
+
|
15
|
+
# This method is overridden to support linked servers
|
16
|
+
def unqualify_db_name(table_name)
|
17
|
+
table_names = table_name.to_s.split('.')
|
18
|
+
table_names.length >= 3 ? table_names[0...table_names.length - 2].join('.').tr('[]','') : nil
|
19
|
+
end
|
20
|
+
|
21
|
+
# This method is overridden to support schema names
|
22
|
+
def tables(name = nil)
|
23
|
+
# return schema.table unless the schema is the default schema, in which case just return table
|
24
|
+
info_schema_query do
|
25
|
+
select_values("SELECT TABLE_SCHEMA + '.' + TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME <> 'dtproperties'").collect do |table|
|
26
|
+
default_schema && table.index("#{default_schema}.") == 0 ? table[default_schema.length + 1..table.length] : table
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# This method is overridden to support schema names
|
32
|
+
def views(name = nil)
|
33
|
+
# return schema.view unless the schema is the default schema, in which case just return view
|
34
|
+
@sqlserver_views_cache ||=
|
35
|
+
info_schema_query do
|
36
|
+
select_values("SELECT TABLE_SCHEMA + '.' + TABLE_NAME FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME NOT IN ('sysconstraints','syssegments')").collect do |view|
|
37
|
+
default_schema && view.index("#{default_schema}.") == 0 ? view[default_schema.length + 1..view.length] : view
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# This method is overridden to support references such as database..table
|
43
|
+
def quote_column_name(column_name)
|
44
|
+
column_name.to_s.split('..').collect do |part|
|
45
|
+
part.split('.').map{ |name| name =~ /^\[.*\]$/ ? name : "[#{name}]" }.join('.')
|
46
|
+
end.join('..')
|
47
|
+
end
|
48
|
+
|
49
|
+
# overridden to support schemas. sp_helpindex does not support linked servers
|
50
|
+
def indexes(table_name, name = nil)
|
51
|
+
db_name = unqualify_db_name(table_name)
|
52
|
+
db_name << '.' if db_name
|
53
|
+
schema_name = unqualify_schema_name(table_name) << '.'
|
54
|
+
table_name = unqualify_table_name(table_name)
|
55
|
+
|
56
|
+
select("EXEC sp_helpindex '#{quote_table_name("#{db_name}#{schema_name}#{table_name}")}'",name).inject([]) do |indexes,index|
|
57
|
+
if index['index_description'] =~ /primary key/
|
58
|
+
indexes
|
59
|
+
else
|
60
|
+
name = index['index_name']
|
61
|
+
unique = index['index_description'] =~ /unique/
|
62
|
+
columns = index['index_keys'].split(',').map do |column|
|
63
|
+
column.strip!
|
64
|
+
column.gsub! '(-)', '' if column.ends_with?('(-)')
|
65
|
+
column
|
66
|
+
end
|
67
|
+
indexes << ::ActiveRecord::ConnectionAdapters::IndexDefinition.new(table_name, name, unique, columns)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def view_information(table_name)
|
73
|
+
db_name = unqualify_db_name(table_name)
|
74
|
+
schema_name = unqualify_schema_name(table_name)
|
75
|
+
table_name = unqualify_table_name(table_name)
|
76
|
+
|
77
|
+
@@sqlserver_view_information_cache ||= {}
|
78
|
+
@@sqlserver_view_information_cache[table_name.downcase] ||= begin
|
79
|
+
sql = "SELECT * FROM #{"#{db_name}." if db_name}INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME = '#{table_name}'"
|
80
|
+
sql << " and TABLE_SCHEMA = '#{schema_name}'" if schema_name
|
81
|
+
view_info = info_schema_query { select_one(sql) }
|
82
|
+
if view_info
|
83
|
+
if view_info['VIEW_DEFINITION'].blank? || view_info['VIEW_DEFINITION'].length == 4000
|
84
|
+
view_info['VIEW_DEFINITION'] = info_schema_query { select_values("EXEC sp_helptext #{table_name}").join }
|
85
|
+
end
|
86
|
+
end
|
87
|
+
view_info
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def column_definitions(table_name)
|
92
|
+
db_name = unqualify_db_name(table_name)
|
93
|
+
db_name << '.' if db_name
|
94
|
+
schema_name = unqualify_schema_name(table_name)
|
95
|
+
table_name = unqualify_table_name(table_name)
|
96
|
+
sql = %{
|
97
|
+
SELECT
|
98
|
+
columns.TABLE_NAME as table_name,
|
99
|
+
columns.COLUMN_NAME as name,
|
100
|
+
columns.DATA_TYPE as type,
|
101
|
+
columns.COLUMN_DEFAULT as default_value,
|
102
|
+
columns.NUMERIC_SCALE as numeric_scale,
|
103
|
+
columns.NUMERIC_PRECISION as numeric_precision,
|
104
|
+
CASE
|
105
|
+
WHEN columns.DATA_TYPE IN ('nchar','nvarchar') THEN columns.CHARACTER_MAXIMUM_LENGTH
|
106
|
+
ELSE COL_LENGTH(columns.TABLE_SCHEMA+'.'+columns.TABLE_NAME, columns.COLUMN_NAME)
|
107
|
+
END as length,
|
108
|
+
CASE
|
109
|
+
WHEN columns.IS_NULLABLE = 'YES' THEN 1
|
110
|
+
ELSE NULL
|
111
|
+
end as is_nullable,
|
112
|
+
CASE
|
113
|
+
WHEN COLUMNPROPERTY(OBJECT_ID(columns.TABLE_SCHEMA+'.'+columns.TABLE_NAME), columns.COLUMN_NAME, 'IsIdentity') = 0 THEN NULL
|
114
|
+
ELSE 1
|
115
|
+
END as is_identity
|
116
|
+
FROM #{db_name}INFORMATION_SCHEMA.COLUMNS columns
|
117
|
+
WHERE columns.TABLE_NAME = '#{table_name}'
|
118
|
+
#{"AND columns.TABLE_SCHEMA = '#{schema_name}'" if schema_name}
|
119
|
+
ORDER BY columns.ordinal_position
|
120
|
+
}.gsub(/[ \t\r\n]+/,' ')
|
121
|
+
results = info_schema_query { select(sql,nil,true) }
|
122
|
+
results.collect do |ci|
|
123
|
+
ci.symbolize_keys!
|
124
|
+
ci[:type] = case ci[:type]
|
125
|
+
when /^bit|image|text|ntext|datetime$/
|
126
|
+
ci[:type]
|
127
|
+
when /^numeric|decimal$/i
|
128
|
+
"#{ci[:type]}(#{ci[:numeric_precision]},#{ci[:numeric_scale]})"
|
129
|
+
when /^char|nchar|varchar|nvarchar|varbinary|bigint|int|smallint$/
|
130
|
+
ci[:length].to_i == -1 ? "#{ci[:type]}(max)" : "#{ci[:type]}(#{ci[:length]})"
|
131
|
+
else
|
132
|
+
ci[:type]
|
133
|
+
end
|
134
|
+
if ci[:default_value].nil? && views.include?(table_name)
|
135
|
+
real_table_name = table_name_or_views_table_name(table_name)
|
136
|
+
real_column_name = views_real_column_name(table_name,ci[:name])
|
137
|
+
col_default_sql = "SELECT c.COLUMN_DEFAULT FROM #{db_name}INFORMATION_SCHEMA.COLUMNS c WHERE c.TABLE_NAME = '#{real_table_name}' AND c.COLUMN_NAME = '#{real_column_name}'"
|
138
|
+
ci[:default_value] = info_schema_query { select_value(col_default_sql) }
|
139
|
+
end
|
140
|
+
ci[:default_value] = case ci[:default_value]
|
141
|
+
when nil, '(null)', '(NULL)'
|
142
|
+
nil
|
143
|
+
else
|
144
|
+
match_data = ci[:default_value].match(/\A\(+N?'?(.*?)'?\)+\Z/m)
|
145
|
+
match_data ? match_data[1] : nil
|
146
|
+
end
|
147
|
+
ci[:null] = ci[:is_nullable].to_i == 1 ; ci.delete(:is_nullable)
|
148
|
+
ci
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: activerecord-sqlserver-adapter-schemas
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Airlite Plastics
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-06-25 00:00:00 -05:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: activerecord-sqlserver-adapter
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
description: Adds schema support to activerecord-sqlserver-adapter.
|
26
|
+
email: dtjablonski@airliteplastics.com
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files:
|
32
|
+
- README.rdoc
|
33
|
+
files:
|
34
|
+
- MIT-LICENSE
|
35
|
+
- README.rdoc
|
36
|
+
- lib/activerecord-sqlserver-adapter-schemas.rb
|
37
|
+
- lib/active_record/schemas/base.rb
|
38
|
+
- lib/active_record/schemas/connection_adapters/sqlserver_adapter.rb
|
39
|
+
has_rdoc: true
|
40
|
+
homepage:
|
41
|
+
licenses: []
|
42
|
+
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options:
|
45
|
+
- --line-numbers
|
46
|
+
- --inline-source
|
47
|
+
- --main
|
48
|
+
- README.rdoc
|
49
|
+
require_paths:
|
50
|
+
- lib
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: 1.8.6
|
56
|
+
version:
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: "0"
|
62
|
+
version:
|
63
|
+
requirements: []
|
64
|
+
|
65
|
+
rubyforge_project:
|
66
|
+
rubygems_version: 1.3.5
|
67
|
+
signing_key:
|
68
|
+
specification_version: 3
|
69
|
+
summary: Adds schema support to activerecord-sqlserver-adapter.
|
70
|
+
test_files: []
|
71
|
+
|