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,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