activerecord-odbc-adapter 2.0

Sign up to get free protection for your applications and to get access to all the features.
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,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,144 @@
1
+ #
2
+ # $Id: odbcext_informix.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
+ @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 type_to_sql(type, limit = nil, precision = nil, scale = nil)
50
+ if type == :decimal
51
+ # Force an explicit scale if none supplied to specify the fixed
52
+ # point form of Informix's DECIMAL type. If no scale is specified,
53
+ # the Informix DECIMAL type stores floating point values.
54
+ precision ||= 32
55
+ scale ||= 0
56
+ end
57
+ super(type, limit, precision, scale)
58
+ end
59
+
60
+ def quoted_date(value)
61
+ @logger.unknown("ODBCAdapter#quoted_date>") if @trace
62
+ @logger.unknown("args=[#{value}]") if @trace
63
+ # Informix's DBTIME and DBDATE environment variables should be set to:
64
+ # DBTIME=%Y-%m-%d %H:%M:%S
65
+ # DBDATE=Y4MD-
66
+ if value.acts_like?(:time) # Time, DateTime
67
+ %Q!'#{value.strftime("%Y-%m-%d %H:%M:%S.")}'!
68
+ else # Date
69
+ %Q!'#{value.strftime("%Y-%m-%d")}'!
70
+ end
71
+ end
72
+
73
+ def rename_table(name, new_name)
74
+ @logger.unknown("ODBCAdapter#rename_table>") if @trace
75
+ @logger.unknown("args=[#{name}|#{new_name}]") if @trace
76
+ execute "RENAME TABLE #{name} TO #{new_name}"
77
+ rescue Exception => e
78
+ @logger.unknown("exception=#{e}") if @trace
79
+ raise ActiveRecord::ActiveRecordError, e.message
80
+ end
81
+
82
+ def change_column(table_name, column_name, type, options = {})
83
+ @logger.unknown("ODBCAdapter#change_column>") if @trace
84
+ @logger.unknown("args=[#{table_name}|#{column_name}|#{type}]") if @trace
85
+ change_column_sql = "ALTER TABLE #{table_name} MODIFY #{column_name} " +
86
+ "#{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
87
+ # Add any :null and :default options
88
+ add_column_options!(change_column_sql, options)
89
+ execute(change_column_sql)
90
+ rescue Exception => e
91
+ @logger.unknown("exception=#{e}") if @trace
92
+ raise ActiveRecord::ActiveRecordError, e.message
93
+ end
94
+
95
+ def change_column_default(table_name, column_name, default)
96
+ @logger.unknown("ODBCAdapter#change_column_default>") if @trace
97
+ @logger.unknown("args=[#{table_name}|#{column_name}]") if @trace
98
+ col = columns(table_name).find {|c| c.name == column_name.to_s }
99
+ change_column(table_name, column_name, col.type, :default => default,
100
+ :limit => col.limit, :precision => col.precision, :scale => col.scale)
101
+ rescue Exception => e
102
+ @logger.unknown("exception=#{e}") if @trace
103
+ raise ActiveRecord::ActiveRecordError, e.message
104
+ end
105
+
106
+ def rename_column(table_name, column_name, new_column_name)
107
+ @logger.unknown("ODBCAdapter#rename_column>") if @trace
108
+ @logger.unknown("args=[#{table_name}|#{column_name}|#{new_column_name}]") if @trace
109
+ execute "RENAME COLUMN #{table_name}.#{column_name} TO #{new_column_name}"
110
+ rescue Exception => e
111
+ @logger.unknown("exception=#{e}") if @trace
112
+ raise ActiveRecord::ActiveRecordError, e.message
113
+ end
114
+
115
+ def remove_index(table_name, options = {})
116
+ @logger.unknown("ODBCAdapter#remove_index>") if @trace
117
+ @logger.unknown("args=[#{table_name}]") if @trace
118
+ execute "DROP INDEX #{quote_column_name(index_name(table_name, options))}"
119
+ rescue Exception => e
120
+ @logger.unknown("exception=#{e}") if @trace
121
+ raise ActiveRecord::ActiveRecordError, e.message
122
+ end
123
+
124
+ def tables(name = nil)
125
+ # Hide the system tables. Some contain columns which don't have an
126
+ # equivalent ODBC SQL type which causes problems with #columns.
127
+ super(name).delete_if {|t| t =~ /^sys/i }
128
+ end
129
+
130
+ def indexes(table_name, name = nil)
131
+ # Informix creates a unique index for a table's primary key.
132
+ # Hide any such index. The index name takes the form ddd_ddd.
133
+ # (Indexes created through 'CREATE INDEX' must have a name starting
134
+ # with a letter or an # underscore.)
135
+ #
136
+ # If this isn't done...
137
+ # Rails' 'rake test_units' attempts to create primary key indexes
138
+ # explicitly when creating the test database schema. Informix rejects
139
+ # the resulting 'CREATE UNIQUE INDEX ddd_ddd' commands with a syntax
140
+ # error.
141
+ super(table_name, name).delete_if { |i| i.unique && i.name =~ /\d+_\d+/ }
142
+ end
143
+
144
+ 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.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
+ 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, options = {})
86
+ @logger.unknown("ODBCAdapter#drop_table>") if @trace
87
+ @logger.unknown("args=[#{name}]") if @trace
88
+ super(name, options)
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 #{quote_table_name(table_name)} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
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 #{quote_table_name(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, options[:limit], options[:precision], options[:scale])}"
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,216 @@
1
+ #
2
+ # $Id: odbcext_microsoftsqlserver.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
+ 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 create_database(name)
82
+ @logger.unknown("ODBCAdapter#create_database>") if @trace
83
+ @logger.unknown("args=[#{name}]") if @trace
84
+ execute "CREATE DATABASE #{name}"
85
+ rescue Exception => e
86
+ @logger.unknown("exception=#{e}") if @trace
87
+ raise
88
+ end
89
+
90
+ def drop_database(name)
91
+ @logger.unknown("ODBCAdapter#drop_database>") if @trace
92
+ @logger.unknown("args=[#{name}]") if @trace
93
+ execute "DROP DATABASE #{name}"
94
+ rescue Exception => e
95
+ @logger.unknown("exception=#{e}") if @trace
96
+ raise
97
+ end
98
+
99
+ def rename_table(name, new_name)
100
+ @logger.unknown("ODBCAdapter#rename_table>") if @trace
101
+ execute "EXEC sp_rename '#{name}', '#{new_name}'"
102
+ rescue Exception => e
103
+ @logger.unknown("exception=#{e}") if @trace
104
+ raise
105
+ end
106
+
107
+ def remove_column(table_name, column_name)
108
+ @logger.unknown("ODBCAdapter#remove_column>") if @trace
109
+ # Remove default constraints first
110
+ 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"
111
+ defaults.each {|constraint|
112
+ execute "ALTER TABLE #{quote_table_name(table_name)} DROP CONSTRAINT #{constraint["name"]}"
113
+ }
114
+ execute "ALTER TABLE #{quote_table_name(table_name)} DROP COLUMN #{quote_column_name(column_name)}"
115
+ rescue Exception => e
116
+ @logger.unknown("exception=#{e}") if @trace
117
+ raise
118
+ end
119
+
120
+ def change_column(table_name, column_name, type, options = {})
121
+ @logger.unknown("ODBCAdapter#change_column>") if @trace
122
+ sql_commands = ["ALTER TABLE #{table_name} ALTER COLUMN #{column_name} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"]
123
+ if options_include_default?(options)
124
+ # Remove default constraints first
125
+ 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"
126
+ defaults.each {|constraint|
127
+ execute "ALTER TABLE #{table_name} DROP CONSTRAINT #{constraint["name"]}"
128
+ }
129
+ sql_commands << "ALTER TABLE #{table_name} ADD CONSTRAINT DF_#{table_name}_#{column_name} DEFAULT #{quote(options[:default])} FOR #{column_name}"
130
+ end
131
+ sql_commands.each {|c|
132
+ execute(c)
133
+ }
134
+ rescue Exception => e
135
+ @logger.unknown("exception=#{e}") if @trace
136
+ raise
137
+ end
138
+
139
+ def change_column_default(table_name, column_name, default)
140
+ @logger.unknown("ODBCAdapter#change_column_default>") if @trace
141
+ # Remove default constraints first
142
+ 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"
143
+ defaults.each {|constraint|
144
+ execute "ALTER TABLE #{table_name} DROP CONSTRAINT #{constraint["name"]}"
145
+ }
146
+ execute "ALTER TABLE #{table_name} ADD CONSTRAINT DF_#{table_name}_#{column_name} DEFAULT #{quote(default)} FOR #{column_name}"
147
+ rescue Exception => e
148
+ @logger.unknown("exception=#{e}") if @trace
149
+ raise
150
+ end
151
+
152
+ def rename_column(table_name, column_name, new_column_name)
153
+ @logger.unknown("ODBCAdapter#rename_column>") if @trace
154
+ execute "EXEC sp_rename '#{table_name}.#{column_name}', '#{new_column_name}'"
155
+ rescue Exception => e
156
+ @logger.unknown("exception=#{e}") if @trace
157
+ raise
158
+ end
159
+
160
+ def remove_index(table_name, options = {})
161
+ @logger.unknown("ODBCAdapter#remove_index>") if @trace
162
+ execute "DROP INDEX #{table_name}.#{quote_column_name(index_name(table_name, options))}"
163
+ rescue Exception => e
164
+ @logger.unknown("exception=#{e}") if @trace
165
+ raise
166
+ end
167
+
168
+ def tables(name = nil)
169
+ # Hide system tables.
170
+ super(name).delete_if {|t| t =~ /^sys/ }
171
+ end
172
+
173
+ def indexes(table_name, name = nil)
174
+ # Hide primary key indexes.
175
+ super(table_name, name).delete_if { |i| i.name =~ /^PK_/ }
176
+ end
177
+
178
+ # ------------------------------------------------------------------------
179
+ # Private methods to support methods above
180
+ #
181
+ private
182
+
183
+ def get_table_name(sql)
184
+ if sql =~ /^\s*insert\s+into\s+([^\(\s]+)\s*|^\s*update\s+([^\(\s]+)\s*/i
185
+ $1
186
+ elsif sql =~ /from\s+([^\(\s]+)\s*/i
187
+ $1
188
+ else
189
+ nil
190
+ end end
191
+
192
+ def get_autounique_column(table_name)
193
+ @table_columns = {} unless @table_columns
194
+ @table_columns[table_name] = columns(table_name) if @table_columns[table_name] == nil
195
+ @table_columns[table_name].each do |col|
196
+ return col.name if col.auto_unique?
197
+ end
198
+
199
+ return nil
200
+ end
201
+
202
+ def query_contains_autounique_col(sql, col)
203
+ sql =~ /(\[#{col}\])|("#{col}")/
204
+ end
205
+
206
+ def enable_identity_insert(table_name, enable = true)
207
+ if has_autounique_column(table_name)
208
+ "SET IDENTITY_INSERT #{table_name} #{enable ? 'ON' : 'OFF'}"
209
+ end
210
+ end
211
+
212
+ def has_autounique_column(table_name)
213
+ !get_autounique_column(table_name).nil?
214
+ end
215
+
216
+ end # module