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.
Files changed (74) hide show
  1. data/AUTHORS +16 -0
  2. data/COPYING +21 -0
  3. data/ChangeLog +139 -0
  4. data/LICENSE +5 -0
  5. data/NEWS +25 -0
  6. data/README +229 -0
  7. data/lib/active_record/connection_adapters/odbc_adapter.rb +1950 -0
  8. data/lib/active_record/vendor/odbcext_db2.rb +87 -0
  9. data/lib/active_record/vendor/odbcext_informix.rb +144 -0
  10. data/lib/active_record/vendor/odbcext_informix_col.rb +45 -0
  11. data/lib/active_record/vendor/odbcext_ingres.rb +156 -0
  12. data/lib/active_record/vendor/odbcext_microsoftsqlserver.rb +216 -0
  13. data/lib/active_record/vendor/odbcext_microsoftsqlserver_col.rb +40 -0
  14. data/lib/active_record/vendor/odbcext_mysql.rb +174 -0
  15. data/lib/active_record/vendor/odbcext_oracle.rb +219 -0
  16. data/lib/active_record/vendor/odbcext_postgresql.rb +158 -0
  17. data/lib/active_record/vendor/odbcext_progress.rb +139 -0
  18. data/lib/active_record/vendor/odbcext_progress89.rb +259 -0
  19. data/lib/active_record/vendor/odbcext_sqlanywhere.rb +115 -0
  20. data/lib/active_record/vendor/odbcext_sqlanywhere_col.rb +49 -0
  21. data/lib/active_record/vendor/odbcext_sybase.rb +213 -0
  22. data/lib/active_record/vendor/odbcext_sybase_col.rb +49 -0
  23. data/lib/active_record/vendor/odbcext_virtuoso.rb +158 -0
  24. data/lib/odbc_adapter.rb +28 -0
  25. data/support/lib/active_record/connection_adapters/abstract/schema_definitions.rb +259 -0
  26. data/support/odbc_rails.diff +367 -0
  27. data/support/pack_odbc.rb +119 -0
  28. data/support/rake/rails_plugin_package_task.rb +212 -0
  29. data/support/rake_fixes/README +6 -0
  30. data/support/rake_fixes/databases.dif +13 -0
  31. data/support/test/base_test.rb +1765 -0
  32. data/support/test/migration_test.rb +1007 -0
  33. data/test/connections/native_odbc/connection.rb +137 -0
  34. data/test/fixtures/db_definitions/db2.drop.sql +33 -0
  35. data/test/fixtures/db_definitions/db2.sql +237 -0
  36. data/test/fixtures/db_definitions/db22.drop.sql +2 -0
  37. data/test/fixtures/db_definitions/db22.sql +5 -0
  38. data/test/fixtures/db_definitions/informix.drop.sql +33 -0
  39. data/test/fixtures/db_definitions/informix.sql +223 -0
  40. data/test/fixtures/db_definitions/informix2.drop.sql +2 -0
  41. data/test/fixtures/db_definitions/informix2.sql +5 -0
  42. data/test/fixtures/db_definitions/ingres.drop.sql +68 -0
  43. data/test/fixtures/db_definitions/ingres.sql +252 -0
  44. data/test/fixtures/db_definitions/ingres2.drop.sql +2 -0
  45. data/test/fixtures/db_definitions/ingres2.sql +5 -0
  46. data/test/fixtures/db_definitions/mysql.drop.sql +33 -0
  47. data/test/fixtures/db_definitions/mysql.sql +238 -0
  48. data/test/fixtures/db_definitions/mysql2.drop.sql +2 -0
  49. data/test/fixtures/db_definitions/mysql2.sql +5 -0
  50. data/test/fixtures/db_definitions/oracle_odbc.drop.sql +72 -0
  51. data/test/fixtures/db_definitions/oracle_odbc.sql +296 -0
  52. data/test/fixtures/db_definitions/oracle_odbc2.drop.sql +2 -0
  53. data/test/fixtures/db_definitions/oracle_odbc2.sql +6 -0
  54. data/test/fixtures/db_definitions/postgresql.drop.sql +38 -0
  55. data/test/fixtures/db_definitions/postgresql.sql +267 -0
  56. data/test/fixtures/db_definitions/postgresql2.drop.sql +2 -0
  57. data/test/fixtures/db_definitions/postgresql2.sql +5 -0
  58. data/test/fixtures/db_definitions/progress.drop.sql +67 -0
  59. data/test/fixtures/db_definitions/progress.sql +255 -0
  60. data/test/fixtures/db_definitions/progress2.drop.sql +2 -0
  61. data/test/fixtures/db_definitions/progress2.sql +6 -0
  62. data/test/fixtures/db_definitions/sqlserver.drop.sql +35 -0
  63. data/test/fixtures/db_definitions/sqlserver.sql +247 -0
  64. data/test/fixtures/db_definitions/sqlserver2.drop.sql +2 -0
  65. data/test/fixtures/db_definitions/sqlserver2.sql +5 -0
  66. data/test/fixtures/db_definitions/sybase.drop.sql +35 -0
  67. data/test/fixtures/db_definitions/sybase.sql +222 -0
  68. data/test/fixtures/db_definitions/sybase2.drop.sql +4 -0
  69. data/test/fixtures/db_definitions/sybase2.sql +5 -0
  70. data/test/fixtures/db_definitions/virtuoso.drop.sql +33 -0
  71. data/test/fixtures/db_definitions/virtuoso.sql +218 -0
  72. data/test/fixtures/db_definitions/virtuoso2.drop.sql +2 -0
  73. data/test/fixtures/db_definitions/virtuoso2.sql +5 -0
  74. metadata +166 -0
@@ -0,0 +1,49 @@
1
+ #
2
+ # $Id: odbcext_sqlanywhere_col.rb,v 1.2 2008/04/22 16:54:57 source Exp $
3
+ #
4
+ # OpenLink ODBC Adapter for Ruby on Rails
5
+ # Copyright (C) 2006 OpenLink Software
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining
8
+ # a copy of this software and associated documentation files (the
9
+ # "Software"), to deal in the Software without restriction, including
10
+ # without limitation the rights to use, copy, modify, merge, publish,
11
+ # distribute, sublicense, and/or sell copies of the Software, and to
12
+ # permit persons to whom the Software is furnished to do so, subject
13
+ # to the following conditions:
14
+ #
15
+ # The above copyright notice and this permission notice shall be
16
+ # included in all copies or substantial portions of the Software.
17
+ #
18
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21
+ # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
22
+ # ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
23
+ # CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
+ #
26
+
27
+ module ODBCColumnExt
28
+
29
+ # Is the column a numeric autoincrementing column?
30
+ def auto_unique?
31
+ @autounique
32
+ end
33
+
34
+ private
35
+
36
+ def autoUnique?
37
+ @nativeType =~ /\bidentity\b/i
38
+ end
39
+
40
+ #private
41
+
42
+ def default_preprocess(nativeType, default)
43
+ return default if default.nil?
44
+ default.replace($2.strip) if default =~ /(DEFAULT +)(.*)/i
45
+ default.replace($1) if default =~ /^'(.*)'$/
46
+ default
47
+ end
48
+
49
+ end # module
@@ -0,0 +1,213 @@
1
+ #
2
+ # $Id: odbcext_sybase.rb,v 1.3 2008/04/13 22:46:09 source Exp $
3
+ #
4
+ # OpenLink ODBC Adapter for Ruby on Rails
5
+ # Copyright (C) 2006 OpenLink Software
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining
8
+ # a copy of this software and associated documentation files (the
9
+ # "Software"), to deal in the Software without restriction, including
10
+ # without limitation the rights to use, copy, modify, merge, publish,
11
+ # distribute, sublicense, and/or sell copies of the Software, and to
12
+ # permit persons to whom the Software is furnished to do so, subject
13
+ # to the following conditions:
14
+ #
15
+ # The above copyright notice and this permission notice shall be
16
+ # included in all copies or substantial portions of the Software.
17
+ #
18
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21
+ # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
22
+ # ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
23
+ # CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
+ #
26
+
27
+ module ODBCExt
28
+
29
+ # ------------------------------------------------------------------------
30
+ # Mandatory methods
31
+ #
32
+
33
+ # #last_insert_id must be implemented for any database which returns
34
+ # false from #prefetch_primary_key?
35
+ def last_insert_id(table, sequence_name, stmt = nil)
36
+ @logger.unknown("ODBCAdapter#last_insert_id>") if @trace
37
+ #TODO: Fixme - Doesn't work with OpenLink TDS driver against Sybase
38
+ #select_value("select @@IDENTITY", 'last_insert_id')
39
+ select_value("select max(syb_identity) from #{table}", 'last_insert_id')
40
+ end
41
+
42
+ # ------------------------------------------------------------------------
43
+ # Optional methods
44
+ #
45
+ # These are supplied for a DBMS only if necessary.
46
+ # ODBCAdapter tests for optional methods using Object#respond_to?
47
+
48
+ # Pre action for ODBCAdapter#insert
49
+ def pre_insert(sql, name, pk, id_value, sequence_name)
50
+ @iiTable = get_table_name(sql)
51
+ @iiCol = get_autounique_column(@iiTable)
52
+ @iiEnabled = false
53
+
54
+ if @iiCol != nil
55
+ if query_contains_autounique_col(sql, @iiCol)
56
+ begin
57
+ @connection.do(enable_identity_insert(@iiTable, true))
58
+ @iiEnabled = true
59
+ rescue Exception => e
60
+ raise ActiveRecordError, "IDENTITY_INSERT could not be turned on"
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ # Post action for ODBCAdapter#insert
67
+ def post_insert(sql, name, pk, id_value, sequence_name)
68
+ if @iiEnabled
69
+ begin
70
+ @connection.do(enable_identity_insert(@iiTable, false))
71
+ rescue Exception => e
72
+ raise ActiveRecordError, "IDENTITY_INSERT could not be turned off"
73
+ end
74
+ end
75
+ end
76
+
77
+ # ------------------------------------------------------------------------
78
+ # Method redefinitions
79
+ #
80
+ # DBMS specific methods which override the default implementation
81
+ # provided by the ODBCAdapter core.
82
+
83
+ def rename_table(name, new_name)
84
+ @logger.unknown("ODBCAdapter#rename_table>") if @trace
85
+ execute "EXEC sp_rename '#{name}', '#{new_name}'"
86
+ rescue Exception => e
87
+ @logger.unknown("exception=#{e}") if @trace
88
+ raise
89
+ end
90
+
91
+ def remove_column(table_name, column_name)
92
+ @logger.unknown("ODBCAdapter#remove_column>") if @trace
93
+ # Remove default constraints first
94
+ defaults = select_all "select def.name from sysobjects def, syscolumns col, sysobjects tab where col.cdefault = def.id and col.name = '#{column_name}' and tab.name = '#{table_name}' and col.id = tab.id"
95
+ defaults.each {|constraint|
96
+ execute "ALTER TABLE #{quote_table_name(table_name)} DROP CONSTRAINT #{constraint["name"]}"
97
+ }
98
+ execute "ALTER TABLE #{quote_table_name(table_name)} DROP #{quote_column_name(column_name)}"
99
+ rescue Exception => e
100
+ @logger.unknown("exception=#{e}") if @trace
101
+ raise
102
+ end
103
+
104
+ def change_column(table_name, column_name, type, options = {})
105
+ @logger.unknown("ODBCAdapter#change_column>") if @trace
106
+ if options.include?(:default)
107
+ # Sybase ASE's ALTER TABLE statement doesn't allow a column's DEFAULT to be changed.
108
+ raise ActiveRecord::ActiveRecordError,
109
+ "Sybase ASE does not support changing a column's DEFAULT definition"
110
+ end
111
+ execute "ALTER TABLE #{table_name} MODIFY #{column_name} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
112
+ rescue Exception => e
113
+ @logger.unknown("exception=#{e}") if @trace
114
+ raise
115
+ end
116
+
117
+ def rename_column(table_name, column_name, new_column_name)
118
+ @logger.unknown("ODBCAdapter#rename_column>") if @trace
119
+ execute "EXEC sp_rename '#{table_name}.#{column_name}', '#{new_column_name}'"
120
+ rescue Exception => e
121
+ @logger.unknown("exception=#{e}") if @trace
122
+ raise
123
+ end
124
+
125
+ def remove_index(table_name, options = {})
126
+ @logger.unknown("ODBCAdapter#remove_index>") if @trace
127
+ execute "DROP INDEX #{table_name}.#{quote_column_name(index_name(table_name, options))}"
128
+ rescue Exception => e
129
+ @logger.unknown("exception=#{e}") if @trace
130
+ raise
131
+ end
132
+
133
+ def tables(name = nil)
134
+ # Hide system tables.
135
+ super(name).delete_if {|t| t =~ /^sys/ }
136
+ end
137
+
138
+ def indexes(table_name, name = nil)
139
+ # Hide primary key indexes.
140
+ # Primary key indexes take the form <tablename>_<primary key name>_<integer>
141
+ super(table_name, name).delete_if { |i| i.unique && i.name =~ /^\w+_\w+_\d+$/ }
142
+ end
143
+
144
+ def add_column_options!(sql, options) # :nodoc:
145
+ @logger.unknown("ODBCAdapter#add_column_options!>") if @trace
146
+ @logger.unknown("args=[#{sql}]") if @trace
147
+ sql << " DEFAULT #{quote(options[:default], options[:column])}" if options_include_default?(options)
148
+
149
+ if column_type_allows_null?(sql, options)
150
+ sql << (options[:null] == false ? " NOT NULL" : " NULL")
151
+ end
152
+ sql
153
+ rescue Exception => e
154
+ @logger.unknown("exception=#{e}") if @trace
155
+ raise ActiveRecord::StatementInvalid, e.message
156
+ end
157
+
158
+ # ------------------------------------------------------------------------
159
+ # Private methods to support methods above
160
+ #
161
+ private
162
+
163
+ def get_table_name(sql)
164
+ if sql =~ /^\s*insert\s+into\s+([^\(\s]+)\s*|^\s*update\s+([^\(\s]+)\s*/i
165
+ $1
166
+ elsif sql =~ /from\s+([^\(\s]+)\s*/i
167
+ $1
168
+ else
169
+ nil
170
+ end end
171
+
172
+ def get_autounique_column(table_name)
173
+ @table_columns = {} unless @table_columns
174
+ @table_columns[table_name] = columns(table_name) if @table_columns[table_name] == nil
175
+ @table_columns[table_name].each do |col|
176
+ return col.name if col.auto_unique?
177
+ end
178
+
179
+ return nil
180
+ end
181
+
182
+ def query_contains_autounique_col(sql, col)
183
+ sql =~ /(\[#{col}\])|("#{col}")/
184
+ end
185
+
186
+ def enable_identity_insert(table_name, enable = true)
187
+ if has_autounique_column(table_name)
188
+ "SET IDENTITY_INSERT #{table_name} #{enable ? 'ON' : 'OFF'}"
189
+ end
190
+ end
191
+
192
+ def has_autounique_column(table_name)
193
+ !get_autounique_column(table_name).nil?
194
+ end
195
+
196
+ def column_type_allows_null?(sql, options)
197
+ # Sybase columns are NOT NULL by default, so explicitly set NULL
198
+ # if :null option is omitted. Disallow NULLs for boolean.
199
+ col = options[:column]
200
+ return false if col && col[:type] == :primary_key
201
+
202
+ # Force options[:null] to be ignored for BIT (:boolea) columns
203
+ # by returning false
204
+ isBitCol = !(sql =~ /\s+bit(\s+default)?/i).nil? || (col && col[:type] == :boolean)
205
+ hasDefault = !$1.nil? || options[:default]
206
+
207
+ # If no default clause found on a boolean column, add one.
208
+ sql << " DEFAULT 0" if isBitCol && !hasDefault
209
+
210
+ !isBitCol
211
+ end
212
+
213
+ end # module
@@ -0,0 +1,49 @@
1
+ #
2
+ # $Id: odbcext_sybase_col.rb,v 1.1 2006/12/06 14:42:11 source Exp $
3
+ #
4
+ # OpenLink ODBC Adapter for Ruby on Rails
5
+ # Copyright (C) 2006 OpenLink Software
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining
8
+ # a copy of this software and associated documentation files (the
9
+ # "Software"), to deal in the Software without restriction, including
10
+ # without limitation the rights to use, copy, modify, merge, publish,
11
+ # distribute, sublicense, and/or sell copies of the Software, and to
12
+ # permit persons to whom the Software is furnished to do so, subject
13
+ # to the following conditions:
14
+ #
15
+ # The above copyright notice and this permission notice shall be
16
+ # included in all copies or substantial portions of the Software.
17
+ #
18
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21
+ # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
22
+ # ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
23
+ # CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
+ #
26
+
27
+ module ODBCColumnExt
28
+
29
+ # Is the column a numeric autoincrementing column?
30
+ def auto_unique?
31
+ @autounique
32
+ end
33
+
34
+ private
35
+
36
+ def autoUnique?
37
+ @nativeType =~ /\bidentity\b/i
38
+ end
39
+
40
+ #private
41
+
42
+ def default_preprocess(nativeType, default)
43
+ return default if default.nil?
44
+ default.replace($2.strip) if default =~ /(DEFAULT +)(.*)/i
45
+ default.replace($1) if default =~ /^'(.*)'$/
46
+ default
47
+ end
48
+
49
+ end # module
@@ -0,0 +1,158 @@
1
+ #
2
+ # $Id: odbcext_virtuoso.rb,v 1.3 2008/04/13 22:46:09 source Exp $
3
+ #
4
+ # OpenLink ODBC Adapter for Ruby on Rails
5
+ # Copyright (C) 2006 OpenLink Software
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining
8
+ # a copy of this software and associated documentation files (the
9
+ # "Software"), to deal in the Software without restriction, including
10
+ # without limitation the rights to use, copy, modify, merge, publish,
11
+ # distribute, sublicense, and/or sell copies of the Software, and to
12
+ # permit persons to whom the Software is furnished to do so, subject
13
+ # to the following conditions:
14
+ #
15
+ # The above copyright notice and this permission notice shall be
16
+ # included in all copies or substantial portions of the Software.
17
+ #
18
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21
+ # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
22
+ # ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
23
+ # CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
+ #
26
+
27
+ module ODBCExt
28
+
29
+ # ------------------------------------------------------------------------
30
+ # Mandatory methods
31
+ #
32
+
33
+ # #last_insert_id must be implemented for any database which returns
34
+ # false from #prefetch_primary_key?
35
+
36
+ def last_insert_id(table, sequence_name, stmt = nil)
37
+ @logger.unknown("ODBCAdapter#last_insert_id>") if @trace
38
+ # 1049 (SQL_LASTSERIAL) is an ODBC extension for SQLGetStmtOption
39
+ stmt.get_option(1049)
40
+ end
41
+
42
+
43
+ # ------------------------------------------------------------------------
44
+ # Optional methods
45
+ #
46
+ # These are supplied for a DBMS only if necessary.
47
+ # ODBCAdapter tests for optional methods using Object#respond_to?
48
+
49
+ # Pre action for ODBCAdapter#insert
50
+ # def pre_insert(sql, name, pk, id_value, sequence_name)
51
+ # end
52
+
53
+ # Post action for ODBCAdapter#insert
54
+ # def post_insert(sql, name, pk, id_value, sequence_name)
55
+ # end
56
+
57
+ def set_sequence(table_name, pk)
58
+ begin
59
+ stmt = @connection.run("select max(#{pk}) + 1 from #{table_name}")
60
+ next_pk_val = stmt.fetch
61
+ stmt.drop
62
+ flds = table_name.split('.')
63
+ @connection.do("sequence_set('#{flds[0]}.#{flds[1]}.#{table_name}.#{pk}', #{next_pk_val}, 0)")
64
+ return true
65
+ rescue Exception => e
66
+ @logger.unknown("exception=#{e}") if @trace
67
+ end
68
+ return false
69
+ end
70
+
71
+ # ------------------------------------------------------------------------
72
+ # Method redefinitions
73
+ #
74
+ # DBMS specific methods which override the default implementation
75
+ # provided by the ODBCAdapter core.
76
+
77
+ def type_to_sql(type, limit = nil, precision = nil, scale = nil)
78
+ if type == :decimal
79
+ # Force an explicit scale if none supplied to specify the fixed
80
+ # point form of Virtuoso's DECIMAL type. If no scale is specified,
81
+ # the Virtuoso DECIMAL type stores floating point values.
82
+ precision ||= 32
83
+ scale ||= 0
84
+ end
85
+ super(type, limit, precision, scale)
86
+ end
87
+
88
+ def quote_string(s)
89
+ s.gsub(/\\/, '\&\&').gsub(/'/, "''")
90
+ end
91
+
92
+ def quoted_date(value)
93
+ @logger.unknown("ODBCAdapter#quoted_date>") if @trace
94
+ @logger.unknown("args=[#{value}]") if @trace
95
+ # Ruby Time class includes a date component and so must be
96
+ # mapped to a Virtuoso DateTime type, not a Virtuoso Time type.
97
+ if value.acts_like?(:time) # Time, DateTime
98
+ %Q!stringdate('#{value.strftime("%Y-%m-%d %H:%M:%S")}')!
99
+ else # Date
100
+ %Q!d('#{value.strftime("%Y-%m-%d")}')!
101
+ end
102
+ end
103
+
104
+ def rename_table(name, new_name)
105
+ @logger.unknown("ODBCAdapter#rename_table>") if @trace
106
+ @logger.unknown("args=[#{name}|#{new_name}]") if @trace
107
+ execute "ALTER TABLE #{name} RENAME #{new_name}"
108
+ rescue Exception => e
109
+ @logger.unknown("exception=#{e}") if @trace
110
+ raise ActiveRecord::ActiveRecordError, e.message
111
+ end
112
+
113
+ def change_column(table_name, column_name, type, options = {})
114
+ @logger.unknown("ODBCAdapter#change_column>") if @trace
115
+ @logger.unknown("args=[#{table_name}|#{column_name}|#{type}]") if @trace
116
+ change_column_sql = "ALTER TABLE #{table_name} MODIFY #{column_name} " +
117
+ "#{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
118
+
119
+ # Add any :null and :default options
120
+ add_column_options!(change_column_sql, options)
121
+ execute(change_column_sql)
122
+ rescue Exception => e
123
+ @logger.unknown("exception=#{e}") if @trace
124
+ raise ActiveRecord::ActiveRecordError, e.message
125
+ end
126
+
127
+ def change_column_default(table_name, column_name, default)
128
+ @logger.unknown("ODBCAdapter#change_column_default>") if @trace
129
+ @logger.unknown("args=[#{table_name}|#{column_name}]") if @trace
130
+ col = columns(table_name).find {|c| c.name == column_name.to_s }
131
+ change_column(table_name, column_name, col.type, :default => default,
132
+ :limit => col.limit, :precision => col.precision, :scale => col.scale)
133
+ rescue Exception => e
134
+ @logger.unknown("exception=#{e}") if @trace
135
+ raise ActiveRecord::ActiveRecordError, e.message
136
+ end
137
+
138
+ def remove_index(table_name, options = {})
139
+ @logger.unknown("ODBCAdapter#remove_index>") if @trace
140
+ @logger.unknown("args=[#{table_name}]") if @trace
141
+ execute "DROP INDEX #{quote_column_name(index_name(table_name, options))} #{table_name}"
142
+ rescue Exception => e
143
+ @logger.unknown("exception=#{e}") if @trace
144
+ raise ActiveRecord::ActiveRecordError, e.message
145
+ end
146
+
147
+ def indexes(table_name, name = nil)
148
+ # Virtuoso creates a unique index for a table's primary key.
149
+ # Hide any such index. The index name matches the table name.
150
+ #
151
+ # If this isn't done...
152
+ # Rails' 'rake test_units' attempts to create this index explicitly,
153
+ # but Virtuoso rejects this as the index has already been created
154
+ # automatically when the table was defined.
155
+ super(table_name, name).delete_if { |i| i.unique && i.name == table_name }
156
+ end
157
+
158
+ end