odbc-rails 1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/AUTHORS +16 -0
- data/COPYING +21 -0
- data/ChangeLog +89 -0
- data/LICENSE +5 -0
- data/NEWS +12 -0
- data/README +282 -0
- data/lib/active_record/connection_adapters/odbc_adapter.rb +1792 -0
- data/lib/active_record/vendor/odbcext_db2.rb +87 -0
- data/lib/active_record/vendor/odbcext_informix.rb +132 -0
- data/lib/active_record/vendor/odbcext_informix_col.rb +45 -0
- data/lib/active_record/vendor/odbcext_ingres.rb +156 -0
- data/lib/active_record/vendor/odbcext_microsoftsqlserver.rb +185 -0
- data/lib/active_record/vendor/odbcext_microsoftsqlserver_col.rb +40 -0
- data/lib/active_record/vendor/odbcext_mysql.rb +136 -0
- data/lib/active_record/vendor/odbcext_oracle.rb +220 -0
- data/lib/active_record/vendor/odbcext_postgresql.rb +179 -0
- data/lib/active_record/vendor/odbcext_progress.rb +139 -0
- data/lib/active_record/vendor/odbcext_progress89.rb +259 -0
- data/lib/active_record/vendor/odbcext_sybase.rb +212 -0
- data/lib/active_record/vendor/odbcext_sybase_col.rb +49 -0
- data/lib/active_record/vendor/odbcext_virtuoso.rb +146 -0
- data/lib/odbc_adapter.rb +28 -0
- data/support/lib/active_record/connection_adapters/abstract/schema_definitions.rb +259 -0
- data/support/odbc_rails.diff +707 -0
- data/support/pack_odbc.rb +119 -0
- data/support/rake/rails_plugin_package_task.rb +212 -0
- data/support/test/base_test.rb +1349 -0
- data/support/test/migration_test.rb +566 -0
- data/test/connections/native_odbc/connection.rb +95 -0
- data/test/fixtures/db_definitions/db2.drop.sql +30 -0
- data/test/fixtures/db_definitions/db2.sql +217 -0
- data/test/fixtures/db_definitions/db22.drop.sql +2 -0
- data/test/fixtures/db_definitions/db22.sql +5 -0
- data/test/fixtures/db_definitions/informix.drop.sql +30 -0
- data/test/fixtures/db_definitions/informix.sql +205 -0
- data/test/fixtures/db_definitions/informix2.drop.sql +2 -0
- data/test/fixtures/db_definitions/informix2.sql +5 -0
- data/test/fixtures/db_definitions/ingres.drop.sql +62 -0
- data/test/fixtures/db_definitions/ingres.sql +232 -0
- data/test/fixtures/db_definitions/ingres2.drop.sql +2 -0
- data/test/fixtures/db_definitions/ingres2.sql +5 -0
- data/test/fixtures/db_definitions/mysql.drop.sql +30 -0
- data/test/fixtures/db_definitions/mysql.sql +219 -0
- data/test/fixtures/db_definitions/mysql2.drop.sql +2 -0
- data/test/fixtures/db_definitions/mysql2.sql +5 -0
- data/test/fixtures/db_definitions/oracle_odbc.drop.sql +64 -0
- data/test/fixtures/db_definitions/oracle_odbc.sql +257 -0
- data/test/fixtures/db_definitions/oracle_odbc2.drop.sql +2 -0
- data/test/fixtures/db_definitions/oracle_odbc2.sql +6 -0
- data/test/fixtures/db_definitions/progress.drop.sql +61 -0
- data/test/fixtures/db_definitions/progress.sql +234 -0
- data/test/fixtures/db_definitions/progress2.drop.sql +2 -0
- data/test/fixtures/db_definitions/progress2.sql +6 -0
- data/test/fixtures/db_definitions/sqlserver.drop.sql +30 -0
- data/test/fixtures/db_definitions/sqlserver.sql +203 -0
- data/test/fixtures/db_definitions/sqlserver2.drop.sql +2 -0
- data/test/fixtures/db_definitions/sqlserver2.sql +5 -0
- data/test/fixtures/db_definitions/sybase.drop.sql +31 -0
- data/test/fixtures/db_definitions/sybase.sql +204 -0
- data/test/fixtures/db_definitions/sybase2.drop.sql +4 -0
- data/test/fixtures/db_definitions/sybase2.sql +5 -0
- data/test/fixtures/db_definitions/virtuoso.drop.sql +30 -0
- data/test/fixtures/db_definitions/virtuoso.sql +200 -0
- data/test/fixtures/db_definitions/virtuoso2.drop.sql +2 -0
- data/test/fixtures/db_definitions/virtuoso2.sql +5 -0
- metadata +149 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
#
|
2
|
+
# $Id: odbcext_microsoftsqlserver_col.rb,v 1.1 2006/12/06 14:42:11 source Exp $
|
3
|
+
#
|
4
|
+
# OpenLink ODBC Adapter for Ruby on Rails
|
5
|
+
# Copyright (C) 2006 OpenLink Software
|
6
|
+
#
|
7
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
8
|
+
# a copy of this software and associated documentation files (the
|
9
|
+
# "Software"), to deal in the Software without restriction, including
|
10
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
11
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
12
|
+
# permit persons to whom the Software is furnished to do so, subject
|
13
|
+
# to the following conditions:
|
14
|
+
#
|
15
|
+
# The above copyright notice and this permission notice shall be
|
16
|
+
# included in all copies or substantial portions of the Software.
|
17
|
+
#
|
18
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
20
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
21
|
+
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
22
|
+
# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
23
|
+
# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
24
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
25
|
+
#
|
26
|
+
|
27
|
+
module ODBCColumnExt
|
28
|
+
|
29
|
+
# Is the column a numeric autoincrementing column?
|
30
|
+
def auto_unique?
|
31
|
+
@autounique
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def autoUnique?
|
37
|
+
@nativeType =~ /\bidentity\b/i
|
38
|
+
end
|
39
|
+
|
40
|
+
end # module
|
@@ -0,0 +1,136 @@
|
|
1
|
+
#
|
2
|
+
# $Id: odbcext_mysql.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
|
+
# The ODBCAdapter core doesn't not implement these methods
|
33
|
+
|
34
|
+
# #last_insert_id must be implemented for any database which returns
|
35
|
+
# false from #prefetch_primary_key?
|
36
|
+
#
|
37
|
+
# This method assumes that the table inserted into has a primary key defined
|
38
|
+
# as INT AUTOINCREMENT
|
39
|
+
def last_insert_id(table, sequence_name, stmt = nil)
|
40
|
+
@logger.unknown("ODBCAdapter#last_insert_id>") if @trace
|
41
|
+
select_value("select LAST_INSERT_ID()", 'last_insert_id')
|
42
|
+
end
|
43
|
+
|
44
|
+
# ------------------------------------------------------------------------
|
45
|
+
# Optional methods
|
46
|
+
#
|
47
|
+
# These are supplied for a DBMS only if necessary.
|
48
|
+
# ODBCAdapter tests for optional methods using Object#respond_to?
|
49
|
+
|
50
|
+
# Pre action for ODBCAdapter#insert
|
51
|
+
# def pre_insert(sql, name, pk, id_value, sequence_name)
|
52
|
+
# end
|
53
|
+
|
54
|
+
# Post action for ODBCAdapter#insert
|
55
|
+
# def post_insert(sql, name, pk, id_value, sequence_name)
|
56
|
+
# end
|
57
|
+
|
58
|
+
# ------------------------------------------------------------------------
|
59
|
+
# Method redefinitions
|
60
|
+
#
|
61
|
+
# DBMS specific methods which override the default implementation
|
62
|
+
# provided by the ODBCAdapter core.
|
63
|
+
|
64
|
+
def quote_string(string)
|
65
|
+
@logger.unknown("ODBCAdapter#quote_string>") if @trace
|
66
|
+
|
67
|
+
# MySQL requires backslashes to be escaped
|
68
|
+
string.gsub(/\\/, '\&\&').gsub(/'/, "''")
|
69
|
+
end
|
70
|
+
|
71
|
+
def create_table(name, options = {})
|
72
|
+
@logger.unknown("ODBCAdapter#create_table>") if @trace
|
73
|
+
super(name, {:options => "ENGINE=InnoDB"}.merge(options))
|
74
|
+
rescue Exception => e
|
75
|
+
@logger.unknown("exception=#{e}") if @trace
|
76
|
+
raise
|
77
|
+
end
|
78
|
+
|
79
|
+
def rename_table(name, new_name)
|
80
|
+
@logger.unknown("ODBCAdapter#rename_table>") if @trace
|
81
|
+
execute "RENAME TABLE #{name} TO #{new_name}"
|
82
|
+
rescue Exception => e
|
83
|
+
@logger.unknown("exception=#{e}") if @trace
|
84
|
+
raise
|
85
|
+
end
|
86
|
+
|
87
|
+
def change_column(table_name, column_name, type, options = {})
|
88
|
+
@logger.unknown("ODBCAdapter#change_column>") if @trace
|
89
|
+
# column_name.to_s used in case column_name is a symbol
|
90
|
+
options[:default] ||= columns(table_name).find { |c| c.name == column_name.to_s }.default
|
91
|
+
change_column_sql = "ALTER TABLE #{table_name} CHANGE #{column_name} #{column_name} #{type_to_sql(type, options[:limit])}"
|
92
|
+
add_column_options!(change_column_sql, options)
|
93
|
+
execute(change_column_sql)
|
94
|
+
rescue Exception => e
|
95
|
+
@logger.unknown("exception=#{e}") if @trace
|
96
|
+
raise
|
97
|
+
end
|
98
|
+
|
99
|
+
def rename_column(table_name, column_name, new_column_name)
|
100
|
+
@logger.unknown("ODBCAdapter#rename_column>") if @trace
|
101
|
+
col = columns(table_name).find{ |c| c.name == column_name.to_s }
|
102
|
+
current_type = col.sql_type
|
103
|
+
current_type << "(#{col.limit})" if col.limit
|
104
|
+
execute "ALTER TABLE #{table_name} CHANGE #{column_name} #{new_column_name} #{current_type}"
|
105
|
+
rescue Exception => e
|
106
|
+
@logger.unknown("exception=#{e}") if @trace
|
107
|
+
raise
|
108
|
+
end
|
109
|
+
|
110
|
+
def change_column_default(table_name, column_name, default)
|
111
|
+
@logger.unknown("ODBCAdapter#change_column_default>") if @trace
|
112
|
+
col = columns(table_name).find{ |c| c.name == column_name.to_s }
|
113
|
+
current_type = col.sql_type
|
114
|
+
current_type << "(#{col.limit})" if col.limit
|
115
|
+
change_column(table_name, column_name, current_type, { :default => default })
|
116
|
+
rescue Exception => e
|
117
|
+
@logger.unknown("exception=#{e}") if @trace
|
118
|
+
raise
|
119
|
+
end
|
120
|
+
|
121
|
+
def indexes(table_name, name = nil)
|
122
|
+
# Skip primary key indexes
|
123
|
+
super(table_name, name).delete_if { |i| i.unique && i.name =~ /^PRIMARY$/ }
|
124
|
+
end
|
125
|
+
|
126
|
+
def structure_dump
|
127
|
+
@logger.unknown("ODBCAdapter#structure_dump>") if @trace
|
128
|
+
select_all("SHOW TABLES").inject("") do |structure, table|
|
129
|
+
structure += select_one("SHOW CREATE TABLE #{table.to_a.first.last}")["Create Table"] + ";\n\n"
|
130
|
+
end
|
131
|
+
rescue Exception => e
|
132
|
+
@logger.unknown("exception=#{e}") if @trace
|
133
|
+
raise
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
@@ -0,0 +1,220 @@
|
|
1
|
+
#
|
2
|
+
# $Id: odbcext_oracle.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
|
+
# (This adapter returns true for Oracle)
|
36
|
+
|
37
|
+
#def last_insert_id(table, sequence_name, stmt = nil)
|
38
|
+
#end
|
39
|
+
|
40
|
+
# #next_sequence_value must be implemented for any database which returns
|
41
|
+
# true from #prefetch_primary_key?
|
42
|
+
#
|
43
|
+
# Returns the next sequence value from a sequence generator. Not generally
|
44
|
+
# called directly; used by ActiveRecord to get the next primary key value
|
45
|
+
# when inserting a new database record (see #prefetch_primary_key?).
|
46
|
+
def next_sequence_value(sequence_name)
|
47
|
+
@logger.unknown("ODBCAdapter#next_sequence_value>") if @trace
|
48
|
+
#@logger.unknown("args=[#{sequence_name}]") if @trace
|
49
|
+
select_one("select #{sequence_name}.nextval id from dual")['id']
|
50
|
+
end
|
51
|
+
|
52
|
+
# ------------------------------------------------------------------------
|
53
|
+
# Optional methods
|
54
|
+
#
|
55
|
+
# These are supplied for a DBMS only if necessary.
|
56
|
+
# ODBCAdapter tests for optional methods using Object#respond_to?
|
57
|
+
|
58
|
+
# Pre action for ODBCAdapter#insert
|
59
|
+
# def pre_insert(sql, name, pk, id_value, sequence_name)
|
60
|
+
# end
|
61
|
+
|
62
|
+
# Post action for ODBCAdapter#insert
|
63
|
+
# def post_insert(sql, name, pk, id_value, sequence_name)
|
64
|
+
# end
|
65
|
+
|
66
|
+
# ------------------------------------------------------------------------
|
67
|
+
# Method redefinitions
|
68
|
+
#
|
69
|
+
# DBMS specific methods which override the default implementation
|
70
|
+
# provided by the ODBCAdapter core.
|
71
|
+
|
72
|
+
def quoted_date(value)
|
73
|
+
@logger.unknown("ODBCAdapter#quoted_date>") if @trace
|
74
|
+
# Ideally, we'd return an ODBC date or timestamp literal escape
|
75
|
+
# sequence, but not all ODBC drivers support them.
|
76
|
+
case value
|
77
|
+
when Time, DateTime
|
78
|
+
#%Q!{ts '#{value.strftime("%Y-%m-%d %H:%M:%S")}'}!
|
79
|
+
"to_timestamp(\'#{value.strftime("%Y-%m-%d %H:%M:%S")}\', \'YYYY-MM-DD HH24:MI:SS\')"
|
80
|
+
when Date
|
81
|
+
#%Q!{d '#{value.strftime("%Y-%m-%d")}'}!
|
82
|
+
"to_timestamp(\'#{value.strftime("%Y-%m-%d")}\', \'YYYY-MM-DD\')"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def create_table(name, options = {})
|
87
|
+
@logger.unknown("ODBCAdapter#create_table>") if @trace
|
88
|
+
super(name, options)
|
89
|
+
# Some ActiveRecord tests insert using an explicit id value. Starting the
|
90
|
+
# primary key sequence from 10000 eliminates collisions (and subsequent
|
91
|
+
# complaints from Oracle of integrity constraint violations) between id's
|
92
|
+
# generated from the sequence and explicitly supplied ids.
|
93
|
+
# Using explicit and generated id's together should be avoided.
|
94
|
+
execute "CREATE SEQUENCE #{name}_seq START WITH 10000" unless options[:id] == false
|
95
|
+
rescue Exception => e
|
96
|
+
@logger.unknown("exception=#{e}") if @trace
|
97
|
+
raise
|
98
|
+
end
|
99
|
+
|
100
|
+
def rename_table(name, new_name)
|
101
|
+
@logger.unknown("ODBCAdapter#rename_table>") if @trace
|
102
|
+
execute "RENAME #{name} TO #{new_name}"
|
103
|
+
execute "RENAME #{name}_seq TO #{new_name}_seq"
|
104
|
+
rescue Exception => e
|
105
|
+
@logger.unknown("exception=#{e}") if @trace
|
106
|
+
raise
|
107
|
+
end
|
108
|
+
|
109
|
+
def drop_table(name)
|
110
|
+
@logger.unknown("ODBCAdapter#drop_table>") if @trace
|
111
|
+
super(name)
|
112
|
+
execute "DROP SEQUENCE #{name}_seq"
|
113
|
+
rescue Exception => e
|
114
|
+
if e.message !~ /ORA-02289/i
|
115
|
+
# Error "ORA-02289: sequence does not exist" will be generated
|
116
|
+
# if the table was created with options[:id] == false
|
117
|
+
@logger.unknown("exception=#{e}") if @trace
|
118
|
+
raise
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def remove_column(table_name, column_name)
|
123
|
+
@logger.unknown("ODBCAdapter#remove_column>") if @trace
|
124
|
+
execute "ALTER TABLE #{table_name} DROP COLUMN #{quote_column_name(column_name)}"
|
125
|
+
rescue Exception => e
|
126
|
+
@logger.unknown("exception=#{e}") if @trace
|
127
|
+
raise
|
128
|
+
end
|
129
|
+
|
130
|
+
def change_column(table_name, column_name, type, options = {})
|
131
|
+
@logger.unknown("ODBCAdapter#change_column>") if @trace
|
132
|
+
change_column_sql = "ALTER TABLE #{table_name} MODIFY #{column_name} #{type_to_sql(type, options[:limit])}"
|
133
|
+
add_column_options!(change_column_sql, options)
|
134
|
+
execute(change_column_sql)
|
135
|
+
rescue Exception => e
|
136
|
+
@logger.unknown("exception=#{e}") if @trace
|
137
|
+
raise
|
138
|
+
end
|
139
|
+
|
140
|
+
def change_column_default(table_name, column_name, default)
|
141
|
+
@logger.unknown("ODBCAdapter#change_column_default>") if @trace
|
142
|
+
execute "ALTER TABLE #{table_name} MODIFY #{column_name} DEFAULT #{quote(default)}"
|
143
|
+
rescue Exception => e
|
144
|
+
@logger.unknown("exception=#{e}") if @trace
|
145
|
+
raise
|
146
|
+
end
|
147
|
+
|
148
|
+
def rename_column(table_name, column_name, new_column_name)
|
149
|
+
@logger.unknown("ODBCAdapter#rename_column>") if @trace
|
150
|
+
execute "ALTER TABLE #{table_name} RENAME COLUMN #{column_name} to #{new_column_name}"
|
151
|
+
rescue Exception => e
|
152
|
+
@logger.unknown("exception=#{e}") if @trace
|
153
|
+
raise
|
154
|
+
end
|
155
|
+
|
156
|
+
def remove_index(table_name, options = {})
|
157
|
+
@logger.unknown("ODBCAdapter#remove_index>") if @trace
|
158
|
+
execute "DROP INDEX #{quote_column_name(index_name(table_name, options))}"
|
159
|
+
rescue Exception => e
|
160
|
+
@logger.unknown("exception=#{e}") if @trace
|
161
|
+
raise
|
162
|
+
end
|
163
|
+
|
164
|
+
def tables(name = nil)
|
165
|
+
# Hide dropped tables in Oracle's recyclebin.
|
166
|
+
super(name).delete_if {|t| t =~ /^BIN\$/i }
|
167
|
+
end
|
168
|
+
|
169
|
+
def indexes(table_name, name = nil)
|
170
|
+
# Oracle creates a unique index for a table's primary key.
|
171
|
+
# Hide any such index. Oracle uses system-generated names
|
172
|
+
# beginning with "SYS_" for implicitly generated schema objects.
|
173
|
+
#
|
174
|
+
# If this isn't done...
|
175
|
+
# Rails' 'rake test_units' attempts to create this index explicitly,
|
176
|
+
# but Oracle rejects this as the index has already been created
|
177
|
+
# automatically when the table was defined.
|
178
|
+
super(table_name, name).delete_if { |i| i.unique && i.name =~ /^SYS_/i }
|
179
|
+
end
|
180
|
+
|
181
|
+
def structure_dump
|
182
|
+
@logger.unknown("ODBCAdapter#structure_dump>") if @trace
|
183
|
+
s = select_all("select sequence_name from user_sequences").inject("") do |structure, seq|
|
184
|
+
structure << "create sequence #{seq.to_a.first.last};\n\n"
|
185
|
+
end
|
186
|
+
|
187
|
+
select_all("select table_name from user_tables").inject(s) do |structure, table|
|
188
|
+
ddl = "create table #{table.to_a.first.last} (\n "
|
189
|
+
cols = select_all(%Q{
|
190
|
+
select column_name, data_type, data_length, data_precision, data_scale, data_default, nullable
|
191
|
+
from user_tab_columns
|
192
|
+
where table_name = '#{table.to_a.first.last}'
|
193
|
+
order by column_id
|
194
|
+
}).map do |row|
|
195
|
+
col = "#{row['column_name'].downcase} #{row['data_type'].downcase}"
|
196
|
+
if row['data_type'] =='NUMBER' and !row['data_precision'].nil?
|
197
|
+
col << "(#{row['data_precision'].to_i}"
|
198
|
+
col << ",#{row['data_scale'].to_i}" if !row['data_scale'].nil?
|
199
|
+
col << ')'
|
200
|
+
elsif row['data_type'].include?('CHAR')
|
201
|
+
col << "(#{row['data_length'].to_i})"
|
202
|
+
end
|
203
|
+
col << " default #{row['data_default']}" if !row['data_default'].nil?
|
204
|
+
col << ' not null' if row['nullable'] == 'N'
|
205
|
+
col
|
206
|
+
end
|
207
|
+
ddl << cols.join(",\n ")
|
208
|
+
ddl << ");\n\n"
|
209
|
+
structure << ddl
|
210
|
+
end
|
211
|
+
rescue Exception => e
|
212
|
+
@logger.unknown("exception=#{e}") if @trace
|
213
|
+
raise
|
214
|
+
end
|
215
|
+
|
216
|
+
# ------------------------------------------------------------------------
|
217
|
+
# Private methods to support methods above
|
218
|
+
#
|
219
|
+
|
220
|
+
end # module
|
@@ -0,0 +1,179 @@
|
|
1
|
+
#
|
2
|
+
# $Id: odbcext_postgresql.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
|
+
#end
|
38
|
+
|
39
|
+
# ------------------------------------------------------------------------
|
40
|
+
# Optional methods
|
41
|
+
#
|
42
|
+
# These are supplied for a DBMS only if necessary.
|
43
|
+
# ODBCAdapter tests for optional methods using Object#respond_to?
|
44
|
+
|
45
|
+
# Pre action for ODBCAdapter#insert
|
46
|
+
# def pre_insert(sql, name, pk, id_value, sequence_name)
|
47
|
+
# end
|
48
|
+
|
49
|
+
# Post action for ODBCAdapter#insert
|
50
|
+
# def post_insert(sql, name, pk, id_value, sequence_name)
|
51
|
+
# end
|
52
|
+
|
53
|
+
# ------------------------------------------------------------------------
|
54
|
+
# Method redefinitions
|
55
|
+
#
|
56
|
+
# DBMS specific methods which override the default implementation
|
57
|
+
# provided by the ODBCAdapter core.
|
58
|
+
|
59
|
+
def default_sequence_name(table, primary_key=nil)
|
60
|
+
@logger.unknown("ODBCAdapter#default_sequence_name>") if @trace
|
61
|
+
#@logger.unknown("args=[#{table}|#{primary_key}]") if @trace
|
62
|
+
default_pk, default_seq = pk_and_sequence_for(table)
|
63
|
+
default_seq || "#{table}_#{primary_key || default_pk || 'id'}_seq"
|
64
|
+
rescue Exception => e
|
65
|
+
@logger.unknown("exception=#{e}") if @trace
|
66
|
+
raise
|
67
|
+
end
|
68
|
+
|
69
|
+
def rename_table(name, new_name)
|
70
|
+
@logger.unknown("ODBCAdapter#rename_table>") if @trace
|
71
|
+
execute "ALTER TABLE #{name} RENAME TO #{new_name}"
|
72
|
+
rescue Exception => e
|
73
|
+
@logger.unknown("exception=#{e}") if @trace
|
74
|
+
raise
|
75
|
+
end
|
76
|
+
|
77
|
+
def add_column(table_name, column_name, type, options = {})
|
78
|
+
@logger.unknown("ODBCAdapter#add_column>") if @trace
|
79
|
+
sql_commands = ["ALTER TABLE #{table_name} ADD #{column_name} #{type_to_sql(type, options[:limit])}"]
|
80
|
+
if options[:default]
|
81
|
+
sql_commands << "ALTER TABLE #{table_name} ALTER #{column_name} SET DEFAULT '#{options[:default]}'"
|
82
|
+
end
|
83
|
+
if options[:null] == false
|
84
|
+
sql_commands << "ALTER TABLE #{table_name} ALTER #{column_name} SET NOT NULL"
|
85
|
+
end
|
86
|
+
sql_commands.each { |cmd| execute(cmd) }
|
87
|
+
rescue Exception => e
|
88
|
+
@logger.unknown("exception=#{e}") if @trace
|
89
|
+
raise
|
90
|
+
end
|
91
|
+
|
92
|
+
def change_column(table_name, column_name, type, options = {})
|
93
|
+
@logger.unknown("ODBCAdapter#change_column>") if @trace
|
94
|
+
execute "ALTER TABLE #{table_name} ALTER #{column_name} TYPE #{type}"
|
95
|
+
change_column_default(table_name, column_name, options[:default]) unless options[:default].nil?
|
96
|
+
rescue Exception => e
|
97
|
+
@logger.unknown("exception=#{e}") if @trace
|
98
|
+
raise
|
99
|
+
end
|
100
|
+
|
101
|
+
def change_column_default(table_name, column_name, default)
|
102
|
+
@logger.unknown("ODBCAdapter#change_column_default>") if @trace
|
103
|
+
execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET DEFAULT '#{default}'"
|
104
|
+
rescue Exception => e
|
105
|
+
@logger.unknown("exception=#{e}") if @trace
|
106
|
+
raise
|
107
|
+
end
|
108
|
+
|
109
|
+
def rename_column(table_name, column_name, new_column_name)
|
110
|
+
@logger.unknown("ODBCAdapter#rename_column>") if @trace
|
111
|
+
execute "ALTER TABLE #{table_name} RENAME COLUMN #{column_name} TO #{new_column_name}"
|
112
|
+
rescue Exception => e
|
113
|
+
@logger.unknown("exception=#{e}") if @trace
|
114
|
+
raise
|
115
|
+
end
|
116
|
+
|
117
|
+
def remove_index(table_name, options = {})
|
118
|
+
@logger.unknown("ODBCAdapter#remove_index>") if @trace
|
119
|
+
if Hash === options
|
120
|
+
index_name = options[:name]
|
121
|
+
else
|
122
|
+
index_name = "#{table_name}_#{options}_index"
|
123
|
+
end
|
124
|
+
execute "DROP INDEX #{index_name}"
|
125
|
+
rescue Exception => e
|
126
|
+
@logger.unknown("exception=#{e}") if @trace
|
127
|
+
raise
|
128
|
+
end
|
129
|
+
|
130
|
+
# ------------------------------------------------------------------------
|
131
|
+
# Private methods to support methods above
|
132
|
+
#
|
133
|
+
private
|
134
|
+
|
135
|
+
# Find a table's primary key and sequence.
|
136
|
+
def pk_and_sequence_for(table)
|
137
|
+
# First try looking for a sequence with a dependency on the
|
138
|
+
# given table's primary key.
|
139
|
+
result = select_all(<<-end_sql, 'PK and serial sequence')[0]
|
140
|
+
SELECT attr.attname, name.nspname, seq.relname
|
141
|
+
FROM pg_class seq,
|
142
|
+
pg_attribute attr,
|
143
|
+
pg_depend dep,
|
144
|
+
pg_namespace name,
|
145
|
+
pg_constraint cons
|
146
|
+
WHERE seq.oid = dep.objid
|
147
|
+
AND seq.relnamespace = name.oid
|
148
|
+
AND seq.relkind = 'S'
|
149
|
+
AND attr.attrelid = dep.refobjid
|
150
|
+
AND attr.attnum = dep.refobjsubid
|
151
|
+
AND attr.attrelid = cons.conrelid
|
152
|
+
AND attr.attnum = cons.conkey[1]
|
153
|
+
AND cons.contype = 'p'
|
154
|
+
AND dep.refobjid = '#{table}'::regclass
|
155
|
+
end_sql
|
156
|
+
|
157
|
+
if result.nil? or result.empty?
|
158
|
+
# If that fails, try parsing the primary key's default value.
|
159
|
+
# Support the 7.x and 8.0 nextval('foo'::text) as well as
|
160
|
+
# the 8.1+ nextval('foo'::regclass).
|
161
|
+
result = select_all(<<-end_sql, 'PK and custom sequence')[0]
|
162
|
+
SELECT attr.attname, name.nspname, split_part(def.adsrc, '\\\'', 2)
|
163
|
+
FROM pg_class t
|
164
|
+
JOIN pg_namespace name ON (t.relnamespace = name.oid)
|
165
|
+
JOIN pg_attribute attr ON (t.oid = attrelid)
|
166
|
+
JOIN pg_attrdef def ON (adrelid = attrelid AND adnum = attnum)
|
167
|
+
JOIN pg_constraint cons ON (conrelid = adrelid AND adnum = conkey[1])
|
168
|
+
WHERE t.oid = '#{table}'::regclass
|
169
|
+
AND cons.contype = 'p'
|
170
|
+
AND def.adsrc ~* 'nextval'
|
171
|
+
end_sql
|
172
|
+
end
|
173
|
+
# check for existence of . in sequence name as in public.foo_sequence. if it does not exist, join the current namespace
|
174
|
+
result.last['.'] ? [result.first, result.last] : [result.first, "#{result[1]}.#{result[2]}"]
|
175
|
+
rescue
|
176
|
+
nil
|
177
|
+
end
|
178
|
+
|
179
|
+
end # module
|