ActiveRecord-JDBC 0.2.1 → 0.2.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/lib/active_record/connection_adapters/jdbc_adapter.rb +45 -9
- data/lib/active_record/connection_adapters/jdbc_adapter_spec.rb +9 -1132
- data/lib/jdbc_adapter/jdbc_db2.rb +83 -0
- data/lib/jdbc_adapter/jdbc_derby.rb +113 -0
- data/lib/jdbc_adapter/jdbc_firebird.rb +103 -0
- data/lib/jdbc_adapter/jdbc_hsqldb.rb +104 -0
- data/lib/jdbc_adapter/jdbc_mimer.rb +122 -0
- data/lib/jdbc_adapter/jdbc_mssql.rb +208 -0
- data/lib/jdbc_adapter/jdbc_mysql.rb +119 -0
- data/lib/jdbc_adapter/jdbc_oracle.rb +237 -0
- data/lib/jdbc_adapter/jdbc_postgre.rb +173 -0
- data/test/db/hsqldb.rb +14 -0
- data/test/db/logger.rb +3 -0
- data/test/db/mysql.rb +20 -0
- data/test/hsqldb_simple_test.rb +9 -0
- data/test/manualTestDatabase.rb +5 -5
- data/test/minirunit/testHsqldb.rb +8 -6
- data/test/minirunit/testMysql.rb +1 -1
- data/test/models/entry.rb +22 -0
- data/test/mysql_simple_test.rb +15 -0
- data/test/simple.rb +65 -0
- metadata +21 -2
@@ -0,0 +1,208 @@
|
|
1
|
+
module JdbcSpec
|
2
|
+
module MsSQL
|
3
|
+
module Column
|
4
|
+
def simplified_type(field_type)
|
5
|
+
case field_type
|
6
|
+
when /int|bigint|smallint|tinyint/i then :integer
|
7
|
+
when /float|double|decimal|money|numeric|real|smallmoney/i then @scale == 0 ? :integer : :float
|
8
|
+
when /datetime|smalldatetime/i then :datetime
|
9
|
+
when /timestamp/i then :timestamp
|
10
|
+
when /time/i then :time
|
11
|
+
when /text|ntext/i then :text
|
12
|
+
when /binary|image|varbinary/i then :binary
|
13
|
+
when /char|nchar|nvarchar|string|varchar/i then :string
|
14
|
+
when /bit/i then :boolean
|
15
|
+
when /uniqueidentifier/i then :string
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def type_cast(value)
|
20
|
+
return nil if value.nil? || value =~ /^\s*null\s*$/i
|
21
|
+
case type
|
22
|
+
when :string then value
|
23
|
+
when :integer then value == true || value == false ? value == true ? 1 : 0 : value.to_i
|
24
|
+
when :primary_key then value == true || value == false ? value == true ? 1 : 0 : value.to_i
|
25
|
+
when :float then value.to_f
|
26
|
+
when :datetime then cast_to_datetime(value)
|
27
|
+
when :timestamp then cast_to_time(value)
|
28
|
+
when :time then cast_to_time(value)
|
29
|
+
when :date then cast_to_datetime(value)
|
30
|
+
when :boolean then value == true or (value =~ /^t(rue)?$/i) == 0 or value.to_s == '1'
|
31
|
+
else value
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def cast_to_time(value)
|
36
|
+
return value if value.is_a?(Time)
|
37
|
+
time_array = ParseDate.parsedate(value)
|
38
|
+
time_array[0] ||= 2000
|
39
|
+
time_array[1] ||= 1
|
40
|
+
time_array[2] ||= 1
|
41
|
+
Time.send(Base.default_timezone, *time_array) rescue nil
|
42
|
+
end
|
43
|
+
|
44
|
+
def cast_to_datetime(value)
|
45
|
+
if value.is_a?(Time)
|
46
|
+
if value.year != 0 and value.month != 0 and value.day != 0
|
47
|
+
return value
|
48
|
+
else
|
49
|
+
return Time.mktime(2000, 1, 1, value.hour, value.min, value.sec) rescue nil
|
50
|
+
end
|
51
|
+
end
|
52
|
+
return cast_to_time(value) if value.is_a?(Date) or value.is_a?(String) rescue nil
|
53
|
+
value
|
54
|
+
end
|
55
|
+
|
56
|
+
# These methods will only allow the adapter to insert binary data with a length of 7K or less
|
57
|
+
# because of a SQL Server statement length policy.
|
58
|
+
def self.string_to_binary(value)
|
59
|
+
value.gsub(/(\r|\n|\0|\x1a)/) do
|
60
|
+
case $1
|
61
|
+
when "\r" then "%00"
|
62
|
+
when "\n" then "%01"
|
63
|
+
when "\0" then "%02"
|
64
|
+
when "\x1a" then "%03"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.binary_to_string(value)
|
70
|
+
value.gsub(/(%00|%01|%02|%03)/) do
|
71
|
+
case $1
|
72
|
+
when "%00" then "\r"
|
73
|
+
when "%01" then "\n"
|
74
|
+
when "%02\0" then "\0"
|
75
|
+
when "%03" then "\x1a"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def modify_types(tp)
|
82
|
+
tp[:primary_key] = "int NOT NULL IDENTITY(1, 1) PRIMARY KEY"
|
83
|
+
tp[:integer][:limit] = nil
|
84
|
+
tp[:boolean][:limit] = nil
|
85
|
+
tp[:binary] = { :name => "image"}
|
86
|
+
tp
|
87
|
+
end
|
88
|
+
|
89
|
+
def quote(value, column = nil)
|
90
|
+
if column && column.type == :primary_key
|
91
|
+
return value.to_s
|
92
|
+
end
|
93
|
+
case value
|
94
|
+
when String
|
95
|
+
if column && column.type == :binary && column.class.respond_to?(:string_to_binary)
|
96
|
+
val = quote_string(column.class.string_to_binary(value))
|
97
|
+
"'#{val}'"
|
98
|
+
else
|
99
|
+
"'#{quote_string(value)}'"
|
100
|
+
end
|
101
|
+
when NilClass then "NULL"
|
102
|
+
when TrueClass then '1'
|
103
|
+
when FalseClass then '0'
|
104
|
+
when Float, Fixnum, Bignum then value.to_s
|
105
|
+
when Date then "'#{value.to_s}'"
|
106
|
+
when Time, DateTime then "'#{value.strftime("%Y-%m-%d %H:%M:%S")}'"
|
107
|
+
else "'#{quote_string(value.to_yaml)}'"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def quote_string(string)
|
112
|
+
string.gsub(/\'/, "''")
|
113
|
+
end
|
114
|
+
|
115
|
+
def quoted_true
|
116
|
+
"1"
|
117
|
+
end
|
118
|
+
|
119
|
+
def quoted_false
|
120
|
+
"0"
|
121
|
+
end
|
122
|
+
|
123
|
+
def quote_column_name(name)
|
124
|
+
"[#{name}]"
|
125
|
+
end
|
126
|
+
|
127
|
+
def add_limit_offset!(sql, options)
|
128
|
+
if options[:limit] and options[:offset]
|
129
|
+
total_rows = @connection.select_all("SELECT count(*) as TotalRows from (#{sql.gsub(/\bSELECT\b/i, "SELECT TOP 1000000000")}) tally")[0][:TotalRows].to_i
|
130
|
+
if (options[:limit] + options[:offset]) >= total_rows
|
131
|
+
options[:limit] = (total_rows - options[:offset] >= 0) ? (total_rows - options[:offset]) : 0
|
132
|
+
end
|
133
|
+
sql.sub!(/^\s*SELECT/i, "SELECT * FROM (SELECT TOP #{options[:limit]} * FROM (SELECT TOP #{options[:limit] + options[:offset]} ")
|
134
|
+
sql << ") AS tmp1"
|
135
|
+
if options[:order]
|
136
|
+
options[:order] = options[:order].split(',').map do |field|
|
137
|
+
parts = field.split(" ")
|
138
|
+
tc = parts[0]
|
139
|
+
if sql =~ /\.\[/ and tc =~ /\./ # if column quoting used in query
|
140
|
+
tc.gsub!(/\./, '\\.\\[')
|
141
|
+
tc << '\\]'
|
142
|
+
end
|
143
|
+
if sql =~ /#{tc} AS (t\d_r\d\d?)/
|
144
|
+
parts[0] = $1
|
145
|
+
end
|
146
|
+
parts.join(' ')
|
147
|
+
end.join(', ')
|
148
|
+
sql << " ORDER BY #{change_order_direction(options[:order])}) AS tmp2 ORDER BY #{options[:order]}"
|
149
|
+
else
|
150
|
+
sql << " ) AS tmp2"
|
151
|
+
end
|
152
|
+
elsif sql !~ /^\s*SELECT (@@|COUNT\()/i
|
153
|
+
sql.sub!(/^\s*SELECT([\s]*distinct)?/i) do
|
154
|
+
"SELECT#{$1} TOP #{options[:limit]}"
|
155
|
+
end unless options[:limit].nil?
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def recreate_database(name)
|
160
|
+
drop_database(name)
|
161
|
+
create_database(name)
|
162
|
+
end
|
163
|
+
|
164
|
+
def drop_database(name)
|
165
|
+
execute "DROP DATABASE #{name}"
|
166
|
+
end
|
167
|
+
|
168
|
+
def create_database(name)
|
169
|
+
execute "CREATE DATABASE #{name}"
|
170
|
+
end
|
171
|
+
|
172
|
+
def rename_table(name, new_name)
|
173
|
+
execute "EXEC sp_rename '#{name}', '#{new_name}'"
|
174
|
+
end
|
175
|
+
|
176
|
+
def rename_column(table, column, new_column_name)
|
177
|
+
execute "EXEC sp_rename '#{table}.#{column}', '#{new_column_name}'"
|
178
|
+
end
|
179
|
+
|
180
|
+
def change_column(table_name, column_name, type, options = {}) #:nodoc:
|
181
|
+
sql_commands = ["ALTER TABLE #{table_name} ALTER COLUMN #{column_name} #{type_to_sql(type, options[:limit])}"]
|
182
|
+
if options[:default]
|
183
|
+
remove_default_constraint(table_name, column_name)
|
184
|
+
sql_commands << "ALTER TABLE #{table_name} ADD CONSTRAINT DF_#{table_name}_#{column_name} DEFAULT #{options[:default]} FOR #{column_name}"
|
185
|
+
end
|
186
|
+
sql_commands.each {|c|
|
187
|
+
execute(c)
|
188
|
+
}
|
189
|
+
end
|
190
|
+
|
191
|
+
def remove_column(table_name, column_name)
|
192
|
+
remove_default_constraint(table_name, column_name)
|
193
|
+
execute "ALTER TABLE #{table_name} DROP COLUMN #{column_name}"
|
194
|
+
end
|
195
|
+
|
196
|
+
def remove_default_constraint(table_name, column_name)
|
197
|
+
defaults = select "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"
|
198
|
+
defaults.each {|constraint|
|
199
|
+
execute "ALTER TABLE #{table_name} DROP CONSTRAINT #{constraint["name"]}"
|
200
|
+
}
|
201
|
+
end
|
202
|
+
|
203
|
+
def remove_index(table_name, options = {})
|
204
|
+
execute "DROP INDEX #{table_name}.#{index_name(table_name, options)}"
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
@@ -0,0 +1,119 @@
|
|
1
|
+
module JdbcSpec
|
2
|
+
module MySQL
|
3
|
+
def modify_types(tp)
|
4
|
+
tp[:primary_key] = "int(11) DEFAULT NULL auto_increment PRIMARY KEY"
|
5
|
+
tp[:decimal] = { :name => "decimal" }
|
6
|
+
tp
|
7
|
+
end
|
8
|
+
|
9
|
+
# QUOTING ==================================================
|
10
|
+
|
11
|
+
def quote(value, column = nil)
|
12
|
+
if column && column.type == :primary_key
|
13
|
+
return value.to_s
|
14
|
+
end
|
15
|
+
super
|
16
|
+
end
|
17
|
+
|
18
|
+
def quote_column_name(name) #:nodoc:
|
19
|
+
"`#{name}`"
|
20
|
+
end
|
21
|
+
|
22
|
+
# from active_record/vendor/mysql.rb
|
23
|
+
def quote_string(str) #:nodoc:
|
24
|
+
str.gsub(/([\0\n\r\032\'\"\\])/) do
|
25
|
+
case $1
|
26
|
+
when "\0" then "\\0"
|
27
|
+
when "\n" then "\\n"
|
28
|
+
when "\r" then "\\r"
|
29
|
+
when "\032" then "\\Z"
|
30
|
+
else "\\"+$1
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def quoted_true
|
36
|
+
"1"
|
37
|
+
end
|
38
|
+
|
39
|
+
def quoted_false
|
40
|
+
"0"
|
41
|
+
end
|
42
|
+
|
43
|
+
# SCHEMA STATEMENTS ========================================
|
44
|
+
|
45
|
+
def structure_dump #:nodoc:
|
46
|
+
if supports_views?
|
47
|
+
sql = "SHOW FULL TABLES WHERE Table_type = 'BASE TABLE'"
|
48
|
+
else
|
49
|
+
sql = "SHOW TABLES"
|
50
|
+
end
|
51
|
+
|
52
|
+
select_all(sql).inject("") do |structure, table|
|
53
|
+
table.delete('Table_type')
|
54
|
+
structure += select_one("SHOW CREATE TABLE #{table.to_a.first.last}")["Create Table"] + ";\n\n"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def recreate_database(name) #:nodoc:
|
59
|
+
drop_database(name)
|
60
|
+
create_database(name)
|
61
|
+
end
|
62
|
+
|
63
|
+
def create_database(name) #:nodoc:
|
64
|
+
execute "CREATE DATABASE `#{name}`"
|
65
|
+
end
|
66
|
+
|
67
|
+
def drop_database(name) #:nodoc:
|
68
|
+
execute "DROP DATABASE IF EXISTS `#{name}`"
|
69
|
+
end
|
70
|
+
|
71
|
+
def current_database
|
72
|
+
select_one("SELECT DATABASE() as db")["db"]
|
73
|
+
end
|
74
|
+
|
75
|
+
def indexes(table_name, name = nil)#:nodoc:
|
76
|
+
indexes = []
|
77
|
+
current_index = nil
|
78
|
+
execute("SHOW KEYS FROM #{table_name}", name).each do |row|
|
79
|
+
if current_index != row[2]
|
80
|
+
next if row[2] == "PRIMARY" # skip the primary key
|
81
|
+
current_index = row[2]
|
82
|
+
indexes << IndexDefinition.new(row[0], row[2], row[1] == "0", [])
|
83
|
+
end
|
84
|
+
|
85
|
+
indexes.last.columns << row[4]
|
86
|
+
end
|
87
|
+
indexes
|
88
|
+
end
|
89
|
+
|
90
|
+
def create_table(name, options = {}) #:nodoc:
|
91
|
+
super(name, {:options => "ENGINE=InnoDB"}.merge(options))
|
92
|
+
end
|
93
|
+
|
94
|
+
def rename_table(name, new_name)
|
95
|
+
execute "RENAME TABLE #{name} TO #{new_name}"
|
96
|
+
end
|
97
|
+
|
98
|
+
def change_column_default(table_name, column_name, default) #:nodoc:
|
99
|
+
current_type = select_one("SHOW COLUMNS FROM #{table_name} LIKE '#{column_name}'")["type"]
|
100
|
+
|
101
|
+
type, limit = native_sql_to_type(current_type)
|
102
|
+
|
103
|
+
change_column(table_name, column_name, type, { :default => default, :limit => limit })
|
104
|
+
end
|
105
|
+
|
106
|
+
def change_column(table_name, column_name, type, options = {}) #:nodoc:
|
107
|
+
options[:default] ||= select_one("SHOW COLUMNS FROM #{table_name} LIKE '#{column_name}'")["default"]
|
108
|
+
|
109
|
+
change_column_sql = "ALTER TABLE #{table_name} CHANGE #{column_name} #{column_name} #{type_to_sql(type, options[:limit])}"
|
110
|
+
add_column_options!(change_column_sql, options)
|
111
|
+
execute(change_column_sql)
|
112
|
+
end
|
113
|
+
|
114
|
+
def rename_column(table_name, column_name, new_column_name) #:nodoc:
|
115
|
+
current_type = select_one("SHOW COLUMNS FROM #{table_name} LIKE '#{column_name}'")["type"]
|
116
|
+
execute "ALTER TABLE #{table_name} CHANGE #{column_name} #{new_column_name} #{current_type}"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,237 @@
|
|
1
|
+
module JdbcSpec
|
2
|
+
module Oracle
|
3
|
+
module Column
|
4
|
+
def type_cast(value)
|
5
|
+
return nil if value.nil? || value =~ /^\s*null\s*$/i
|
6
|
+
case type
|
7
|
+
when :string then value
|
8
|
+
when :integer then defined?(value.to_i) ? value.to_i : (value ? 1 : 0)
|
9
|
+
when :primary_key then defined?(value.to_i) ? value.to_i : (value ? 1 : 0)
|
10
|
+
when :float then value.to_f
|
11
|
+
when :datetime then cast_to_date_or_time(value)
|
12
|
+
when :time then cast_to_time(value)
|
13
|
+
else value
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
def simplified_type(field_type)
|
19
|
+
case field_type
|
20
|
+
when /char/i : :string
|
21
|
+
when /num|float|double|dec|real|int/i : @scale == 0 ? :integer : :float
|
22
|
+
when /date|time/i : @name =~ /_at$/ ? :time : :datetime
|
23
|
+
when /clob/i : :text
|
24
|
+
when /blob/i : :binary
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def cast_to_date_or_time(value)
|
29
|
+
return value if value.is_a? Date
|
30
|
+
return nil if value.blank?
|
31
|
+
guess_date_or_time (value.is_a? Time) ? value : cast_to_time(value)
|
32
|
+
end
|
33
|
+
|
34
|
+
def cast_to_time(value)
|
35
|
+
return value if value.is_a? Time
|
36
|
+
time_array = ParseDate.parsedate value
|
37
|
+
time_array[0] ||= 2000; time_array[1] ||= 1; time_array[2] ||= 1;
|
38
|
+
Time.send(Base.default_timezone, *time_array) rescue nil
|
39
|
+
end
|
40
|
+
|
41
|
+
def guess_date_or_time(value)
|
42
|
+
(value.hour == 0 and value.min == 0 and value.sec == 0) ?
|
43
|
+
Date.new(value.year, value.month, value.day) : value
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def default_sequence_name(table, column) #:nodoc:
|
48
|
+
"#{table}_seq"
|
49
|
+
end
|
50
|
+
|
51
|
+
def create_table(name, options = {}) #:nodoc:
|
52
|
+
super(name, options)
|
53
|
+
execute "CREATE SEQUENCE #{name}_seq START WITH 10000" unless options[:id] == false
|
54
|
+
end
|
55
|
+
|
56
|
+
def rename_table(name, new_name) #:nodoc:
|
57
|
+
execute "RENAME #{name} TO #{new_name}"
|
58
|
+
execute "RENAME #{name}_seq TO #{new_name}_seq" rescue nil
|
59
|
+
end
|
60
|
+
|
61
|
+
def drop_table(name) #:nodoc:
|
62
|
+
super(name)
|
63
|
+
execute "DROP SEQUENCE #{name}_seq" rescue nil
|
64
|
+
end
|
65
|
+
|
66
|
+
def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
|
67
|
+
if pk.nil? # Who called us? What does the sql look like? No idea!
|
68
|
+
execute sql, name
|
69
|
+
elsif id_value # Pre-assigned id
|
70
|
+
log(sql, name) { @connection.execute_insert sql,pk }
|
71
|
+
else # Assume the sql contains a bind-variable for the id
|
72
|
+
id_value = select_one("select #{sequence_name}.nextval id from dual")['id']
|
73
|
+
log(sql, name) {
|
74
|
+
execute_prepared_insert(sql,id_value)
|
75
|
+
}
|
76
|
+
end
|
77
|
+
id_value
|
78
|
+
end
|
79
|
+
|
80
|
+
def execute_prepared_insert(sql, id)
|
81
|
+
@stmts ||= {}
|
82
|
+
@stmts[sql] ||= @connection.ps(sql)
|
83
|
+
stmt = @stmts[sql]
|
84
|
+
stmt.setLong(1,id)
|
85
|
+
stmt.executeUpdate
|
86
|
+
id
|
87
|
+
end
|
88
|
+
|
89
|
+
def modify_types(tp)
|
90
|
+
tp[:primary_key] = "NUMBER(38) NOT NULL PRIMARY KEY"
|
91
|
+
tp[:datetime] = { :name => "DATE" }
|
92
|
+
tp[:timestamp] = { :name => "DATE" }
|
93
|
+
tp[:time] = { :name => "DATE" }
|
94
|
+
tp[:date] = { :name => "DATE" }
|
95
|
+
tp
|
96
|
+
end
|
97
|
+
|
98
|
+
def add_limit_offset!(sql, options) #:nodoc:
|
99
|
+
offset = options[:offset] || 0
|
100
|
+
|
101
|
+
if limit = options[:limit]
|
102
|
+
sql.replace "select * from (select raw_sql_.*, rownum raw_rnum_ from (#{sql}) raw_sql_ where rownum <= #{offset+limit}) where raw_rnum_ > #{offset}"
|
103
|
+
elsif offset > 0
|
104
|
+
sql.replace "select * from (select raw_sql_.*, rownum raw_rnum_ from (#{sql}) raw_sql_) where raw_rnum_ > #{offset}"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def current_database #:nodoc:
|
109
|
+
select_one("select sys_context('userenv','db_name') db from dual")["db"]
|
110
|
+
end
|
111
|
+
|
112
|
+
def indexes(table_name, name = nil) #:nodoc:
|
113
|
+
result = select_all(<<-SQL, name)
|
114
|
+
SELECT lower(i.index_name) as index_name, i.uniqueness, lower(c.column_name) as column_name
|
115
|
+
FROM user_indexes i, user_ind_columns c
|
116
|
+
WHERE i.table_name = '#{table_name.to_s.upcase}'
|
117
|
+
AND c.index_name = i.index_name
|
118
|
+
AND i.index_name NOT IN (SELECT index_name FROM user_constraints WHERE constraint_type = 'P')
|
119
|
+
ORDER BY i.index_name, c.column_position
|
120
|
+
SQL
|
121
|
+
|
122
|
+
current_index = nil
|
123
|
+
indexes = []
|
124
|
+
|
125
|
+
result.each do |row|
|
126
|
+
if current_index != row['index_name']
|
127
|
+
indexes << IndexDefinition.new(table_name, row['index_name'], row['uniqueness'] == "UNIQUE", [])
|
128
|
+
current_index = row['index_name']
|
129
|
+
end
|
130
|
+
|
131
|
+
indexes.last.columns << row['column_name']
|
132
|
+
end
|
133
|
+
|
134
|
+
indexes
|
135
|
+
end
|
136
|
+
|
137
|
+
def remove_index(table_name, options = {}) #:nodoc:
|
138
|
+
execute "DROP INDEX #{index_name(table_name, options)}"
|
139
|
+
end
|
140
|
+
|
141
|
+
def change_column_default(table_name, column_name, default) #:nodoc:
|
142
|
+
execute "ALTER TABLE #{table_name} MODIFY #{column_name} DEFAULT #{quote(default)}"
|
143
|
+
end
|
144
|
+
|
145
|
+
def change_column(table_name, column_name, type, options = {}) #:nodoc:
|
146
|
+
change_column_sql = "ALTER TABLE #{table_name} MODIFY #{column_name} #{type_to_sql(type, options[:limit])}"
|
147
|
+
add_column_options!(change_column_sql, options)
|
148
|
+
execute(change_column_sql)
|
149
|
+
end
|
150
|
+
|
151
|
+
def rename_column(table_name, column_name, new_column_name) #:nodoc:
|
152
|
+
execute "ALTER TABLE #{table_name} RENAME COLUMN #{column_name} to #{new_column_name}"
|
153
|
+
end
|
154
|
+
|
155
|
+
def remove_column(table_name, column_name) #:nodoc:
|
156
|
+
execute "ALTER TABLE #{table_name} DROP COLUMN #{column_name}"
|
157
|
+
end
|
158
|
+
|
159
|
+
def structure_dump #:nodoc:
|
160
|
+
s = select_all("select sequence_name from user_sequences").inject("") do |structure, seq|
|
161
|
+
structure << "create sequence #{seq.to_a.first.last};\n\n"
|
162
|
+
end
|
163
|
+
|
164
|
+
select_all("select table_name from user_tables").inject(s) do |structure, table|
|
165
|
+
ddl = "create table #{table.to_a.first.last} (\n "
|
166
|
+
cols = select_all(%Q{
|
167
|
+
select column_name, data_type, data_length, data_precision, data_scale, data_default, nullable
|
168
|
+
from user_tab_columns
|
169
|
+
where table_name = '#{table.to_a.first.last}'
|
170
|
+
order by column_id
|
171
|
+
}).map do |row|
|
172
|
+
col = "#{row['column_name'].downcase} #{row['data_type'].downcase}"
|
173
|
+
if row['data_type'] =='NUMBER' and !row['data_precision'].nil?
|
174
|
+
col << "(#{row['data_precision'].to_i}"
|
175
|
+
col << ",#{row['data_scale'].to_i}" if !row['data_scale'].nil?
|
176
|
+
col << ')'
|
177
|
+
elsif row['data_type'].include?('CHAR')
|
178
|
+
col << "(#{row['data_length'].to_i})"
|
179
|
+
end
|
180
|
+
col << " default #{row['data_default']}" if !row['data_default'].nil?
|
181
|
+
col << ' not null' if row['nullable'] == 'N'
|
182
|
+
col
|
183
|
+
end
|
184
|
+
ddl << cols.join(",\n ")
|
185
|
+
ddl << ");\n\n"
|
186
|
+
structure << ddl
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def structure_drop #:nodoc:
|
191
|
+
s = select_all("select sequence_name from user_sequences").inject("") do |drop, seq|
|
192
|
+
drop << "drop sequence #{seq.to_a.first.last};\n\n"
|
193
|
+
end
|
194
|
+
|
195
|
+
select_all("select table_name from user_tables").inject(s) do |drop, table|
|
196
|
+
drop << "drop table #{table.to_a.first.last} cascade constraints;\n\n"
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
# QUOTING ==================================================
|
201
|
+
#
|
202
|
+
# see: abstract/quoting.rb
|
203
|
+
|
204
|
+
# camelCase column names need to be quoted; not that anyone using Oracle
|
205
|
+
# would really do this, but handling this case means we pass the test...
|
206
|
+
def quote_column_name(name) #:nodoc:
|
207
|
+
name =~ /[A-Z]/ ? "\"#{name}\"" : name
|
208
|
+
end
|
209
|
+
|
210
|
+
def quote_string(string) #:nodoc:
|
211
|
+
string.gsub(/'/, "''")
|
212
|
+
end
|
213
|
+
|
214
|
+
def quote(value, column = nil) #:nodoc:
|
215
|
+
if column && column.type == :binary
|
216
|
+
if /(.*?)\([0-9]+\)/ =~ column.sql_type
|
217
|
+
%Q{empty_#{ $1 }()}
|
218
|
+
else
|
219
|
+
%Q{empty_#{ column.sql_type rescue 'blob' }()}
|
220
|
+
end
|
221
|
+
else
|
222
|
+
if column && column.type == :primary_key
|
223
|
+
return value.to_s
|
224
|
+
end
|
225
|
+
case value
|
226
|
+
when String : %Q{'#{quote_string(value)}'}
|
227
|
+
when NilClass : 'null'
|
228
|
+
when TrueClass : '1'
|
229
|
+
when FalseClass : '0'
|
230
|
+
when Numeric : value.to_s
|
231
|
+
when Date, Time : %Q{TIMESTAMP'#{value.strftime("%Y-%m-%d %H:%M:%S")}'}
|
232
|
+
else %Q{'#{quote_string(value.to_yaml)}'}
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|