odbc-rails 1.2

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 (66) hide show
  1. data/AUTHORS +16 -0
  2. data/COPYING +21 -0
  3. data/ChangeLog +89 -0
  4. data/LICENSE +5 -0
  5. data/NEWS +12 -0
  6. data/README +282 -0
  7. data/lib/active_record/connection_adapters/odbc_adapter.rb +1792 -0
  8. data/lib/active_record/vendor/odbcext_db2.rb +87 -0
  9. data/lib/active_record/vendor/odbcext_informix.rb +132 -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 +185 -0
  13. data/lib/active_record/vendor/odbcext_microsoftsqlserver_col.rb +40 -0
  14. data/lib/active_record/vendor/odbcext_mysql.rb +136 -0
  15. data/lib/active_record/vendor/odbcext_oracle.rb +220 -0
  16. data/lib/active_record/vendor/odbcext_postgresql.rb +179 -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_sybase.rb +212 -0
  20. data/lib/active_record/vendor/odbcext_sybase_col.rb +49 -0
  21. data/lib/active_record/vendor/odbcext_virtuoso.rb +146 -0
  22. data/lib/odbc_adapter.rb +28 -0
  23. data/support/lib/active_record/connection_adapters/abstract/schema_definitions.rb +259 -0
  24. data/support/odbc_rails.diff +707 -0
  25. data/support/pack_odbc.rb +119 -0
  26. data/support/rake/rails_plugin_package_task.rb +212 -0
  27. data/support/test/base_test.rb +1349 -0
  28. data/support/test/migration_test.rb +566 -0
  29. data/test/connections/native_odbc/connection.rb +95 -0
  30. data/test/fixtures/db_definitions/db2.drop.sql +30 -0
  31. data/test/fixtures/db_definitions/db2.sql +217 -0
  32. data/test/fixtures/db_definitions/db22.drop.sql +2 -0
  33. data/test/fixtures/db_definitions/db22.sql +5 -0
  34. data/test/fixtures/db_definitions/informix.drop.sql +30 -0
  35. data/test/fixtures/db_definitions/informix.sql +205 -0
  36. data/test/fixtures/db_definitions/informix2.drop.sql +2 -0
  37. data/test/fixtures/db_definitions/informix2.sql +5 -0
  38. data/test/fixtures/db_definitions/ingres.drop.sql +62 -0
  39. data/test/fixtures/db_definitions/ingres.sql +232 -0
  40. data/test/fixtures/db_definitions/ingres2.drop.sql +2 -0
  41. data/test/fixtures/db_definitions/ingres2.sql +5 -0
  42. data/test/fixtures/db_definitions/mysql.drop.sql +30 -0
  43. data/test/fixtures/db_definitions/mysql.sql +219 -0
  44. data/test/fixtures/db_definitions/mysql2.drop.sql +2 -0
  45. data/test/fixtures/db_definitions/mysql2.sql +5 -0
  46. data/test/fixtures/db_definitions/oracle_odbc.drop.sql +64 -0
  47. data/test/fixtures/db_definitions/oracle_odbc.sql +257 -0
  48. data/test/fixtures/db_definitions/oracle_odbc2.drop.sql +2 -0
  49. data/test/fixtures/db_definitions/oracle_odbc2.sql +6 -0
  50. data/test/fixtures/db_definitions/progress.drop.sql +61 -0
  51. data/test/fixtures/db_definitions/progress.sql +234 -0
  52. data/test/fixtures/db_definitions/progress2.drop.sql +2 -0
  53. data/test/fixtures/db_definitions/progress2.sql +6 -0
  54. data/test/fixtures/db_definitions/sqlserver.drop.sql +30 -0
  55. data/test/fixtures/db_definitions/sqlserver.sql +203 -0
  56. data/test/fixtures/db_definitions/sqlserver2.drop.sql +2 -0
  57. data/test/fixtures/db_definitions/sqlserver2.sql +5 -0
  58. data/test/fixtures/db_definitions/sybase.drop.sql +31 -0
  59. data/test/fixtures/db_definitions/sybase.sql +204 -0
  60. data/test/fixtures/db_definitions/sybase2.drop.sql +4 -0
  61. data/test/fixtures/db_definitions/sybase2.sql +5 -0
  62. data/test/fixtures/db_definitions/virtuoso.drop.sql +30 -0
  63. data/test/fixtures/db_definitions/virtuoso.sql +200 -0
  64. data/test/fixtures/db_definitions/virtuoso2.drop.sql +2 -0
  65. data/test/fixtures/db_definitions/virtuoso2.sql +5 -0
  66. metadata +149 -0
@@ -0,0 +1,87 @@
1
+ #
2
+ # $Id: odbcext_db2.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 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
+ @logger.unknown("args=[#{table}]") if @trace
39
+ select_value("VALUES IDENTITY_VAL_LOCAL()", 'last_insert_id')
40
+ end
41
+
42
+ # ------------------------------------------------------------------------
43
+ # Method redefinitions
44
+ #
45
+ # DBMS specific methods which override the default implementation
46
+ # provided by the ODBCAdapter core.
47
+
48
+ def rename_table(name, new_name)
49
+ @logger.unknown("ODBCAdapter#rename_table>") if @trace
50
+ @logger.unknown("args=[#{name}|#{new_name}]") if @trace
51
+ execute "RENAME TABLE #{name} TO #{new_name}"
52
+ rescue Exception => e
53
+ @logger.unknown("exception=#{e}") if @trace
54
+ raise ActiveRecord::ActiveRecordError, e.message
55
+ end
56
+
57
+ def change_column_default(table_name, column_name, default)
58
+ @logger.unknown("ODBCAdapter#change_column_default>") if @trace
59
+ @logger.unknown("args=[#{table_name}|#{column_name}]") if @trace
60
+ execute "ALTER TABLE #{table_name} ALTER #{column_name} SET DEFAULT #{quote(default)}"
61
+ rescue Exception => e
62
+ @logger.unknown("exception=#{e}") if @trace
63
+ raise ActiveRecord::ActiveRecordError, e.message
64
+ end
65
+
66
+ def remove_column(table_name, column_name)
67
+ @logger.unknown("ODBCAdapter#remove_column>\n" +
68
+ "args=[#{table_name}|#{column_name}]\n" +
69
+ "exception=remove_column is not supported") if @trace
70
+ raise ActiveRecord::ActiveRecordError, "remove_column is not supported"
71
+ end
72
+
73
+ def remove_index(table_name, options = {})
74
+ @logger.unknown("ODBCAdapter#remove_index>") if @trace
75
+ @logger.unknown("args=[#{table_name}]") if @trace
76
+ execute "DROP INDEX #{quote_column_name(index_name(table_name, options))}"
77
+ rescue Exception => e
78
+ @logger.unknown("exception=#{e}") if @trace
79
+ raise ActiveRecord::ActiveRecordError, e.message
80
+ end
81
+
82
+ def indexes(table_name, name = nil)
83
+ # Hide primary key indexes
84
+ super(table_name, name).delete_if { |i| i.unique && i.name =~ /^sql\d+$/ }
85
+ end
86
+
87
+ end # module
@@ -0,0 +1,132 @@
1
+ #
2
+ # $Id: odbcext_informix.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 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
+ @logger.unknown("args=[#{table}]") if @trace
39
+ # 1049 (SQL_LASTSERIAL) is an ODBC extension for SQLGetStmtOption
40
+ stmt.get_option(1049)
41
+ end
42
+
43
+ # ------------------------------------------------------------------------
44
+ # Method redefinitions
45
+ #
46
+ # DBMS specific methods which override the default implementation
47
+ # provided by the ODBCAdapter core.
48
+
49
+ def quoted_date(value)
50
+ @logger.unknown("ODBCAdapter#quoted_date>") if @trace
51
+ @logger.unknown("args=[#{value}]") if @trace
52
+ # Informix's DBTIME and DBDATE environment variables should be set to:
53
+ # DBTIME=%Y-%m-%d %H:%M:%S
54
+ # DBDATE=Y4MD-
55
+ case value
56
+ when Time, DateTime
57
+ %Q!'#{value.strftime("%Y-%m-%d %H:%M:%S.")}'!
58
+ when Date
59
+ %Q!'#{value.strftime("%Y-%m-%d")}'!
60
+ end
61
+ end
62
+
63
+ def rename_table(name, new_name)
64
+ @logger.unknown("ODBCAdapter#rename_table>") if @trace
65
+ @logger.unknown("args=[#{name}|#{new_name}]") if @trace
66
+ execute "RENAME TABLE #{name} TO #{new_name}"
67
+ rescue Exception => e
68
+ @logger.unknown("exception=#{e}") if @trace
69
+ raise ActiveRecord::ActiveRecordError, e.message
70
+ end
71
+
72
+ def change_column(table_name, column_name, type, options = {})
73
+ @logger.unknown("ODBCAdapter#change_column>") if @trace
74
+ @logger.unknown("args=[#{table_name}|#{column_name}|#{type}]") if @trace
75
+ change_column_sql = "ALTER TABLE #{table_name} MODIFY #{column_name} " +
76
+ "#{type_to_sql(type)}"
77
+ # Add any :null and :default options
78
+ add_column_options!(change_column_sql, options)
79
+ execute(change_column_sql)
80
+ rescue Exception => e
81
+ @logger.unknown("exception=#{e}") if @trace
82
+ raise ActiveRecord::ActiveRecordError, e.message
83
+ end
84
+
85
+ def change_column_default(table_name, column_name, default)
86
+ @logger.unknown("ODBCAdapter#change_column_default>") if @trace
87
+ @logger.unknown("args=[#{table_name}|#{column_name}]") if @trace
88
+ change_column(table_name, column_name, nil, {:default => default})
89
+ rescue Exception => e
90
+ @logger.unknown("exception=#{e}") if @trace
91
+ raise ActiveRecord::ActiveRecordError, e.message
92
+ end
93
+
94
+ def rename_column(table_name, column_name, new_column_name)
95
+ @logger.unknown("ODBCAdapter#rename_column>") if @trace
96
+ @logger.unknown("args=[#{table_name}|#{column_name}|#{new_column_name}]") if @trace
97
+ execute "RENAME COLUMN #{table_name}.#{column_name} TO #{new_column_name}"
98
+ rescue Exception => e
99
+ @logger.unknown("exception=#{e}") if @trace
100
+ raise ActiveRecord::ActiveRecordError, e.message
101
+ end
102
+
103
+ def remove_index(table_name, options = {})
104
+ @logger.unknown("ODBCAdapter#remove_index>") if @trace
105
+ @logger.unknown("args=[#{table_name}]") if @trace
106
+ execute "DROP INDEX #{quote_column_name(index_name(table_name, options))}"
107
+ rescue Exception => e
108
+ @logger.unknown("exception=#{e}") if @trace
109
+ raise ActiveRecord::ActiveRecordError, e.message
110
+ end
111
+
112
+ def tables(name = nil)
113
+ # Hide the system tables. Some contain columns which don't have an
114
+ # equivalent ODBC SQL type which causes problems with #columns.
115
+ super(name).delete_if {|t| t =~ /^sys/i }
116
+ end
117
+
118
+ def indexes(table_name, name = nil)
119
+ # Informix creates a unique index for a table's primary key.
120
+ # Hide any such index. The index name takes the form ddd_ddd.
121
+ # (Indexes created through 'CREATE INDEX' must have a name starting
122
+ # with a letter or an # underscore.)
123
+ #
124
+ # If this isn't done...
125
+ # Rails' 'rake test_units' attempts to create primary key indexes
126
+ # explicitly when creating the test database schema. Informix rejects
127
+ # the resulting 'CREATE UNIQUE INDEX ddd_ddd' commands with a syntax
128
+ # error.
129
+ super(table_name, name).delete_if { |i| i.unique && i.name =~ /\d+_\d+/ }
130
+ end
131
+
132
+ end # module
@@ -0,0 +1,45 @@
1
+ #
2
+ # $Id: odbcext_informix_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
+ #private
30
+
31
+ def default_preprocess(nativeType, default)
32
+ return default if default.nil?
33
+ if ["INTEGER", "SMALLINT"].include?(nativeType)
34
+ # Literal default value is encoded in two parts, space separated
35
+ # Strip off first part
36
+ dflt = default.strip
37
+ if (indx = dflt.index(" "))
38
+ dflt = dflt[(indx + 1)...dflt.length]
39
+ default.replace(dflt)
40
+ end
41
+ end
42
+ default
43
+ end
44
+
45
+ end # module
@@ -0,0 +1,156 @@
1
+ #
2
+ # $Id: odbcext_ingres.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
+ require 'active_record/connection_adapters/abstract_adapter'
28
+
29
+ module ODBCExt
30
+
31
+ # ------------------------------------------------------------------------
32
+ # Mandatory methods
33
+ #
34
+
35
+ # #last_insert_id must be implemented for any database which returns
36
+ # false from #prefetch_primary_key?
37
+ # (This adapter returns true for Ingres)
38
+
39
+ #def last_insert_id(table, sequence_name, stmt = nil)
40
+ #end
41
+
42
+ # #next_sequence_value must be implemented for any database which returns
43
+ # true from #prefetch_primary_key?
44
+ #
45
+ # Returns the next sequence value from a sequence generator. Not generally
46
+ # called directly; used by ActiveRecord to get the next primary key value
47
+ # when inserting a new database record (see #prefetch_primary_key?).
48
+ def next_sequence_value(sequence_name)
49
+ @logger.unknown("ODBCAdapter#next_sequence_value>") if @trace
50
+ @logger.unknown("args=[#{sequence_name}]") if @trace
51
+ select_one("select #{sequence_name}.nextval id")['id']
52
+ end
53
+
54
+ # ------------------------------------------------------------------------
55
+ # Optional methods
56
+ #
57
+ # These are supplied for a DBMS only if necessary.
58
+ # ODBCAdapter tests for optional methods using Object#respond_to?
59
+
60
+ # Pre action for ODBCAdapter#insert
61
+ # def pre_insert(sql, name, pk, id_value, sequence_name)
62
+ # end
63
+
64
+ # Post action for ODBCAdapter#insert
65
+ # def post_insert(sql, name, pk, id_value, sequence_name)
66
+ # end
67
+
68
+ # ------------------------------------------------------------------------
69
+ # Method redefinitions
70
+ #
71
+ # DBMS specific methods which override the default implementation
72
+ # provided by the ODBCAdapter core.
73
+
74
+ def create_table(name, options = {})
75
+ @logger.unknown("ODBCAdapter#create_table>") if @trace
76
+ @logger.unknown("args=[#{name}]") if @trace
77
+ #ALTER TABLE ADD COLUMN not allowed with default page size of 2K
78
+ super(name, {:options => "WITH PAGE_SIZE=8192"}.merge(options))
79
+ execute "CREATE SEQUENCE #{name}_seq"
80
+ rescue Exception => e
81
+ @logger.unknown("exception=#{e}") if @trace
82
+ raise ActiveRecord::ActiveRecordError, e.message
83
+ end
84
+
85
+ def drop_table(name)
86
+ @logger.unknown("ODBCAdapter#drop_table>") if @trace
87
+ @logger.unknown("args=[#{name}]") if @trace
88
+ super
89
+ execute "DROP SEQUENCE #{name}_seq"
90
+ rescue Exception => e
91
+ @logger.unknown("exception=#{e}") if @trace
92
+ raise ActiveRecord::ActiveRecordError, e.message
93
+ end
94
+
95
+ def add_column(table_name, column_name, type, options = {})
96
+ @logger.unknown("ODBCAdapter#add_column>") if @trace
97
+ @logger.unknown("args=[#{table_name}|#{column_name}]") if @trace
98
+
99
+ sql = "ALTER TABLE #{table_name} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit])}"
100
+ sql << " DEFAULT #{quote(options[:default], options[:column])}" unless options[:default].nil?
101
+
102
+ # Ingres requires that if 'ALTER TABLE table ADD column' specifies a NOT NULL constraint,
103
+ # then 'WITH DEFAULT' must also be specified *without* a default value.
104
+ # Ingres will report an error if both options[:null] == false && options[:default]
105
+ if options[:null] == false
106
+ sql << " NOT NULL"
107
+ sql << " WITH DEFAULT" if options[:default].nil?
108
+ end
109
+ execute(sql)
110
+ rescue Exception => e
111
+ @logger.unknown("exception=#{e}") if @trace
112
+ raise ActiveRecord::ActiveRecordError, e.message
113
+ end
114
+
115
+ def remove_column(table_name, column_name)
116
+ @logger.unknown("ODBCAdapter#remove_column>") if @trace
117
+ @logger.unknown("args=[#{table_name}|#{column_name}]") if @trace
118
+ execute "ALTER TABLE #{table_name} DROP #{quote_column_name(column_name)} RESTRICT"
119
+ rescue Exception => e
120
+ @logger.unknown("exception=#{e}") if @trace
121
+ raise ActiveRecord::ActiveRecordError, e.message
122
+ end
123
+
124
+ def change_column(table_name, column_name, type, options = {})
125
+ @logger.unknown("ODBCAdapter#change_column>") if @trace
126
+ @logger.unknown("args=[#{table_name}|#{column_name}|#{type}]") if @trace
127
+ change_column_sql = "ALTER TABLE #{table_name} ALTER #{column_name} " +
128
+ "#{type_to_sql(type)}"
129
+ # Add any :null and :default options
130
+ add_column_options!(change_column_sql, options)
131
+ execute(change_column_sql)
132
+ rescue Exception => e
133
+ @logger.unknown("exception=#{e}") if @trace
134
+ raise ActiveRecord::ActiveRecordError, e.message
135
+ end
136
+
137
+ def remove_index(table_name, options = {})
138
+ @logger.unknown("ODBCAdapter#remove_index>") if @trace
139
+ @logger.unknown("args=[#{table_name}]") if @trace
140
+ execute "DROP INDEX #{quote_column_name(index_name(table_name, options))}"
141
+ rescue Exception => e
142
+ @logger.unknown("exception=#{e}") if @trace
143
+ raise ActiveRecord::ActiveRecordError, e.message
144
+ end
145
+
146
+ def tables(name = nil)
147
+ # Hide system tables
148
+ super(name).delete_if {|t| t =~ /^ii/i }
149
+ end
150
+
151
+ def indexes(table_name, name = nil)
152
+ # Hide internally generated indexes used to support primary keys.
153
+ super(table_name, name).delete_if { |i| i.unique && i.name =~ /^\$/ }
154
+ end
155
+
156
+ end # module
@@ -0,0 +1,185 @@
1
+ #
2
+ # $Id: odbcext_microsoftsqlserver.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 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
+ select_value("select @@IDENTITY", 'last_insert_id')
38
+ end
39
+
40
+ # ------------------------------------------------------------------------
41
+ # Optional methods
42
+ #
43
+ # These are supplied for a DBMS only if necessary.
44
+ # ODBCAdapter tests for optional methods using Object#respond_to?
45
+
46
+ # Pre action for ODBCAdapter#insert
47
+ def pre_insert(sql, name, pk, id_value, sequence_name)
48
+ @iiTable = get_table_name(sql)
49
+ @iiCol = get_autounique_column(@iiTable)
50
+ @iiEnabled = false
51
+
52
+ if @iiCol != nil
53
+ if query_contains_autounique_col(sql, @iiCol)
54
+ begin
55
+ @connection.do(enable_identity_insert(@iiTable, true))
56
+ @iiEnabled = true
57
+ rescue Exception => e
58
+ raise ActiveRecordError, "IDENTITY_INSERT could not be turned on"
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ # Post action for ODBCAdapter#insert
65
+ def post_insert(sql, name, pk, id_value, sequence_name)
66
+ if @iiEnabled
67
+ begin
68
+ @connection.do(enable_identity_insert(@iiTable, false))
69
+ rescue Exception => e
70
+ raise ActiveRecordError, "IDENTITY_INSERT could not be turned off"
71
+ end
72
+ end
73
+ end
74
+
75
+ # ------------------------------------------------------------------------
76
+ # Method redefinitions
77
+ #
78
+ # DBMS specific methods which override the default implementation
79
+ # provided by the ODBCAdapter core.
80
+
81
+ def rename_table(name, new_name)
82
+ @logger.unknown("ODBCAdapter#rename_table>") if @trace
83
+ execute "EXEC sp_rename '#{name}', '#{new_name}'"
84
+ rescue Exception => e
85
+ @logger.unknown("exception=#{e}") if @trace
86
+ raise
87
+ end
88
+
89
+ def remove_column(table_name, column_name)
90
+ @logger.unknown("ODBCAdapter#remove_column>") if @trace
91
+ # Remove default constraints first
92
+ 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"
93
+ defaults.each {|constraint|
94
+ execute "ALTER TABLE #{table_name} DROP CONSTRAINT #{constraint["name"]}"
95
+ }
96
+ execute "ALTER TABLE #{table_name} DROP COLUMN #{quote_column_name(column_name)}"
97
+ rescue Exception => e
98
+ @logger.unknown("exception=#{e}") if @trace
99
+ raise
100
+ end
101
+
102
+ def change_column(table_name, column_name, type, options = {})
103
+ @logger.unknown("ODBCAdapter#change_column>") if @trace
104
+ sql_commands = ["ALTER TABLE #{table_name} ALTER COLUMN #{column_name} #{type_to_sql(type, options[:limit])}"]
105
+ if options[:default]
106
+ # Remove default constraints first
107
+ 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"
108
+ defaults.each {|constraint|
109
+ execute "ALTER TABLE #{table_name} DROP CONSTRAINT #{constraint["name"]}"
110
+ }
111
+ sql_commands << "ALTER TABLE #{table_name} ADD CONSTRAINT DF_#{table_name}_#{column_name} DEFAULT #{options[:default]} FOR #{column_name}"
112
+ end
113
+ sql_commands.each {|c|
114
+ execute(c)
115
+ }
116
+ rescue Exception => e
117
+ @logger.unknown("exception=#{e}") if @trace
118
+ raise
119
+ end
120
+
121
+ def rename_column(table_name, column_name, new_column_name)
122
+ @logger.unknown("ODBCAdapter#rename_column>") if @trace
123
+ execute "EXEC sp_rename '#{table_name}.#{column_name}', '#{new_column_name}'"
124
+ rescue Exception => e
125
+ @logger.unknown("exception=#{e}") if @trace
126
+ raise
127
+ end
128
+
129
+ def remove_index(table_name, options = {})
130
+ @logger.unknown("ODBCAdapter#remove_index>") if @trace
131
+ execute "DROP INDEX #{table_name}.#{quote_column_name(index_name(table_name, options))}"
132
+ rescue Exception => e
133
+ @logger.unknown("exception=#{e}") if @trace
134
+ raise
135
+ end
136
+
137
+ def tables(name = nil)
138
+ # Hide system tables.
139
+ super(name).delete_if {|t| t =~ /^sys/ }
140
+ end
141
+
142
+ def indexes(table_name, name = nil)
143
+ # Hide primary key indexes.
144
+ super(table_name, name).delete_if { |i| i.name =~ /^PK_/ }
145
+ end
146
+
147
+ # ------------------------------------------------------------------------
148
+ # Private methods to support methods above
149
+ #
150
+ private
151
+
152
+ def get_table_name(sql)
153
+ if sql =~ /^\s*insert\s+into\s+([^\(\s]+)\s*|^\s*update\s+([^\(\s]+)\s*/i
154
+ $1
155
+ elsif sql =~ /from\s+([^\(\s]+)\s*/i
156
+ $1
157
+ else
158
+ nil
159
+ end end
160
+
161
+ def get_autounique_column(table_name)
162
+ @table_columns = {} unless @table_columns
163
+ @table_columns[table_name] = columns(table_name) if @table_columns[table_name] == nil
164
+ @table_columns[table_name].each do |col|
165
+ return col.name if col.auto_unique?
166
+ end
167
+
168
+ return nil
169
+ end
170
+
171
+ def query_contains_autounique_col(sql, col)
172
+ sql =~ /(\[#{col}\])|("#{col}")/
173
+ end
174
+
175
+ def enable_identity_insert(table_name, enable = true)
176
+ if has_autounique_column(table_name)
177
+ "SET IDENTITY_INSERT #{table_name} #{enable ? 'ON' : 'OFF'}"
178
+ end
179
+ end
180
+
181
+ def has_autounique_column(table_name)
182
+ !get_autounique_column(table_name).nil?
183
+ end
184
+
185
+ end # module