activerecord-jdbc-adapter 0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/History.txt +61 -0
  2. data/LICENSE +21 -0
  3. data/Manifest.txt +64 -0
  4. data/README.txt +116 -0
  5. data/Rakefile +146 -0
  6. data/lib/active_record/connection_adapters/derby_adapter.rb +13 -0
  7. data/lib/active_record/connection_adapters/h2_adapter.rb +1 -0
  8. data/lib/active_record/connection_adapters/hsqldb_adapter.rb +13 -0
  9. data/lib/active_record/connection_adapters/jdbc_adapter.rb +575 -0
  10. data/lib/active_record/connection_adapters/jdbc_adapter_spec.rb +10 -0
  11. data/lib/active_record/connection_adapters/jndi_adapter.rb +1 -0
  12. data/lib/active_record/connection_adapters/mysql_adapter.rb +13 -0
  13. data/lib/active_record/connection_adapters/oracle_adapter.rb +1 -0
  14. data/lib/active_record/connection_adapters/postgresql_adapter.rb +13 -0
  15. data/lib/jdbc_adapter.rb +32 -0
  16. data/lib/jdbc_adapter/jdbc_db2.rb +104 -0
  17. data/lib/jdbc_adapter/jdbc_derby.rb +362 -0
  18. data/lib/jdbc_adapter/jdbc_firebird.rb +109 -0
  19. data/lib/jdbc_adapter/jdbc_hsqldb.rb +168 -0
  20. data/lib/jdbc_adapter/jdbc_mimer.rb +134 -0
  21. data/lib/jdbc_adapter/jdbc_mssql.rb +356 -0
  22. data/lib/jdbc_adapter/jdbc_mysql.rb +168 -0
  23. data/lib/jdbc_adapter/jdbc_oracle.rb +340 -0
  24. data/lib/jdbc_adapter/jdbc_postgre.rb +347 -0
  25. data/lib/jdbc_adapter/missing_functionality_helper.rb +72 -0
  26. data/lib/jdbc_adapter/version.rb +5 -0
  27. data/lib/jdbc_adapter_internal.jar +0 -0
  28. data/lib/tasks/jdbc_databases.rake +72 -0
  29. data/src/java/JDBCDerbySpec.java +323 -0
  30. data/src/java/JDBCMySQLSpec.java +89 -0
  31. data/src/java/JdbcAdapterInternalService.java +953 -0
  32. data/test/activerecord/connection_adapters/type_conversion_test.rb +31 -0
  33. data/test/activerecord/connections/native_jdbc_mysql/connection.rb +25 -0
  34. data/test/db/derby.rb +18 -0
  35. data/test/db/h2.rb +11 -0
  36. data/test/db/hsqldb.rb +15 -0
  37. data/test/db/jdbc.rb +11 -0
  38. data/test/db/jndi_config.rb +30 -0
  39. data/test/db/logger.rb +3 -0
  40. data/test/db/mysql.rb +9 -0
  41. data/test/db/postgres.rb +9 -0
  42. data/test/derby_multibyte_test.rb +12 -0
  43. data/test/derby_simple_test.rb +12 -0
  44. data/test/generic_jdbc_connection_test.rb +9 -0
  45. data/test/h2_simple_test.rb +7 -0
  46. data/test/hsqldb_simple_test.rb +6 -0
  47. data/test/jdbc_adapter/jdbc_db2_test.rb +21 -0
  48. data/test/jdbc_common.rb +6 -0
  49. data/test/jndi_test.rb +37 -0
  50. data/test/manualTestDatabase.rb +195 -0
  51. data/test/minirunit.rb +109 -0
  52. data/test/minirunit/testConnect.rb +14 -0
  53. data/test/minirunit/testH2.rb +73 -0
  54. data/test/minirunit/testHsqldb.rb +73 -0
  55. data/test/minirunit/testLoadActiveRecord.rb +3 -0
  56. data/test/minirunit/testMysql.rb +83 -0
  57. data/test/minirunit/testRawSelect.rb +24 -0
  58. data/test/models/auto_id.rb +18 -0
  59. data/test/models/data_types.rb +18 -0
  60. data/test/models/entry.rb +20 -0
  61. data/test/mysql_multibyte_test.rb +6 -0
  62. data/test/mysql_simple_test.rb +13 -0
  63. data/test/postgres_simple_test.rb +12 -0
  64. data/test/simple.rb +157 -0
  65. metadata +112 -0
@@ -0,0 +1,10 @@
1
+
2
+ require 'jdbc_adapter/jdbc_mimer'
3
+ require 'jdbc_adapter/jdbc_hsqldb'
4
+ require 'jdbc_adapter/jdbc_oracle'
5
+ require 'jdbc_adapter/jdbc_postgre'
6
+ require 'jdbc_adapter/jdbc_mysql'
7
+ require 'jdbc_adapter/jdbc_derby'
8
+ require 'jdbc_adapter/jdbc_firebird'
9
+ require 'jdbc_adapter/jdbc_db2'
10
+ require 'jdbc_adapter/jdbc_mssql'
@@ -0,0 +1 @@
1
+ require 'active_record/connection_adapters/jdbc_adapter'
@@ -0,0 +1,13 @@
1
+ tried_gem = false
2
+ begin
3
+ require "jdbc/mysql"
4
+ rescue LoadError
5
+ unless tried_gem
6
+ require 'rubygems'
7
+ gem "jdbc-mysql"
8
+ tried_gem = true
9
+ retry
10
+ end
11
+ # trust that the mysql jar is already present
12
+ end
13
+ require 'active_record/connection_adapters/jdbc_adapter'
@@ -0,0 +1 @@
1
+ require 'active_record/connection_adapters/jdbc_adapter'
@@ -0,0 +1,13 @@
1
+ tried_gem = false
2
+ begin
3
+ require "jdbc/postgres"
4
+ rescue LoadError
5
+ unless tried_gem
6
+ require 'rubygems'
7
+ gem "jdbc-postgres"
8
+ tried_gem = true
9
+ retry
10
+ end
11
+ # trust that the postgres jar is already present
12
+ end
13
+ require 'active_record/connection_adapters/jdbc_adapter'
@@ -0,0 +1,32 @@
1
+ if RUBY_PLATFORM =~ /java/
2
+ begin
3
+ tried_gem ||= false
4
+ require 'active_record/version'
5
+ rescue LoadError
6
+ raise if tried_gem
7
+ require 'rubygems'
8
+ gem 'activerecord'
9
+ tried_gem = true
10
+ retry
11
+ end
12
+ if ActiveRecord::VERSION::MAJOR < 2
13
+ if defined?(RAILS_CONNECTION_ADAPTERS)
14
+ RAILS_CONNECTION_ADAPTERS << %q(jdbc)
15
+ else
16
+ RAILS_CONNECTION_ADAPTERS = %w(jdbc)
17
+ end
18
+ if ActiveRecord::VERSION::MAJOR == 1 && ActiveRecord::VERSION::MINOR == 14
19
+ require 'active_record/connection_adapters/jdbc_adapter'
20
+ end
21
+ end
22
+ if defined?(RAILS_ROOT)
23
+ to_file = File.expand_path(File.join(RAILS_ROOT, 'lib', 'tasks', 'jdbc_databases.rake'))
24
+ from_file = File.expand_path(File.join(File.dirname(__FILE__), 'tasks', 'jdbc_databases.rake'))
25
+ if !File.exist?(to_file) || (File.mtime(to_file) < File.mtime(from_file))
26
+ require 'fileutils'
27
+ FileUtils.cp from_file, to_file, :verbose => true
28
+ end
29
+ end
30
+ else
31
+ warn "ActiveRecord-JDBC is for use with JRuby only"
32
+ end
@@ -0,0 +1,104 @@
1
+ module JdbcSpec
2
+ module DB2
3
+ def self.column_selector
4
+ [/db2/i, lambda {|cfg,col|
5
+ if cfg[:url] =~ /^jdbc:derby:net:/
6
+ col.extend(::JdbcSpec::Derby::Column)
7
+ else
8
+ col.extend(::JdbcSpec::DB2::Column)
9
+ end }]
10
+ end
11
+
12
+ def self.adapter_selector
13
+ [/db2/i, lambda {|cfg,adapt|
14
+ if cfg[:url] =~ /^jdbc:derby:net:/
15
+ adapt.extend(::JdbcSpec::Derby)
16
+ else
17
+ adapt.extend(::JdbcSpec::DB2)
18
+ end }]
19
+ end
20
+
21
+ module Column
22
+ def type_cast(value)
23
+ return nil if value.nil? || value =~ /^\s*null\s*$/i
24
+ case type
25
+ when :string then value
26
+ when :integer then defined?(value.to_i) ? value.to_i : (value ? 1 : 0)
27
+ when :primary_key then defined?(value.to_i) ? value.to_i : (value ? 1 : 0)
28
+ when :float then value.to_f
29
+ when :datetime then cast_to_date_or_time(value)
30
+ when :timestamp then cast_to_time(value)
31
+ when :time then cast_to_time(value)
32
+ else value
33
+ end
34
+ end
35
+ def cast_to_date_or_time(value)
36
+ return value if value.is_a? Date
37
+ return nil if value.blank?
38
+ guess_date_or_time((value.is_a? Time) ? value : cast_to_time(value))
39
+ end
40
+
41
+ def cast_to_time(value)
42
+ return value if value.is_a? Time
43
+ time_array = ParseDate.parsedate value
44
+ time_array[0] ||= 2000; time_array[1] ||= 1; time_array[2] ||= 1;
45
+ Time.send(ActiveRecord::Base.default_timezone, *time_array) rescue nil
46
+ end
47
+
48
+ def guess_date_or_time(value)
49
+ (value.hour == 0 and value.min == 0 and value.sec == 0) ?
50
+ Date.new(value.year, value.month, value.day) : value
51
+ end
52
+ end
53
+
54
+ def modify_types(tp)
55
+ tp[:primary_key] = 'int generated by default as identity (start with 42) primary key'
56
+ tp[:string][:limit] = 255
57
+ tp[:integer][:limit] = nil
58
+ tp[:boolean][:limit] = nil
59
+ tp
60
+ end
61
+
62
+ def add_limit_offset!(sql, options)
63
+ if limit = options[:limit]
64
+ offset = options[:offset] || 0
65
+ sql.gsub!(/SELECT/i, 'SELECT B.* FROM (SELECT A.*, row_number() over () AS internal$rownum FROM (SELECT')
66
+ sql << ") A ) B WHERE B.internal$rownum > #{offset} AND B.internal$rownum <= #{limit + offset}"
67
+ end
68
+ end
69
+
70
+ def quote_column_name(column_name)
71
+ column_name
72
+ end
73
+
74
+ def quote(value, column = nil) # :nodoc:
75
+ if column && column.type == :primary_key
76
+ return value.to_s
77
+ end
78
+ if column && column.type == :decimal && value
79
+ return value.to_s
80
+ end
81
+ case value
82
+ when String
83
+ if column && column.type == :binary
84
+ "BLOB('#{quote_string(value)}')"
85
+ else
86
+ "'#{quote_string(value)}'"
87
+ end
88
+ else super
89
+ end
90
+ end
91
+
92
+ def quote_string(string)
93
+ string.gsub(/'/, "''") # ' (for ruby-mode)
94
+ end
95
+
96
+ def quoted_true
97
+ '1'
98
+ end
99
+
100
+ def quoted_false
101
+ '0'
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,362 @@
1
+ require 'jdbc_adapter/missing_functionality_helper'
2
+
3
+ module ::JdbcSpec
4
+ module ActiveRecordExtensions
5
+ def derby_connection(config)
6
+ config[:url] ||= "jdbc:derby:#{config[:database]};create=true"
7
+ config[:driver] ||= "org.apache.derby.jdbc.EmbeddedDriver"
8
+ embedded_driver(config)
9
+ end
10
+ end
11
+
12
+ module Derby
13
+ def self.column_selector
14
+ [/derby/i, lambda {|cfg,col| col.extend(::JdbcSpec::Derby::Column)}]
15
+ end
16
+
17
+ def self.adapter_selector
18
+ [/derby/i, lambda {|cfg,adapt| adapt.extend(::JdbcSpec::Derby)}]
19
+ end
20
+
21
+ def self.monkey_rails
22
+ unless @already_monkeyd
23
+ # Needed because Rails is broken wrt to quoting of
24
+ # some values. Most databases are nice about it,
25
+ # but not Derby. The real issue is that you can't
26
+ # compare a CHAR value to a NUMBER column.
27
+ ::ActiveRecord::Associations::ClassMethods.module_eval do
28
+ private
29
+
30
+ def select_limited_ids_list(options, join_dependency)
31
+ connection.select_all(
32
+ construct_finder_sql_for_association_limiting(options, join_dependency),
33
+ "#{name} Load IDs For Limited Eager Loading"
34
+ ).collect { |row| connection.quote(row[primary_key], columns_hash[primary_key]) }.join(", ")
35
+ end
36
+ end
37
+
38
+ @already_monkeyd = true
39
+ end
40
+ end
41
+
42
+ def self.extended(*args)
43
+ monkey_rails
44
+ end
45
+
46
+ def self.included(*args)
47
+ monkey_rails
48
+ end
49
+
50
+ module Column
51
+ def value_to_binary(value)
52
+ value.scan(/[0-9A-Fa-f]{2}/).collect {|v| v.to_i(16)}.pack("C*")
53
+ end
54
+
55
+ def cast_to_date_or_time(value)
56
+ return value if value.is_a? Date
57
+ return nil if value.blank?
58
+ guess_date_or_time((value.is_a? Time) ? value : cast_to_time(value))
59
+ end
60
+
61
+ def cast_to_time(value)
62
+ return value if value.is_a? Time
63
+ time_array = ParseDate.parsedate value
64
+ time_array[0] ||= 2000; time_array[1] ||= 1; time_array[2] ||= 1;
65
+ Time.send(ActiveRecord::Base.default_timezone, *time_array) rescue nil
66
+ end
67
+
68
+ def guess_date_or_time(value)
69
+ (value.hour == 0 and value.min == 0 and value.sec == 0) ?
70
+ Date.new(value.year, value.month, value.day) : value
71
+ end
72
+
73
+ def simplified_type(field_type)
74
+ return :boolean if field_type =~ /smallint/i
75
+ return :float if field_type =~ /real/i
76
+ super
77
+ end
78
+ end
79
+
80
+ include JdbcSpec::MissingFunctionalityHelper
81
+
82
+ def modify_types(tp)
83
+ tp[:primary_key] = "int generated by default as identity NOT NULL PRIMARY KEY"
84
+ tp[:integer][:limit] = nil
85
+ tp[:string][:limit] = 256
86
+ tp[:boolean] = {:name => "smallint"}
87
+ tp
88
+ end
89
+
90
+ def classes_for_table_name(table)
91
+ ActiveRecord::Base.send(:subclasses).select {|klass| klass.table_name == table}
92
+ end
93
+
94
+ # Set the sequence to the max value of the table's column.
95
+ def reset_sequence!(table, column, sequence = nil)
96
+ mpk = select_value("SELECT MAX(#{quote_column_name column}) FROM #{table}")
97
+ execute("ALTER TABLE #{table} ALTER COLUMN #{quote_column_name column} RESTART WITH #{mpk.to_i + 1}")
98
+ end
99
+
100
+ def reset_pk_sequence!(table, pk = nil, sequence = nil)
101
+ klasses = classes_for_table_name(table)
102
+ klass = klasses.nil? ? nil : klasses.first
103
+ pk = klass.primary_key unless klass.nil?
104
+ if pk && klass.columns_hash[pk].type == :integer
105
+ reset_sequence!(klass.table_name, pk)
106
+ end
107
+ end
108
+
109
+ def primary_key(table_name) #:nodoc:
110
+ primary_keys(table_name).first
111
+ end
112
+
113
+ def remove_index(table_name, options) #:nodoc:
114
+ execute "DROP INDEX #{index_name(table_name, options)}"
115
+ end
116
+
117
+ def rename_table(name, new_name)
118
+ execute "RENAME TABLE #{name} TO #{new_name}"
119
+ end
120
+
121
+ COLUMN_INFO_STMT = "SELECT C.COLUMNNAME, C.REFERENCEID, C.COLUMNNUMBER FROM SYS.SYSCOLUMNS C, SYS.SYSTABLES T WHERE T.TABLEID = '%s' AND T.TABLEID = C.REFERENCEID ORDER BY C.COLUMNNUMBER"
122
+
123
+ COLUMN_TYPE_STMT = "SELECT COLUMNDATATYPE, COLUMNDEFAULT FROM SYS.SYSCOLUMNS WHERE REFERENCEID = '%s' AND COLUMNNAME = '%s'"
124
+
125
+ AUTO_INC_STMT = "SELECT AUTOINCREMENTSTART, AUTOINCREMENTINC, COLUMNNAME, REFERENCEID, COLUMNDEFAULT FROM SYS.SYSCOLUMNS WHERE REFERENCEID = '%s' AND COLUMNNAME = '%s'"
126
+ AUTO_INC_STMT2 = "SELECT AUTOINCREMENTSTART, AUTOINCREMENTINC, COLUMNNAME, REFERENCEID, COLUMNDEFAULT FROM SYS.SYSCOLUMNS WHERE REFERENCEID = (SELECT T.TABLEID FROM SYS.SYSTABLES T WHERE T.TABLENAME = '%s') AND COLUMNNAME = '%s'"
127
+
128
+ def add_quotes(name)
129
+ return name unless name
130
+ %Q{"#{name}"}
131
+ end
132
+
133
+ def strip_quotes(str)
134
+ return str unless str
135
+ return str unless /^(["']).*\1$/ =~ str
136
+ str[1..-2]
137
+ end
138
+
139
+ def expand_double_quotes(name)
140
+ return name unless name && name['"']
141
+ name.gsub(/"/,'""')
142
+ end
143
+
144
+ def reinstate_auto_increment(name, refid, coldef)
145
+ stmt = AUTO_INC_STMT % [refid, strip_quotes(name)]
146
+ data = execute(stmt).first
147
+ if data
148
+ start = data['autoincrementstart']
149
+ if start
150
+ coldef << " GENERATED " << (data['columndefault'].nil? ? "ALWAYS" : "BY DEFAULT ")
151
+ coldef << "AS IDENTITY (START WITH "
152
+ coldef << start
153
+ coldef << ", INCREMENT BY "
154
+ coldef << data['autoincrementinc']
155
+ coldef << ")"
156
+ return true
157
+ end
158
+ end
159
+ false
160
+ end
161
+
162
+ def reinstate_auto_increment(name, refid, coldef)
163
+ stmt = AUTO_INC_STMT % [refid, strip_quotes(name)]
164
+ data = execute(stmt).first
165
+ if data
166
+ start = data['autoincrementstart']
167
+ if start
168
+ coldef << " GENERATED " << (data['columndefault'].nil? ? "ALWAYS" : "BY DEFAULT ")
169
+ coldef << "AS IDENTITY (START WITH "
170
+ coldef << start
171
+ coldef << ", INCREMENT BY "
172
+ coldef << data['autoincrementinc']
173
+ coldef << ")"
174
+ return true
175
+ end
176
+ end
177
+ false
178
+ end
179
+
180
+ def auto_increment_stmt(tname, cname)
181
+ stmt = AUTO_INC_STMT2 % [tname, strip_quotes(cname)]
182
+ data = execute(stmt).first
183
+ if data
184
+ start = data['autoincrementstart']
185
+ if start
186
+ coldef = ""
187
+ coldef << " GENERATED " << (data['columndefault'].nil? ? "ALWAYS" : "BY DEFAULT ")
188
+ coldef << "AS IDENTITY (START WITH "
189
+ coldef << start
190
+ coldef << ", INCREMENT BY "
191
+ coldef << data['autoincrementinc']
192
+ coldef << ")"
193
+ return coldef
194
+ end
195
+ end
196
+ ""
197
+ end
198
+
199
+ def create_column(name, refid, colno)
200
+ stmt = COLUMN_TYPE_STMT % [refid, strip_quotes(name)]
201
+ coldef = ""
202
+ data = execute(stmt).first
203
+ if data
204
+ coldef << add_quotes(expand_double_quotes(strip_quotes(name)))
205
+ coldef << " "
206
+ coldef << data['columndatatype']
207
+ if !reinstate_auto_increment(name, refid, coldef) && data['columndefault']
208
+ coldef << " DEFAULT " << data['columndefault']
209
+ end
210
+ end
211
+ coldef
212
+ end
213
+
214
+ SIZEABLE = %w(VARCHAR CLOB BLOB)
215
+
216
+ def structure_dump #:nodoc:
217
+ definition=""
218
+ rs = @connection.connection.meta_data.getTables(nil,nil,nil,["TABLE"].to_java(:string))
219
+ while rs.next
220
+ tname = rs.getString(3)
221
+ definition << "CREATE TABLE #{tname} (\n"
222
+ rs2 = @connection.connection.meta_data.getColumns(nil,nil,tname,nil)
223
+ first_col = true
224
+ while rs2.next
225
+ col_name = add_quotes(rs2.getString(4));
226
+ default = ""
227
+ d1 = rs2.getString(13)
228
+ if d1 =~ /^GENERATED_/
229
+ default = auto_increment_stmt(tname, col_name)
230
+ elsif d1
231
+ default = " DEFAULT #{d1}"
232
+ end
233
+
234
+ type = rs2.getString(6)
235
+ col_size = rs2.getString(7)
236
+ nulling = (rs2.getString(18) == 'NO' ? " NOT NULL" : "")
237
+ create_col_string = add_quotes(expand_double_quotes(strip_quotes(col_name))) +
238
+ " " +
239
+ type +
240
+ (SIZEABLE.include?(type) ? "(#{col_size})" : "") +
241
+ nulling +
242
+ default
243
+ if !first_col
244
+ create_col_string = ",\n #{create_col_string}"
245
+ else
246
+ create_col_string = " #{create_col_string}"
247
+ end
248
+
249
+ definition << create_col_string
250
+
251
+ first_col = false
252
+ end
253
+ definition << ");\n\n"
254
+ end
255
+ definition
256
+ end
257
+
258
+ # Support for removing columns added via derby bug issue:
259
+ # https://issues.apache.org/jira/browse/DERBY-1489
260
+ #
261
+ # This feature has not made it into a formal release and is not in Java 6.
262
+ # If the normal strategy fails we fall back on a strategy by creating a new
263
+ # table without the new column and there after moving the data to the new
264
+ #
265
+ def remove_column(table_name, column_name)
266
+ begin
267
+ execute "ALTER TABLE #{table_name} DROP COLUMN #{column_name} RESTRICT"
268
+ rescue
269
+ alter_table(table_name) do |definition|
270
+ definition.columns.delete(definition[column_name])
271
+ end
272
+ end
273
+ end
274
+
275
+ # Notes about changing in Derby:
276
+ # http://db.apache.org/derby/docs/10.2/ref/rrefsqlj81859.html#rrefsqlj81859__rrefsqlj37860)
277
+ #
278
+ # We support changing columns using the strategy outlined in:
279
+ # https://issues.apache.org/jira/browse/DERBY-1515
280
+ #
281
+ # This feature has not made it into a formal release and is not in Java 6. We will
282
+ # need to conditionally support this somehow (supposed to arrive for 10.3.0.0)
283
+ def change_column(table_name, column_name, type, options = {})
284
+ # null/not nulling is easy, handle that separately
285
+ if options.include?(:null)
286
+ # This seems to only work with 10.2 of Derby
287
+ if options.delete(:null) == false
288
+ execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} NOT NULL"
289
+ else
290
+ execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} NULL"
291
+ end
292
+ end
293
+
294
+ # anything left to do?
295
+ unless options.empty?
296
+ begin
297
+ execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET DATA TYPE #{type_to_sql(type, options[:limit])}"
298
+ rescue
299
+ transaction do
300
+ temp_new_column_name = "#{column_name}_newtype"
301
+ # 1) ALTER TABLE t ADD COLUMN c1_newtype NEWTYPE;
302
+ add_column table_name, temp_new_column_name, type, options
303
+ # 2) UPDATE t SET c1_newtype = c1;
304
+ execute "UPDATE #{table_name} SET #{temp_new_column_name} = CAST(#{column_name} AS #{type_to_sql(type, options[:limit])})"
305
+ # 3) ALTER TABLE t DROP COLUMN c1;
306
+ remove_column table_name, column_name
307
+ # 4) ALTER TABLE t RENAME COLUMN c1_newtype to c1;
308
+ rename_column table_name, temp_new_column_name, column_name
309
+ end
310
+ end
311
+ end
312
+ end
313
+
314
+ # Support for renaming columns:
315
+ # https://issues.apache.org/jira/browse/DERBY-1490
316
+ #
317
+ # This feature is expect to arrive in version 10.3.0.0:
318
+ # http://wiki.apache.org/db-derby/DerbyTenThreeRelease)
319
+ #
320
+ def rename_column(table_name, column_name, new_column_name) #:nodoc:
321
+ begin
322
+ execute "ALTER TABLE #{table_name} ALTER RENAME COLUMN #{column_name} TO #{new_column_name}"
323
+ rescue
324
+ alter_table(table_name, :rename => {column_name => new_column_name})
325
+ end
326
+ end
327
+
328
+ def primary_keys(table_name)
329
+ @connection.primary_keys table_name.to_s.upcase
330
+ end
331
+
332
+ def recreate_database(db_name)
333
+ tables.each do |t|
334
+ drop_table t
335
+ end
336
+ end
337
+
338
+ # For DDL it appears you can quote "" column names, but in queries (like insert it errors out?)
339
+ def quote_column_name(name) #:nodoc:
340
+ if /^references$/i =~ name
341
+ %Q{"#{name.upcase}"}
342
+ elsif /[A-Z]/ =~ name && /[a-z]/ =~ name
343
+ %Q{"#{name}"}
344
+ elsif name =~ /\s/
345
+ %Q{"#{name.upcase}"}
346
+ elsif name =~ /^[_\d]/
347
+ %Q{"#{name.upcase}"}
348
+ else
349
+ name
350
+ end
351
+ end
352
+
353
+ def quoted_true
354
+ '1'
355
+ end
356
+
357
+ def quoted_false
358
+ '0'
359
+ end
360
+ end
361
+ end
362
+