odbc-rails 1.2

Sign up to get free protection for your applications and to get access to all the features.
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