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