activerecord-odbc-adapter 2.0
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.
- data/AUTHORS +16 -0
- data/COPYING +21 -0
- data/ChangeLog +139 -0
- data/LICENSE +5 -0
- data/NEWS +25 -0
- data/README +229 -0
- data/lib/active_record/connection_adapters/odbc_adapter.rb +1950 -0
- data/lib/active_record/vendor/odbcext_db2.rb +87 -0
- data/lib/active_record/vendor/odbcext_informix.rb +144 -0
- data/lib/active_record/vendor/odbcext_informix_col.rb +45 -0
- data/lib/active_record/vendor/odbcext_ingres.rb +156 -0
- data/lib/active_record/vendor/odbcext_microsoftsqlserver.rb +216 -0
- data/lib/active_record/vendor/odbcext_microsoftsqlserver_col.rb +40 -0
- data/lib/active_record/vendor/odbcext_mysql.rb +174 -0
- data/lib/active_record/vendor/odbcext_oracle.rb +219 -0
- data/lib/active_record/vendor/odbcext_postgresql.rb +158 -0
- data/lib/active_record/vendor/odbcext_progress.rb +139 -0
- data/lib/active_record/vendor/odbcext_progress89.rb +259 -0
- data/lib/active_record/vendor/odbcext_sqlanywhere.rb +115 -0
- data/lib/active_record/vendor/odbcext_sqlanywhere_col.rb +49 -0
- data/lib/active_record/vendor/odbcext_sybase.rb +213 -0
- data/lib/active_record/vendor/odbcext_sybase_col.rb +49 -0
- data/lib/active_record/vendor/odbcext_virtuoso.rb +158 -0
- data/lib/odbc_adapter.rb +28 -0
- data/support/lib/active_record/connection_adapters/abstract/schema_definitions.rb +259 -0
- data/support/odbc_rails.diff +367 -0
- data/support/pack_odbc.rb +119 -0
- data/support/rake/rails_plugin_package_task.rb +212 -0
- data/support/rake_fixes/README +6 -0
- data/support/rake_fixes/databases.dif +13 -0
- data/support/test/base_test.rb +1765 -0
- data/support/test/migration_test.rb +1007 -0
- data/test/connections/native_odbc/connection.rb +137 -0
- data/test/fixtures/db_definitions/db2.drop.sql +33 -0
- data/test/fixtures/db_definitions/db2.sql +237 -0
- data/test/fixtures/db_definitions/db22.drop.sql +2 -0
- data/test/fixtures/db_definitions/db22.sql +5 -0
- data/test/fixtures/db_definitions/informix.drop.sql +33 -0
- data/test/fixtures/db_definitions/informix.sql +223 -0
- data/test/fixtures/db_definitions/informix2.drop.sql +2 -0
- data/test/fixtures/db_definitions/informix2.sql +5 -0
- data/test/fixtures/db_definitions/ingres.drop.sql +68 -0
- data/test/fixtures/db_definitions/ingres.sql +252 -0
- data/test/fixtures/db_definitions/ingres2.drop.sql +2 -0
- data/test/fixtures/db_definitions/ingres2.sql +5 -0
- data/test/fixtures/db_definitions/mysql.drop.sql +33 -0
- data/test/fixtures/db_definitions/mysql.sql +238 -0
- data/test/fixtures/db_definitions/mysql2.drop.sql +2 -0
- data/test/fixtures/db_definitions/mysql2.sql +5 -0
- data/test/fixtures/db_definitions/oracle_odbc.drop.sql +72 -0
- data/test/fixtures/db_definitions/oracle_odbc.sql +296 -0
- data/test/fixtures/db_definitions/oracle_odbc2.drop.sql +2 -0
- data/test/fixtures/db_definitions/oracle_odbc2.sql +6 -0
- data/test/fixtures/db_definitions/postgresql.drop.sql +38 -0
- data/test/fixtures/db_definitions/postgresql.sql +267 -0
- data/test/fixtures/db_definitions/postgresql2.drop.sql +2 -0
- data/test/fixtures/db_definitions/postgresql2.sql +5 -0
- data/test/fixtures/db_definitions/progress.drop.sql +67 -0
- data/test/fixtures/db_definitions/progress.sql +255 -0
- data/test/fixtures/db_definitions/progress2.drop.sql +2 -0
- data/test/fixtures/db_definitions/progress2.sql +6 -0
- data/test/fixtures/db_definitions/sqlserver.drop.sql +35 -0
- data/test/fixtures/db_definitions/sqlserver.sql +247 -0
- data/test/fixtures/db_definitions/sqlserver2.drop.sql +2 -0
- data/test/fixtures/db_definitions/sqlserver2.sql +5 -0
- data/test/fixtures/db_definitions/sybase.drop.sql +35 -0
- data/test/fixtures/db_definitions/sybase.sql +222 -0
- data/test/fixtures/db_definitions/sybase2.drop.sql +4 -0
- data/test/fixtures/db_definitions/sybase2.sql +5 -0
- data/test/fixtures/db_definitions/virtuoso.drop.sql +33 -0
- data/test/fixtures/db_definitions/virtuoso.sql +218 -0
- data/test/fixtures/db_definitions/virtuoso2.drop.sql +2 -0
- data/test/fixtures/db_definitions/virtuoso2.sql +5 -0
- metadata +166 -0
data/lib/odbc_adapter.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# $Id: odbc_adapter.rb,v 1.1 2006/12/06 16:16:08 source Exp $
|
4
|
+
#
|
5
|
+
# OpenLink ODBC Adapter for Ruby on Rails
|
6
|
+
# Copyright (C) 2006 OpenLink Software
|
7
|
+
#
|
8
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
9
|
+
# a copy of this software and associated documentation files (the
|
10
|
+
# "Software"), to deal in the Software without restriction, including
|
11
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
12
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
13
|
+
# permit persons to whom the Software is furnished to do so, subject
|
14
|
+
# to the following conditions:
|
15
|
+
#
|
16
|
+
# The above copyright notice and this permission notice shall be
|
17
|
+
# included in all copies or substantial portions of the Software.
|
18
|
+
#
|
19
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
20
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
21
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
22
|
+
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
23
|
+
# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
24
|
+
# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
25
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
26
|
+
#
|
27
|
+
|
28
|
+
require 'active_record/connection_adapters/odbc_adapter'
|
@@ -0,0 +1,259 @@
|
|
1
|
+
require 'parsedate'
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module ConnectionAdapters #:nodoc:
|
5
|
+
# An abstract definition of a column in a table.
|
6
|
+
class Column
|
7
|
+
attr_reader :name, :default, :type, :limit, :null, :sql_type
|
8
|
+
attr_accessor :primary
|
9
|
+
|
10
|
+
# Instantiates a new column in the table.
|
11
|
+
#
|
12
|
+
# +name+ is the column's name, as in <tt><b>supplier_id</b> int(11)</tt>.
|
13
|
+
# +default+ is the type-casted default value, such as <tt>sales_stage varchar(20) default <b>'new'</b></tt>.
|
14
|
+
# +sql_type+ is only used to extract the column's length, if necessary. For example, <tt>company_name varchar(<b>60</b>)</tt>.
|
15
|
+
# +null+ determines if this column allows +NULL+ values.
|
16
|
+
def initialize(name, default, sql_type = nil, null = true)
|
17
|
+
@name, @type, @null = name, simplified_type(sql_type), null
|
18
|
+
@sql_type = sql_type
|
19
|
+
# have to do this one separately because type_cast depends on #type
|
20
|
+
@default = type_cast(default)
|
21
|
+
@limit = extract_limit(sql_type) unless sql_type.nil?
|
22
|
+
@primary = nil
|
23
|
+
@text = [:string, :text].include? @type
|
24
|
+
@number = [:float, :integer].include? @type
|
25
|
+
end
|
26
|
+
|
27
|
+
def text?
|
28
|
+
@text
|
29
|
+
end
|
30
|
+
|
31
|
+
def number?
|
32
|
+
@number
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns the Ruby class that corresponds to the abstract data type.
|
36
|
+
def klass
|
37
|
+
case type
|
38
|
+
when :integer then Fixnum
|
39
|
+
when :float then Float
|
40
|
+
when :datetime then Time
|
41
|
+
when :date then Date
|
42
|
+
when :timestamp then Time
|
43
|
+
when :time then Time
|
44
|
+
when :text, :string then String
|
45
|
+
when :binary then String
|
46
|
+
when :boolean then Object
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Casts value (which is a String) to an appropriate instance.
|
51
|
+
def type_cast(value)
|
52
|
+
return nil if value.nil?
|
53
|
+
case type
|
54
|
+
when :string then value
|
55
|
+
when :text then value
|
56
|
+
when :integer then value.to_i rescue value ? 1 : 0
|
57
|
+
when :float then value.to_f
|
58
|
+
when :datetime then self.class.string_to_time(value)
|
59
|
+
when :timestamp then self.class.string_to_time(value)
|
60
|
+
when :time then self.class.string_to_dummy_time(value)
|
61
|
+
when :date then self.class.string_to_date(value)
|
62
|
+
when :binary then self.class.binary_to_string(value)
|
63
|
+
when :boolean then self.class.value_to_boolean(value)
|
64
|
+
else value
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def type_cast_code(var_name)
|
69
|
+
case type
|
70
|
+
when :string then nil
|
71
|
+
when :text then nil
|
72
|
+
when :integer then "(#{var_name}.to_i rescue #{var_name} ? 1 : 0)"
|
73
|
+
when :float then "#{var_name}.to_f"
|
74
|
+
when :datetime then "#{self.class.name}.string_to_time(#{var_name})"
|
75
|
+
when :timestamp then "#{self.class.name}.string_to_time(#{var_name})"
|
76
|
+
when :time then "#{self.class.name}.string_to_dummy_time(#{var_name})"
|
77
|
+
when :date then "#{self.class.name}.string_to_date(#{var_name})"
|
78
|
+
when :binary then "#{self.class.name}.binary_to_string(#{var_name})"
|
79
|
+
when :boolean then "#{self.class.name}.value_to_boolean(#{var_name})"
|
80
|
+
else nil
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Returns the human name of the column name.
|
85
|
+
#
|
86
|
+
# ===== Examples
|
87
|
+
# Column.new('sales_stage', ...).human_name #=> 'Sales stage'
|
88
|
+
def human_name
|
89
|
+
Base.human_attribute_name(@name)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Used to convert from Strings to BLOBs
|
93
|
+
def self.string_to_binary(value)
|
94
|
+
value
|
95
|
+
end
|
96
|
+
|
97
|
+
# Used to convert from BLOBs to Strings
|
98
|
+
def self.binary_to_string(value)
|
99
|
+
value
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.string_to_date(string)
|
103
|
+
return string unless string.is_a?(String)
|
104
|
+
date_array = ParseDate.parsedate(string)
|
105
|
+
# treat 0000-00-00 as nil
|
106
|
+
Date.new(date_array[0], date_array[1], date_array[2]) rescue nil
|
107
|
+
end
|
108
|
+
|
109
|
+
def self.string_to_time(string)
|
110
|
+
return string unless string.is_a?(String)
|
111
|
+
time_array = ParseDate.parsedate(string)[0..5]
|
112
|
+
# treat 0000-00-00 00:00:00 as nil
|
113
|
+
Time.send(Base.default_timezone, *time_array) rescue nil
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.string_to_dummy_time(string)
|
117
|
+
return string unless string.is_a?(String)
|
118
|
+
time_array = ParseDate.parsedate(string)
|
119
|
+
# pad the resulting array with dummy date information
|
120
|
+
time_array[0] = 2000; time_array[1] = 1; time_array[2] = 1;
|
121
|
+
Time.send(Base.default_timezone, *time_array) rescue nil
|
122
|
+
end
|
123
|
+
|
124
|
+
# convert something to a boolean
|
125
|
+
def self.value_to_boolean(value)
|
126
|
+
return value if value==true || value==false
|
127
|
+
case value.to_s.downcase
|
128
|
+
when "true", "t", "1" then true
|
129
|
+
else false
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
private
|
134
|
+
def extract_limit(sql_type)
|
135
|
+
$1.to_i if sql_type =~ /\((.*)\)/
|
136
|
+
end
|
137
|
+
|
138
|
+
def simplified_type(field_type)
|
139
|
+
case field_type
|
140
|
+
when /int/i
|
141
|
+
:integer
|
142
|
+
when /float|double|decimal|numeric/i
|
143
|
+
:float
|
144
|
+
when /datetime/i
|
145
|
+
:datetime
|
146
|
+
when /timestamp/i
|
147
|
+
:timestamp
|
148
|
+
when /time/i
|
149
|
+
:time
|
150
|
+
when /date/i
|
151
|
+
:date
|
152
|
+
when /clob/i, /text/i
|
153
|
+
:text
|
154
|
+
when /blob/i, /binary/i
|
155
|
+
:binary
|
156
|
+
when /char/i, /string/i
|
157
|
+
:string
|
158
|
+
when /boolean/i
|
159
|
+
:boolean
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
class IndexDefinition < Struct.new(:table, :name, :unique, :columns) #:nodoc:
|
165
|
+
end
|
166
|
+
|
167
|
+
class ColumnDefinition < Struct.new(:base, :name, :type, :limit, :default, :null) #:nodoc:
|
168
|
+
def to_sql
|
169
|
+
column_sql = "#{base.quote_column_name(name)} #{type_to_sql(type.to_sym, limit)}"
|
170
|
+
add_column_options!(column_sql, :null => null, :default => default)
|
171
|
+
column_sql
|
172
|
+
end
|
173
|
+
alias to_s :to_sql
|
174
|
+
|
175
|
+
private
|
176
|
+
def type_to_sql(name, limit)
|
177
|
+
base.type_to_sql(name, limit) rescue name
|
178
|
+
end
|
179
|
+
|
180
|
+
def add_column_options!(sql, options)
|
181
|
+
base.add_column_options!(sql, options.merge(:column => self))
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
# Represents a SQL table in an abstract way.
|
186
|
+
# Columns are stored as ColumnDefinition in the #columns attribute.
|
187
|
+
class TableDefinition
|
188
|
+
attr_accessor :columns
|
189
|
+
|
190
|
+
def initialize(base)
|
191
|
+
@columns = []
|
192
|
+
@base = base
|
193
|
+
end
|
194
|
+
|
195
|
+
# Appends a primary key definition to the table definition.
|
196
|
+
# Can be called multiple times, but this is probably not a good idea.
|
197
|
+
def primary_key(name)
|
198
|
+
column(name, :primary_key)
|
199
|
+
end
|
200
|
+
|
201
|
+
# Returns a ColumnDefinition for the column with name +name+.
|
202
|
+
def [](name)
|
203
|
+
@columns.find {|column| column.name.to_s == name.to_s}
|
204
|
+
end
|
205
|
+
|
206
|
+
# Instantiates a new column for the table.
|
207
|
+
# The +type+ parameter must be one of the following values:
|
208
|
+
# <tt>:primary_key</tt>, <tt>:string</tt>, <tt>:text</tt>,
|
209
|
+
# <tt>:integer</tt>, <tt>:float</tt>, <tt>:datetime</tt>,
|
210
|
+
# <tt>:timestamp</tt>, <tt>:time</tt>, <tt>:date</tt>,
|
211
|
+
# <tt>:binary</tt>, <tt>:boolean</tt>.
|
212
|
+
#
|
213
|
+
# Available options are (none of these exists by default):
|
214
|
+
# * <tt>:limit</tt>:
|
215
|
+
# Requests a maximum column length (<tt>:string</tt>, <tt>:text</tt>,
|
216
|
+
# <tt>:binary</tt> or <tt>:integer</tt> columns only)
|
217
|
+
# * <tt>:default</tt>:
|
218
|
+
# The column's default value. You cannot explicitely set the default
|
219
|
+
# value to +NULL+. Simply leave off this option if you want a +NULL+
|
220
|
+
# default value.
|
221
|
+
# * <tt>:null</tt>:
|
222
|
+
# Allows or disallows +NULL+ values in the column. This option could
|
223
|
+
# have been named <tt>:null_allowed</tt>.
|
224
|
+
#
|
225
|
+
# This method returns <tt>self</tt>.
|
226
|
+
#
|
227
|
+
# ===== Examples
|
228
|
+
# # Assuming def is an instance of TableDefinition
|
229
|
+
# def.column(:granted, :boolean)
|
230
|
+
# #=> granted BOOLEAN
|
231
|
+
#
|
232
|
+
# def.column(:picture, :binary, :limit => 2.megabytes)
|
233
|
+
# #=> picture BLOB(2097152)
|
234
|
+
#
|
235
|
+
# def.column(:sales_stage, :string, :limit => 20, :default => 'new', :null => false)
|
236
|
+
# #=> sales_stage VARCHAR(20) DEFAULT 'new' NOT NULL
|
237
|
+
def column(name, type, options = {})
|
238
|
+
column = self[name] || ColumnDefinition.new(@base, name, type)
|
239
|
+
column.limit = options[:limit] || native[type.to_sym][:limit] if options[:limit] or native[type.to_sym]
|
240
|
+
column.default = options[:default]
|
241
|
+
column.null = options[:null]
|
242
|
+
@columns << column unless @columns.include? column
|
243
|
+
self
|
244
|
+
end
|
245
|
+
|
246
|
+
# Returns a String whose contents are the column definitions
|
247
|
+
# concatenated together. This string can then be pre and appended to
|
248
|
+
# to generate the final SQL to create the table.
|
249
|
+
def to_sql
|
250
|
+
@columns * ', '
|
251
|
+
end
|
252
|
+
|
253
|
+
private
|
254
|
+
def native
|
255
|
+
@base.native_database_types
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
@@ -0,0 +1,367 @@
|
|
1
|
+
Index: base_test.rb
|
2
|
+
===================================================================
|
3
|
+
--- base_test.rb (revision 1)
|
4
|
+
+++ base_test.rb (working copy)
|
5
|
+
@@ -389,6 +389,8 @@
|
6
|
+
if current_adapter?(:SybaseAdapter, :OracleAdapter)
|
7
|
+
# Sybase ctlib does not (yet?) support the date type; use datetime instead.
|
8
|
+
# Oracle treats all dates/times as Time.
|
9
|
+
+ elsif current_adapter?(:ODBCAdapter) && [:ingres, :microsoftsqlserver, :oracle].include?(ActiveRecord::Base.connection.dbmsName)
|
10
|
+
+ # Above databases don't have a pure date type. (They have a datetime-like type).
|
11
|
+
assert_kind_of(
|
12
|
+
Time, Topic.find(1).last_read,
|
13
|
+
"The last_read attribute should be of the Time class"
|
14
|
+
@@ -704,7 +706,12 @@
|
15
|
+
|
16
|
+
def test_default_values_on_empty_strings
|
17
|
+
topic = Topic.new
|
18
|
+
- topic.approved = nil
|
19
|
+
+ #Sybase does not allow nulls in boolean columns
|
20
|
+
+ if current_adapter?(:ODBCAdapter) && ActiveRecord::Base.connection.dbmsName == :sybase
|
21
|
+
+ topic.approved = false
|
22
|
+
+ else
|
23
|
+
+ topic.approved = nil
|
24
|
+
+ end
|
25
|
+
topic.last_read = nil
|
26
|
+
|
27
|
+
topic.save
|
28
|
+
@@ -713,7 +720,8 @@
|
29
|
+
assert_nil topic.last_read
|
30
|
+
|
31
|
+
# Sybase adapter does not allow nulls in boolean columns
|
32
|
+
- if current_adapter?(:SybaseAdapter)
|
33
|
+
+ if current_adapter?(:SybaseAdapter) ||
|
34
|
+
+ current_adapter?(:ODBCAdapter) && ActiveRecord::Base.connection.dbmsName == :sybase
|
35
|
+
assert topic.approved == false
|
36
|
+
else
|
37
|
+
assert_nil topic.approved
|
38
|
+
@@ -941,6 +949,10 @@
|
39
|
+
def test_attributes_on_dummy_time
|
40
|
+
# Oracle, SQL Server, and Sybase do not have a TIME datatype.
|
41
|
+
return true if current_adapter?(:SQLServerAdapter, :OracleAdapter, :SybaseAdapter)
|
42
|
+
+ if current_adapter?(:ODBCAdapter)
|
43
|
+
+ # Check for databases which don't have a true TIME datatype
|
44
|
+
+ return true if [:ingres, :oracle].include?(ActiveRecord::Base.connection.dbmsName)
|
45
|
+
+ end
|
46
|
+
|
47
|
+
attributes = {
|
48
|
+
"bonus_time" => "5:42:00AM"
|
49
|
+
@@ -1185,8 +1197,11 @@
|
50
|
+
replies = Reply.find(:all, :conditions => [ "id IN (?)", topics(:first).replies.collect(&:id) ])
|
51
|
+
assert_equal topics(:first).replies.size, replies.size
|
52
|
+
|
53
|
+
- replies = Reply.find(:all, :conditions => [ "id IN (?)", [] ])
|
54
|
+
- assert_equal 0, replies.size
|
55
|
+
+ # DB2 doesn't support "WHERE (id IN (NULL))" clause
|
56
|
+
+ unless current_adapter?(:ODBCAdapter) && [:db2].include?(ActiveRecord::Base.connection.dbmsName)
|
57
|
+
+ replies = Reply.find(:all, :conditions => [ "id IN (?)", [] ])
|
58
|
+
+ assert_equal 0, replies.size
|
59
|
+
+ end
|
60
|
+
end
|
61
|
+
|
62
|
+
MyObject = Struct.new :attribute1, :attribute2
|
63
|
+
@@ -1225,7 +1240,12 @@
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_quote
|
67
|
+
- author_name = "\\ \001 ' \n \\n \""
|
68
|
+
+ if current_adapter?(:ODBCAdapter) && [:informix, :sybase].include?(ActiveRecord::Base.connection.dbmsName)
|
69
|
+
+ #Some databases only allow printable characters in VARCHAR columns.
|
70
|
+
+ author_name = "\\ \041 ' \n \\n \""
|
71
|
+
+ else
|
72
|
+
+ author_name = "\\ \001 ' \n \\n \""
|
73
|
+
+ end
|
74
|
+
topic = Topic.create('author_name' => author_name)
|
75
|
+
assert_equal author_name, Topic.find(topic.id).author_name
|
76
|
+
end
|
77
|
+
Index: migration_test.rb
|
78
|
+
===================================================================
|
79
|
+
--- migration_test.rb (revision 1)
|
80
|
+
+++ migration_test.rb (working copy)
|
81
|
+
@@ -52,8 +52,15 @@
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_add_index
|
85
|
+
- # Limit size of last_name and key columns to support Firebird index limitations
|
86
|
+
- Person.connection.add_column "people", "last_name", :string, :limit => 100
|
87
|
+
+ if current_adapter?(:ODBCAdapter) && ActiveRecord::Base.connection.dbmsName == :informix
|
88
|
+
+ # Index on (last_name, first_name) exceeds max. index width supported by Informix if
|
89
|
+
+ # both columns are created with a default width of 255, in which case
|
90
|
+
+ # Informix may return error -517: "The total size of the index is too large..."
|
91
|
+
+ Person.connection.add_column "people", "last_name", :string, {:limit => 40}
|
92
|
+
+ else
|
93
|
+
+ # Limit size of last_name and key columns to support Firebird index limitations
|
94
|
+
+ Person.connection.add_column "people", "last_name", :string, :limit => 100
|
95
|
+
+ end
|
96
|
+
Person.connection.add_column "people", "key", :string, :limit => 100
|
97
|
+
Person.connection.add_column "people", "administrator", :boolean
|
98
|
+
|
99
|
+
@@ -62,7 +69,8 @@
|
100
|
+
|
101
|
+
# Orcl nds shrt indx nms. Sybs 2.
|
102
|
+
# OpenBase does not have named indexes. You must specify a single column name
|
103
|
+
- unless current_adapter?(:OracleAdapter, :SybaseAdapter, :OpenBaseAdapter)
|
104
|
+
+ unless current_adapter?(:OracleAdapter, :SybaseAdapter, :OpenBaseAdapter) ||
|
105
|
+
+ current_adapter?(:ODBCAdapter) && [:sybase, :oracle].include?(ActiveRecord::Base.connection.dbmsName)
|
106
|
+
assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) }
|
107
|
+
assert_nothing_raised { Person.connection.remove_index("people", :column => ["last_name", "first_name"]) }
|
108
|
+
assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) }
|
109
|
+
@@ -83,7 +91,8 @@
|
110
|
+
|
111
|
+
# Sybase adapter does not support indexes on :boolean columns
|
112
|
+
# OpenBase does not have named indexes. You must specify a single column
|
113
|
+
- unless current_adapter?(:SybaseAdapter, :OpenBaseAdapter)
|
114
|
+
+ unless current_adapter?(:SybaseAdapter, :OpenBaseAdapter) ||
|
115
|
+
+ current_adapter?(:ODBCAdapter) && ActiveRecord::Base.connection.dbmsName == :sybase
|
116
|
+
assert_nothing_raised { Person.connection.add_index("people", %w(last_name first_name administrator), :name => "named_admin") }
|
117
|
+
assert_nothing_raised { Person.connection.remove_index("people", :name => "named_admin") }
|
118
|
+
end
|
119
|
+
@@ -182,7 +191,8 @@
|
120
|
+
|
121
|
+
# SQL Server, Sybase, and SQLite3 will not allow you to add a NOT NULL
|
122
|
+
# column to a table without a default value.
|
123
|
+
- unless current_adapter?(:SQLServerAdapter, :SybaseAdapter, :SQLiteAdapter)
|
124
|
+
+ unless current_adapter?(:SQLServerAdapter, :SybaseAdapter, :SQLiteAdapter) ||
|
125
|
+
+ current_adapter?(:ODBCAdapter) && [:microsoftsqlserver, :sybase].include?(ActiveRecord::Base.connection.dbmsName)
|
126
|
+
def test_add_column_not_null_without_default
|
127
|
+
Person.connection.create_table :testings do |t|
|
128
|
+
t.column :foo, :string
|
129
|
+
@@ -206,7 +216,13 @@
|
130
|
+
Person.connection.enable_identity_insert("testings", true) if current_adapter?(:SybaseAdapter)
|
131
|
+
Person.connection.execute "insert into testings (#{con.quote_column_name('id')}, #{con.quote_column_name('foo')}) values (1, 'hello')"
|
132
|
+
Person.connection.enable_identity_insert("testings", false) if current_adapter?(:SybaseAdapter)
|
133
|
+
- assert_nothing_raised {Person.connection.add_column :testings, :bar, :string, :null => false, :default => "default" }
|
134
|
+
+ if current_adapter?(:ODBCAdapter) && ActiveRecord::Base.connection.dbmsName == :ingres
|
135
|
+
+ # Ingres requires that if 'ALTER TABLE table ADD column' specifies a NOT NULL constraint,
|
136
|
+
+ # then 'WITH DEFAULT' must also be specified *without* a default value.
|
137
|
+
+ assert_nothing_raised {Person.connection.add_column :testings, :bar, :string, :null => false}
|
138
|
+
+ else
|
139
|
+
+ assert_nothing_raised {Person.connection.add_column :testings, :bar, :string, :null => false, :default => "default" }
|
140
|
+
+ end
|
141
|
+
|
142
|
+
assert_raises(ActiveRecord::StatementInvalid) do
|
143
|
+
unless current_adapter?(:OpenBaseAdapter)
|
144
|
+
@@ -310,8 +326,10 @@
|
145
|
+
assert_equal Fixnum, bob.age.class
|
146
|
+
assert_equal Time, bob.birthday.class
|
147
|
+
|
148
|
+
- if current_adapter?(:SQLServerAdapter, :OracleAdapter, :SybaseAdapter)
|
149
|
+
- # Sybase, and Oracle don't differentiate between date/time
|
150
|
+
+ if current_adapter?(:SQLServerAdapter, :OracleAdapter, :SybaseAdapter) ||
|
151
|
+
+ (current_adapter?(:ODBCAdapter) &&
|
152
|
+
+ [:ingres, :oracle, :microsoftsqlserver].include?(ActiveRecord::Base.connection.dbmsName))
|
153
|
+
+ # SQL Server, Sybase, Oracle and Ingres don't differentiate between date/time
|
154
|
+
assert_equal Time, bob.favorite_day.class
|
155
|
+
else
|
156
|
+
assert_equal Date, bob.favorite_day.class
|
157
|
+
@@ -373,27 +391,33 @@
|
158
|
+
assert !Person.column_methods_hash.include?(:last_name)
|
159
|
+
end
|
160
|
+
|
161
|
+
- def test_add_rename
|
162
|
+
- Person.delete_all
|
163
|
+
+ # Ingres, Virtuoso:
|
164
|
+
+ # Neither supports renaming of columns. Skip test.
|
165
|
+
+ unless current_adapter?(:ODBCAdapter) &&
|
166
|
+
+ [:ingres, :virtuoso].include?(ActiveRecord::Base.connection.dbmsName)
|
167
|
+
+ def test_add_rename
|
168
|
+
+ Person.delete_all
|
169
|
+
|
170
|
+
- begin
|
171
|
+
- Person.connection.add_column "people", "girlfriend", :string
|
172
|
+
- Person.reset_column_information
|
173
|
+
- Person.create :girlfriend => 'bobette'
|
174
|
+
+ begin
|
175
|
+
+ Person.connection.add_column "people", "girlfriend", :string
|
176
|
+
+ Person.reset_column_information
|
177
|
+
+ Person.create :girlfriend => 'bobette'
|
178
|
+
|
179
|
+
- Person.connection.rename_column "people", "girlfriend", "exgirlfriend"
|
180
|
+
+ Person.connection.rename_column "people", "girlfriend", "exgirlfriend"
|
181
|
+
|
182
|
+
- Person.reset_column_information
|
183
|
+
- bob = Person.find(:first)
|
184
|
+
+ Person.reset_column_information
|
185
|
+
+ bob = Person.find(:first)
|
186
|
+
|
187
|
+
- assert_equal "bobette", bob.exgirlfriend
|
188
|
+
- ensure
|
189
|
+
- Person.connection.remove_column("people", "girlfriend") rescue nil
|
190
|
+
- Person.connection.remove_column("people", "exgirlfriend") rescue nil
|
191
|
+
+ assert_equal "bobette", bob.exgirlfriend
|
192
|
+
+ ensure
|
193
|
+
+ Person.connection.remove_column("people", "girlfriend") rescue nil
|
194
|
+
+ Person.connection.remove_column("people", "exgirlfriend") rescue nil
|
195
|
+
+ end
|
196
|
+
end
|
197
|
+
-
|
198
|
+
end
|
199
|
+
|
200
|
+
+ # Ingres and Virtuoso don't support renaming of columns. Skip test.
|
201
|
+
+ unless current_adapter?(:ODBCAdapter) && [:ingres, :virtuoso].include?(ActiveRecord::Base.connection.dbmsName)
|
202
|
+
def test_rename_column_using_symbol_arguments
|
203
|
+
begin
|
204
|
+
names_before = Person.find(:all).map(&:first_name)
|
205
|
+
@@ -406,7 +430,9 @@
|
206
|
+
Person.connection.add_column("people","first_name", :string)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
+ end
|
210
|
+
|
211
|
+
+ unless current_adapter?(:ODBCAdapter) && [:ingres, :virtuoso].include?(ActiveRecord::Base.connection.dbmsName)
|
212
|
+
def test_rename_column
|
213
|
+
begin
|
214
|
+
names_before = Person.find(:all).map(&:first_name)
|
215
|
+
@@ -419,6 +445,7 @@
|
216
|
+
Person.connection.add_column("people","first_name", :string)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
+ end
|
220
|
+
|
221
|
+
def test_rename_column_with_sql_reserved_word
|
222
|
+
begin
|
223
|
+
@@ -441,6 +468,8 @@
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
+ # Ingres doesn't support renaming of tables. Skip test.
|
228
|
+
+ unless current_adapter?(:ODBCAdapter) && ActiveRecord::Base.connection.dbmsName == :ingres
|
229
|
+
def test_rename_table
|
230
|
+
begin
|
231
|
+
ActiveRecord::Base.connection.create_table :octopuses do |t|
|
232
|
+
@@ -461,6 +490,7 @@
|
233
|
+
ActiveRecord::Base.connection.drop_table :octopi rescue nil
|
234
|
+
end
|
235
|
+
end
|
236
|
+
+ end
|
237
|
+
|
238
|
+
def test_change_column_nullability
|
239
|
+
Person.delete_all
|
240
|
+
@@ -475,6 +505,8 @@
|
241
|
+
assert Person.columns_hash["funny"].null, "Column 'funny' must allow nulls again at this point"
|
242
|
+
end
|
243
|
+
|
244
|
+
+ # Ingres doesn't support renaming of tables. Skip test.
|
245
|
+
+ unless current_adapter?(:ODBCAdapter) && ActiveRecord::Base.connection.dbmsName == :ingres
|
246
|
+
def test_rename_table_with_an_index
|
247
|
+
begin
|
248
|
+
ActiveRecord::Base.connection.create_table :octopuses do |t|
|
249
|
+
@@ -497,18 +529,34 @@
|
250
|
+
ActiveRecord::Base.connection.drop_table :octopi rescue nil
|
251
|
+
end
|
252
|
+
end
|
253
|
+
+ end
|
254
|
+
|
255
|
+
+ # Virtuoso disallows virtually all column type conversions.
|
256
|
+
+ # Conversion between any of the native types used by the ActiveRecord generic types is not allowed.
|
257
|
+
+ # Skip the test.
|
258
|
+
+ unless current_adapter?(:ODBCAdapter) && [:virtuoso].include?(ActiveRecord::Base.connection.dbmsName)
|
259
|
+
def test_change_column
|
260
|
+
- Person.connection.add_column 'people', 'age', :integer
|
261
|
+
+ #Ingres doesn't support changing an integer column to varchar/text.
|
262
|
+
+ if current_adapter?(:ODBCAdapter) && [:ingres].include?(ActiveRecord::Base.connection.dbmsName)
|
263
|
+
+ initial_type = :integer
|
264
|
+
+ new_type = :float
|
265
|
+
+ else
|
266
|
+
+ initial_type = :integer
|
267
|
+
+ new_type = :string
|
268
|
+
+ end
|
269
|
+
+
|
270
|
+
+ Person.connection.add_column 'people', 'age', initial_type
|
271
|
+
old_columns = Person.connection.columns(Person.table_name, "#{name} Columns")
|
272
|
+
- assert old_columns.find { |c| c.name == 'age' and c.type == :integer }
|
273
|
+
+ assert old_columns.find { |c| c.name == 'age' and c.type == initial_type }
|
274
|
+
|
275
|
+
- assert_nothing_raised { Person.connection.change_column "people", "age", :string }
|
276
|
+
+ assert_nothing_raised { Person.connection.change_column "people", "age", new_type }
|
277
|
+
|
278
|
+
new_columns = Person.connection.columns(Person.table_name, "#{name} Columns")
|
279
|
+
- assert_nil new_columns.find { |c| c.name == 'age' and c.type == :integer }
|
280
|
+
- assert new_columns.find { |c| c.name == 'age' and c.type == :string }
|
281
|
+
+ assert_nil new_columns.find { |c| c.name == 'age' and c.type == initial_type }
|
282
|
+
+ assert new_columns.find { |c| c.name == 'age' and c.type == new_type }
|
283
|
+
|
284
|
+
+ # Sybase ASE's ALTER TABLE doesn't support altering a column's DEFAULT definition.
|
285
|
+
+ unless current_adapter?(:ODBCAdapter) && [:sybase].include?(ActiveRecord::Base.connection.dbmsName)
|
286
|
+
old_columns = Topic.connection.columns(Topic.table_name, "#{name} Columns")
|
287
|
+
assert old_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == true }
|
288
|
+
assert_nothing_raised { Topic.connection.change_column :topics, :approved, :boolean, :default => false }
|
289
|
+
@@ -516,8 +564,12 @@
|
290
|
+
assert_nil new_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == true }
|
291
|
+
assert new_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == false }
|
292
|
+
assert_nothing_raised { Topic.connection.change_column :topics, :approved, :boolean, :default => true }
|
293
|
+
+ end
|
294
|
+
+ end
|
295
|
+
end
|
296
|
+
|
297
|
+
+ # Sybase ASE's ALTER TABLE doesn't support altering a column's DEFAULT definition.
|
298
|
+
+ unless current_adapter?(:ODBCAdapter) && [:ingres, :sybase].include?(ActiveRecord::Base.connection.dbmsName)
|
299
|
+
def test_change_column_with_nil_default
|
300
|
+
Person.connection.add_column "people", "contributor", :boolean, :default => true
|
301
|
+
Person.reset_column_information
|
302
|
+
@@ -530,7 +582,11 @@
|
303
|
+
ensure
|
304
|
+
Person.connection.remove_column("people", "contributor") rescue nil
|
305
|
+
end
|
306
|
+
+ end
|
307
|
+
|
308
|
+
+ # Ingres doesn't support ALTER TABLE ADD COLUMN WITH NULL WITH DEFAULT.
|
309
|
+
+ # Sybase ASE's ALTER TABLE doesn't support altering a column's DEFAULT definition.
|
310
|
+
+ unless current_adapter?(:ODBCAdapter) && [:ingres, :sybase].include?(ActiveRecord::Base.connection.dbmsName)
|
311
|
+
def test_change_column_with_new_default
|
312
|
+
Person.connection.add_column "people", "administrator", :boolean, :default => true
|
313
|
+
Person.reset_column_information
|
314
|
+
@@ -542,12 +598,16 @@
|
315
|
+
ensure
|
316
|
+
Person.connection.remove_column("people", "administrator") rescue nil
|
317
|
+
end
|
318
|
+
+ end
|
319
|
+
|
320
|
+
+ # Sybase ASE's ALTER TABLE doesn't support altering a column's DEFAULT definition.
|
321
|
+
+ unless current_adapter?(:ODBCAdapter) && [:sybase].include?(ActiveRecord::Base.connection.dbmsName)
|
322
|
+
def test_change_column_default
|
323
|
+
Person.connection.change_column_default "people", "first_name", "Tester"
|
324
|
+
Person.reset_column_information
|
325
|
+
assert_equal "Tester", Person.new.first_name
|
326
|
+
end
|
327
|
+
+ end
|
328
|
+
|
329
|
+
def test_change_column_quotes_column_names
|
330
|
+
Person.connection.create_table :testings do |t|
|
331
|
+
@@ -561,11 +621,14 @@
|
332
|
+
Person.connection.drop_table :testings rescue nil
|
333
|
+
end
|
334
|
+
|
335
|
+
+ # Sybase ASE's ALTER TABLE doesn't support altering a column's DEFAULT definition.
|
336
|
+
+ unless current_adapter?(:ODBCAdapter) && [:sybase].include?(ActiveRecord::Base.connection.dbmsName)
|
337
|
+
def test_change_column_default_to_null
|
338
|
+
Person.connection.change_column_default "people", "first_name", nil
|
339
|
+
Person.reset_column_information
|
340
|
+
assert_nil Person.new.first_name
|
341
|
+
end
|
342
|
+
+ end
|
343
|
+
|
344
|
+
def test_add_table
|
345
|
+
assert !Reminder.table_exists?
|
346
|
+
@@ -797,8 +860,19 @@
|
347
|
+
Person.connection.drop_table :binary_testings rescue nil
|
348
|
+
|
349
|
+
assert_nothing_raised {
|
350
|
+
- Person.connection.create_table :binary_testings do |t|
|
351
|
+
- t.column "data", :binary, :null => false
|
352
|
+
+ if current_adapter?(:ODBCAdapter) && [:informix, :ingres].include?(ActiveRecord::Base.connection.dbmsName)
|
353
|
+
+ # Specifying a non-null default generates the following error:
|
354
|
+
+ # Informix:
|
355
|
+
+ # "Cannot specify non-null default value for blob column. (-594)"
|
356
|
+
+ # Ingres:
|
357
|
+
+ # "Cannot create a default on column of type 'long byte'"
|
358
|
+
+ Person.connection.create_table :binary_testings do |t|
|
359
|
+
+ t.column "data", :binary
|
360
|
+
+ end
|
361
|
+
+ else
|
362
|
+
+ Person.connection.create_table :binary_testings do |t|
|
363
|
+
+ t.column "data", :binary, :null => false
|
364
|
+
+ end
|
365
|
+
end
|
366
|
+
}
|
367
|
+
|