activerecord-jdbc-adapter 0.9.3-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. data/History.txt +248 -0
  2. data/LICENSE.txt +21 -0
  3. data/Manifest.txt +125 -0
  4. data/README.txt +218 -0
  5. data/Rakefile +10 -0
  6. data/lib/active_record/connection_adapters/cachedb_adapter.rb +1 -0
  7. data/lib/active_record/connection_adapters/derby_adapter.rb +13 -0
  8. data/lib/active_record/connection_adapters/h2_adapter.rb +13 -0
  9. data/lib/active_record/connection_adapters/hsqldb_adapter.rb +13 -0
  10. data/lib/active_record/connection_adapters/informix_adapter.rb +1 -0
  11. data/lib/active_record/connection_adapters/jdbc_adapter.rb +640 -0
  12. data/lib/active_record/connection_adapters/jdbc_adapter_spec.rb +26 -0
  13. data/lib/active_record/connection_adapters/jndi_adapter.rb +1 -0
  14. data/lib/active_record/connection_adapters/mysql_adapter.rb +13 -0
  15. data/lib/active_record/connection_adapters/oracle_adapter.rb +1 -0
  16. data/lib/active_record/connection_adapters/postgresql_adapter.rb +13 -0
  17. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +13 -0
  18. data/lib/generators/jdbc/jdbc_generator.rb +9 -0
  19. data/lib/jdbc_adapter.rb +27 -0
  20. data/lib/jdbc_adapter/jdbc.rake +121 -0
  21. data/lib/jdbc_adapter/jdbc_adapter_internal.jar +0 -0
  22. data/lib/jdbc_adapter/jdbc_cachedb.rb +33 -0
  23. data/lib/jdbc_adapter/jdbc_db2.rb +203 -0
  24. data/lib/jdbc_adapter/jdbc_derby.rb +430 -0
  25. data/lib/jdbc_adapter/jdbc_firebird.rb +109 -0
  26. data/lib/jdbc_adapter/jdbc_hsqldb.rb +218 -0
  27. data/lib/jdbc_adapter/jdbc_informix.rb +147 -0
  28. data/lib/jdbc_adapter/jdbc_mimer.rb +141 -0
  29. data/lib/jdbc_adapter/jdbc_mssql.rb +337 -0
  30. data/lib/jdbc_adapter/jdbc_mysql.rb +236 -0
  31. data/lib/jdbc_adapter/jdbc_oracle.rb +377 -0
  32. data/lib/jdbc_adapter/jdbc_postgre.rb +498 -0
  33. data/lib/jdbc_adapter/jdbc_sqlite3.rb +384 -0
  34. data/lib/jdbc_adapter/jdbc_sybase.rb +50 -0
  35. data/lib/jdbc_adapter/missing_functionality_helper.rb +87 -0
  36. data/lib/jdbc_adapter/rake_tasks.rb +10 -0
  37. data/lib/jdbc_adapter/tsql_helper.rb +60 -0
  38. data/lib/jdbc_adapter/version.rb +5 -0
  39. data/lib/pg.rb +4 -0
  40. data/rails_generators/jdbc_generator.rb +15 -0
  41. data/rails_generators/templates/config/initializers/jdbc.rb +7 -0
  42. data/rails_generators/templates/lib/tasks/jdbc.rake +8 -0
  43. data/rakelib/compile.rake +23 -0
  44. data/rakelib/package.rake +90 -0
  45. data/rakelib/rails.rake +41 -0
  46. data/rakelib/test.rake +76 -0
  47. data/src/java/jdbc_adapter/JdbcAdapterInternalService.java +53 -0
  48. data/src/java/jdbc_adapter/JdbcConnectionFactory.java +36 -0
  49. data/src/java/jdbc_adapter/JdbcDerbySpec.java +293 -0
  50. data/src/java/jdbc_adapter/JdbcMySQLSpec.java +134 -0
  51. data/src/java/jdbc_adapter/MssqlRubyJdbcConnection.java +71 -0
  52. data/src/java/jdbc_adapter/PostgresRubyJdbcConnection.java +55 -0
  53. data/src/java/jdbc_adapter/RubyJdbcConnection.java +1162 -0
  54. data/src/java/jdbc_adapter/SQLBlock.java +27 -0
  55. data/src/java/jdbc_adapter/Sqlite3RubyJdbcConnection.java +41 -0
  56. data/test/abstract_db_create.rb +107 -0
  57. data/test/activerecord/connection_adapters/type_conversion_test.rb +31 -0
  58. data/test/activerecord/connections/native_jdbc_mysql/connection.rb +25 -0
  59. data/test/cachedb_simple_test.rb +6 -0
  60. data/test/db/cachedb.rb +9 -0
  61. data/test/db/db2.rb +9 -0
  62. data/test/db/derby.rb +14 -0
  63. data/test/db/h2.rb +11 -0
  64. data/test/db/hsqldb.rb +12 -0
  65. data/test/db/informix.rb +11 -0
  66. data/test/db/jdbc.rb +11 -0
  67. data/test/db/jndi_config.rb +30 -0
  68. data/test/db/logger.rb +3 -0
  69. data/test/db/mssql.rb +9 -0
  70. data/test/db/mysql.rb +10 -0
  71. data/test/db/oracle.rb +34 -0
  72. data/test/db/postgres.rb +9 -0
  73. data/test/db/sqlite3.rb +15 -0
  74. data/test/db2_simple_test.rb +10 -0
  75. data/test/derby_migration_test.rb +21 -0
  76. data/test/derby_multibyte_test.rb +12 -0
  77. data/test/derby_simple_test.rb +21 -0
  78. data/test/generic_jdbc_connection_test.rb +9 -0
  79. data/test/h2_simple_test.rb +6 -0
  80. data/test/has_many_through.rb +79 -0
  81. data/test/helper.rb +5 -0
  82. data/test/hsqldb_simple_test.rb +6 -0
  83. data/test/informix_simple_test.rb +48 -0
  84. data/test/jdbc_adapter/jdbc_db2_test.rb +26 -0
  85. data/test/jdbc_adapter/jdbc_sybase_test.rb +33 -0
  86. data/test/jdbc_common.rb +25 -0
  87. data/test/jndi_callbacks_test.rb +38 -0
  88. data/test/jndi_test.rb +35 -0
  89. data/test/manualTestDatabase.rb +191 -0
  90. data/test/minirunit.rb +109 -0
  91. data/test/minirunit/testConnect.rb +14 -0
  92. data/test/minirunit/testH2.rb +73 -0
  93. data/test/minirunit/testHsqldb.rb +73 -0
  94. data/test/minirunit/testLoadActiveRecord.rb +3 -0
  95. data/test/minirunit/testMysql.rb +83 -0
  96. data/test/minirunit/testRawSelect.rb +24 -0
  97. data/test/models/add_not_null_column_to_table.rb +12 -0
  98. data/test/models/auto_id.rb +18 -0
  99. data/test/models/data_types.rb +28 -0
  100. data/test/models/entry.rb +23 -0
  101. data/test/models/mixed_case.rb +20 -0
  102. data/test/models/reserved_word.rb +18 -0
  103. data/test/models/string_id.rb +18 -0
  104. data/test/models/validates_uniqueness_of_string.rb +19 -0
  105. data/test/mssql_simple_test.rb +6 -0
  106. data/test/mysql_db_create_test.rb +25 -0
  107. data/test/mysql_multibyte_test.rb +10 -0
  108. data/test/mysql_nonstandard_primary_key_test.rb +42 -0
  109. data/test/mysql_simple_test.rb +32 -0
  110. data/test/oracle_simple_test.rb +29 -0
  111. data/test/pick_rails_version.rb +3 -0
  112. data/test/postgres_db_create_test.rb +21 -0
  113. data/test/postgres_mixed_case_test.rb +19 -0
  114. data/test/postgres_nonseq_pkey_test.rb +40 -0
  115. data/test/postgres_reserved_test.rb +22 -0
  116. data/test/postgres_schema_search_path_test.rb +46 -0
  117. data/test/postgres_simple_test.rb +13 -0
  118. data/test/simple.rb +475 -0
  119. data/test/sqlite3_simple_test.rb +233 -0
  120. data/test/sybase_jtds_simple_test.rb +6 -0
  121. metadata +188 -0
@@ -0,0 +1,384 @@
1
+ module ::JdbcSpec
2
+ # Don't need to load native postgres adapter
3
+ $LOADED_FEATURES << "active_record/connection_adapters/sqlite3_adapter.rb"
4
+
5
+ module ActiveRecordExtensions
6
+ add_method_to_remove_from_ar_base(:sqlite3_connection)
7
+
8
+ def sqlite3_connection(config)
9
+ require File.dirname(__FILE__) + "/../active_record/connection_adapters/sqlite3_adapter"
10
+
11
+ parse_sqlite3_config!(config)
12
+
13
+ config[:url] ||= "jdbc:sqlite:#{config[:database]}"
14
+ config[:driver] ||= "org.sqlite.JDBC"
15
+ jdbc_connection(config)
16
+ end
17
+
18
+ def parse_sqlite3_config!(config)
19
+ config[:database] ||= config[:dbfile]
20
+
21
+ # Allow database path relative to RAILS_ROOT, but only if
22
+ # the database path is not the special path that tells
23
+ # Sqlite to build a database only in memory.
24
+ if Object.const_defined?(:RAILS_ROOT) && ':memory:' != config[:database]
25
+ config[:database] = File.expand_path(config[:database], RAILS_ROOT)
26
+ end
27
+ end
28
+ end
29
+
30
+ module SQLite3
31
+ def self.extended(base)
32
+ base.class.class_eval do
33
+ alias_chained_method :insert, :query_dirty, :insert
34
+ end
35
+ end
36
+
37
+ def self.adapter_matcher(name, *)
38
+ name =~ /sqlite/i ? self : false
39
+ end
40
+
41
+ def self.column_selector
42
+ [/sqlite/i, lambda {|cfg,col| col.extend(::JdbcSpec::SQLite3::Column)}]
43
+ end
44
+
45
+ def self.jdbc_connection_class
46
+ ::ActiveRecord::ConnectionAdapters::Sqlite3JdbcConnection
47
+ end
48
+
49
+ module Column
50
+ def init_column(name, default, *args)
51
+ @default = '' if default =~ /NULL/
52
+ end
53
+
54
+ def type_cast(value)
55
+ return nil if value.nil?
56
+ case type
57
+ when :string then value
58
+ when :integer then JdbcSpec::SQLite3::Column.cast_to_integer(value)
59
+ when :primary_key then defined?(value.to_i) ? value.to_i : (value ? 1 : 0)
60
+ when :float then value.to_f
61
+ when :datetime then JdbcSpec::SQLite3::Column.cast_to_date_or_time(value)
62
+ when :date then JdbcSpec::SQLite3::Column.cast_to_date_or_time(value)
63
+ when :time then JdbcSpec::SQLite3::Column.cast_to_time(value)
64
+ when :decimal then self.class.value_to_decimal(value)
65
+ when :boolean then self.class.value_to_boolean(value)
66
+ else value
67
+ end
68
+ end
69
+
70
+ def type_cast_code(var_name)
71
+ case type
72
+ when :integer then "JdbcSpec::SQLite3::Column.cast_to_integer(#{var_name})"
73
+ when :datetime then "JdbcSpec::SQLite3::Column.cast_to_date_or_time(#{var_name})"
74
+ when :date then "JdbcSpec::SQLite3::Column.cast_to_date_or_time(#{var_name})"
75
+ when :time then "JdbcSpec::SQLite3::Column.cast_to_time(#{var_name})"
76
+ else
77
+ super
78
+ end
79
+ end
80
+
81
+ private
82
+ def simplified_type(field_type)
83
+ case field_type
84
+ when /boolean/i then :boolean
85
+ when /text/i then :text
86
+ when /varchar/i then :string
87
+ when /int/i then :integer
88
+ when /float/i then :float
89
+ when /real/i then @scale == 0 ? :integer : :decimal
90
+ when /datetime/i then :datetime
91
+ when /date/i then :date
92
+ when /time/i then :time
93
+ when /blob/i then :binary
94
+ end
95
+ end
96
+
97
+ def extract_precision(sql_type)
98
+ case sql_type
99
+ when /^(real)\((\d+)(,\d+)?\)/i then $2.to_i
100
+ else super
101
+ end
102
+ end
103
+
104
+ def extract_scale(sql_type)
105
+ case sql_type
106
+ when /^(real)\((\d+)\)/i then 0
107
+ when /^(real)\((\d+)(,(\d+))\)/i then $4.to_i
108
+ else super
109
+ end
110
+ end
111
+
112
+ # Post process default value from JDBC into a Rails-friendly format (columns{-internal})
113
+ def default_value(value)
114
+ # jdbc returns column default strings with actual single quotes around the value.
115
+ return $1 if value =~ /^'(.*)'$/
116
+
117
+ value
118
+ end
119
+
120
+ def self.cast_to_integer(value)
121
+ return nil if value =~ /NULL/ or value.to_s.empty? or value.nil?
122
+ return (value.to_i) ? value.to_i : (value ? 1 : 0)
123
+ end
124
+
125
+ def self.cast_to_date_or_time(value)
126
+ return value if value.is_a? Date
127
+ return nil if value.blank?
128
+ guess_date_or_time((value.is_a? Time) ? value : cast_to_time(value))
129
+ end
130
+
131
+ def self.cast_to_time(value)
132
+ return value if value.is_a? Time
133
+ time_array = ParseDate.parsedate value
134
+ time_array[0] ||= 2000; time_array[1] ||= 1; time_array[2] ||= 1;
135
+ Time.send(ActiveRecord::Base.default_timezone, *time_array) rescue nil
136
+ end
137
+
138
+ def self.guess_date_or_time(value)
139
+ (value.hour == 0 and value.min == 0 and value.sec == 0) ?
140
+ Date.new(value.year, value.month, value.day) : value
141
+ end
142
+ end
143
+
144
+ def adapter_name #:nodoc:
145
+ 'SQLite'
146
+ end
147
+
148
+ def supports_count_distinct? #:nodoc:
149
+ sqlite_version >= '3.2.6'
150
+ end
151
+
152
+ def supports_autoincrement? #:nodoc:
153
+ sqlite_version >= '3.1.0'
154
+ end
155
+
156
+ def sqlite_version
157
+ @sqlite_version ||= select_value('select sqlite_version(*)')
158
+ end
159
+
160
+ def modify_types(tp)
161
+ tp[:primary_key] = "INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL"
162
+ tp[:string] = { :name => "VARCHAR", :limit => 255 }
163
+ tp[:float] = { :name => "REAL" }
164
+ tp[:decimal] = { :name => "REAL" }
165
+ tp[:datetime] = { :name => "DATETIME" }
166
+ tp[:timestamp] = { :name => "DATETIME" }
167
+ tp[:time] = { :name => "TIME" }
168
+ tp[:date] = { :name => "DATE" }
169
+ tp[:boolean] = { :name => "BOOLEAN" }
170
+ tp
171
+ end
172
+
173
+ def quote(value, column = nil) # :nodoc:
174
+ return value.quoted_id if value.respond_to?(:quoted_id)
175
+ case value
176
+ when String
177
+ if column && column.type == :binary
178
+ "'#{quote_string(column.class.string_to_binary(value))}'"
179
+ elsif column && [:integer, :float].include?(column.type)
180
+ (column.type == :integer ? value.to_i : value.to_f).to_s
181
+ elsif column && column.respond_to?(:primary) && column.primary && column.klass != String
182
+ value.to_i.to_s
183
+ else
184
+ "'#{quote_string(value)}'"
185
+ end
186
+ else super
187
+ end
188
+ end
189
+
190
+ def quote_column_name(name) #:nodoc:
191
+ name = name.to_s
192
+ # Did not find reference on values needing quoting, but these
193
+ # happen in AR unit tests
194
+ if name == "references" || name =~ /-/
195
+ %Q("#{name}")
196
+ else
197
+ name
198
+ end
199
+ end
200
+
201
+ def quote_string(str)
202
+ str.gsub(/'/, "''")
203
+ end
204
+
205
+ def quoted_true
206
+ %Q{'t'}
207
+ end
208
+
209
+ def quoted_false
210
+ %Q{'f'}
211
+ end
212
+
213
+ def add_column(table_name, column_name, type, options = {})
214
+ if option_not_null = options[:null] == false
215
+ option_not_null = options.delete(:null)
216
+ end
217
+ add_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
218
+ add_column_options!(add_column_sql, options)
219
+ execute(add_column_sql)
220
+ if option_not_null
221
+ alter_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ALTER #{quote_column_name(column_name)} NOT NULL"
222
+ end
223
+ end
224
+
225
+ def remove_column(table_name, *column_names) #:nodoc:
226
+ column_names.flatten.each do |column_name|
227
+ alter_table(table_name) do |definition|
228
+ definition.columns.delete(definition[column_name])
229
+ end
230
+ end
231
+ end
232
+ alias :remove_columns :remove_column
233
+
234
+ def change_column(table_name, column_name, type, options = {}) #:nodoc:
235
+ alter_table(table_name) do |definition|
236
+ include_default = options_include_default?(options)
237
+ definition[column_name].instance_eval do
238
+ self.type = type
239
+ self.limit = options[:limit] if options.include?(:limit)
240
+ self.default = options[:default] if include_default
241
+ self.null = options[:null] if options.include?(:null)
242
+ end
243
+ end
244
+ end
245
+
246
+ def change_column_default(table_name, column_name, default) #:nodoc:
247
+ alter_table(table_name) do |definition|
248
+ definition[column_name].default = default
249
+ end
250
+ end
251
+
252
+ def rename_column(table_name, column_name, new_column_name) #:nodoc:
253
+ unless columns(table_name).detect{|c| c.name == column_name.to_s }
254
+ raise ActiveRecord::ActiveRecordError, "Missing column #{table_name}.#{column_name}"
255
+ end
256
+ alter_table(table_name, :rename => {column_name.to_s => new_column_name.to_s})
257
+ end
258
+
259
+ def rename_table(name, new_name)
260
+ execute "ALTER TABLE #{name} RENAME TO #{new_name}"
261
+ end
262
+
263
+ def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
264
+ log(sql,name) do
265
+ @connection.execute_update(sql)
266
+ end
267
+ table = sql.split(" ", 4)[2]
268
+ id_value || last_insert_id(table, nil)
269
+ end
270
+
271
+ def last_insert_id(table, sequence_name)
272
+ Integer(select_value("SELECT SEQ FROM SQLITE_SEQUENCE WHERE NAME = '#{table}'"))
273
+ end
274
+
275
+ def add_limit_offset!(sql, options) #:nodoc:
276
+ if options[:limit]
277
+ sql << " LIMIT #{options[:limit]}"
278
+ sql << " OFFSET #{options[:offset]}" if options[:offset]
279
+ end
280
+ end
281
+
282
+ def tables(name = nil) #:nodoc:
283
+ sql = <<-SQL
284
+ SELECT name
285
+ FROM sqlite_master
286
+ WHERE type = 'table' AND NOT name = 'sqlite_sequence'
287
+ SQL
288
+
289
+ select_rows(sql, name).map do |row|
290
+ row[0]
291
+ end
292
+ end
293
+
294
+ def remove_index(table_name, options = {})
295
+ execute "DROP INDEX #{quote_column_name(index_name(table_name, options))}"
296
+ end
297
+
298
+ def indexes(table_name, name = nil)
299
+ result = select_rows("SELECT name, sql FROM sqlite_master WHERE tbl_name = '#{table_name}' AND type = 'index'", name)
300
+
301
+ result.collect do |row|
302
+ name = row[0]
303
+ index_sql = row[1]
304
+ unique = (index_sql =~ /unique/i)
305
+ cols = index_sql.match(/\((.*)\)/)[1].gsub(/,/,' ').split
306
+ ::ActiveRecord::ConnectionAdapters::IndexDefinition.new(table_name, name, unique, cols)
307
+ end
308
+ end
309
+
310
+ def primary_key(table_name) #:nodoc:
311
+ column = table_structure(table_name).find {|field| field['pk'].to_i == 1}
312
+ column ? column['name'] : nil
313
+ end
314
+
315
+ def recreate_database(name)
316
+ tables.each{ |table| drop_table(table) }
317
+ end
318
+
319
+ def _execute(sql, name = nil)
320
+ if ActiveRecord::ConnectionAdapters::JdbcConnection::select?(sql)
321
+ @connection.execute_query(sql)
322
+ else
323
+ affected_rows = @connection.execute_update(sql)
324
+ ActiveRecord::ConnectionAdapters::JdbcConnection::insert?(sql) ? last_insert_id(sql.split(" ", 4)[2], nil) : affected_rows
325
+ end
326
+ end
327
+
328
+ def select(sql, name=nil)
329
+ execute(sql, name).map do |row|
330
+ record = {}
331
+ row.each_key do |key|
332
+ if key.is_a?(String)
333
+ record[key.sub(/^"?\w+"?\./, '')] = row[key]
334
+ end
335
+ end
336
+ record
337
+ end
338
+ end
339
+
340
+ def table_structure(table_name)
341
+ structure = @connection.execute_query("PRAGMA table_info(#{quote_table_name(table_name)})")
342
+ raise ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'" if structure.empty?
343
+ structure
344
+ end
345
+
346
+ def columns(table_name, name = nil) #:nodoc:
347
+ table_structure(table_name).map do |field|
348
+ ::ActiveRecord::ConnectionAdapters::JdbcColumn.new(@config, field['name'], field['dflt_value'], field['type'], field['notnull'] == 0)
349
+ end
350
+ end
351
+
352
+ # SELECT ... FOR UPDATE is redundant since the table is locked.
353
+ def add_lock!(sql, options) #:nodoc:
354
+ sql
355
+ end
356
+
357
+ protected
358
+ include JdbcSpec::MissingFunctionalityHelper
359
+ end
360
+ end
361
+
362
+ module ActiveRecord
363
+ module ConnectionAdapters
364
+ class JdbcColumn < Column
365
+ def self.string_to_binary(value)
366
+ value.gsub(/\0|%/n) do |b|
367
+ case b
368
+ when "\0" then "%00"
369
+ when "\%" then "%25"
370
+ end
371
+ end
372
+ end
373
+
374
+ def self.binary_to_string(value)
375
+ value.gsub(/%00|%25/n) do |b|
376
+ case b
377
+ when "%00" then "\0"
378
+ when "%25" then "%"
379
+ end
380
+ end
381
+ end
382
+ end
383
+ end
384
+ end
@@ -0,0 +1,50 @@
1
+ module JdbcSpec
2
+ module Sybase
3
+ def self.adapter_matcher(name, *)
4
+ name =~ /sybase|tds/i ? self : false
5
+ end
6
+
7
+ def add_limit_offset!(sql, options) # :nodoc:
8
+ @limit = options[:limit]
9
+ @offset = options[:offset]
10
+ if use_temp_table?
11
+ # Use temp table to hack offset with Sybase
12
+ sql.sub!(/ FROM /i, ' INTO #artemp FROM ')
13
+ elsif zero_limit?
14
+ # "SET ROWCOUNT 0" turns off limits, so we havesy
15
+ # to use a cheap trick.
16
+ if sql =~ /WHERE/i
17
+ sql.sub!(/WHERE/i, 'WHERE 1 = 2 AND ')
18
+ elsif sql =~ /ORDER\s+BY/i
19
+ sql.sub!(/ORDER\s+BY/i, 'WHERE 1 = 2 ORDER BY')
20
+ else
21
+ sql << 'WHERE 1 = 2'
22
+ end
23
+ end
24
+ end
25
+
26
+ # If limit is not set at all, we can ignore offset;
27
+ # if limit *is* set but offset is zero, use normal select
28
+ # with simple SET ROWCOUNT. Thus, only use the temp table
29
+ # if limit is set and offset > 0.
30
+ def use_temp_table?
31
+ !@limit.nil? && !@offset.nil? && @offset > 0
32
+ end
33
+
34
+ def zero_limit?
35
+ !@limit.nil? && @limit == 0
36
+ end
37
+
38
+ def modify_types(tp) #:nodoc:
39
+ tp[:primary_key] = "NUMERIC(22,0) IDENTITY PRIMARY KEY"
40
+ tp[:integer][:limit] = nil
41
+ tp[:boolean] = {:name => "bit"}
42
+ tp[:binary] = {:name => "image"}
43
+ tp
44
+ end
45
+
46
+ def remove_index(table_name, options = {})
47
+ execute "DROP INDEX #{table_name}.#{index_name(table_name, options)}"
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,87 @@
1
+ module JdbcSpec
2
+ module MissingFunctionalityHelper
3
+ #Taken from SQLite adapter
4
+
5
+ def alter_table(table_name, options = {}) #:nodoc:
6
+ table_name = table_name.to_s.downcase
7
+ altered_table_name = "altered_#{table_name}"
8
+ caller = lambda {|definition| yield definition if block_given?}
9
+
10
+ transaction do
11
+ # A temporary table might improve performance here, but
12
+ # it doesn't seem to maintain indices across the whole move.
13
+ move_table(table_name, altered_table_name,
14
+ options)
15
+ move_table(altered_table_name, table_name, &caller)
16
+ end
17
+ end
18
+
19
+ def move_table(from, to, options = {}, &block) #:nodoc:
20
+ copy_table(from, to, options, &block)
21
+ drop_table(from)
22
+ end
23
+
24
+ def copy_table(from, to, options = {}) #:nodoc:
25
+ options = options.merge(:id => (!columns(from).detect{|c| c.name == 'id'}.nil? && 'id' == primary_key(from).to_s))
26
+ create_table(to, options) do |definition|
27
+ @definition = definition
28
+ columns(from).each do |column|
29
+ column_name = options[:rename] ?
30
+ (options[:rename][column.name] ||
31
+ options[:rename][column.name.to_sym] ||
32
+ column.name) : column.name
33
+
34
+ @definition.column(column_name, column.type,
35
+ :limit => column.limit, :default => column.default,
36
+ :null => column.null)
37
+ end
38
+ @definition.primary_key(primary_key(from)) if primary_key(from)
39
+ yield @definition if block_given?
40
+ end
41
+
42
+ copy_table_indexes(from, to, options[:rename] || {})
43
+ copy_table_contents(from, to,
44
+ @definition.columns.map {|column| column.name},
45
+ options[:rename] || {})
46
+ end
47
+
48
+ def copy_table_indexes(from, to, rename = {}) #:nodoc:
49
+ indexes(from).each do |index|
50
+ name = index.name.downcase
51
+ if to == "altered_#{from}"
52
+ name = "temp_#{name}"
53
+ elsif from == "altered_#{to}"
54
+ name = name[5..-1]
55
+ end
56
+
57
+ to_column_names = columns(to).map(&:name)
58
+ columns = index.columns.map {|c| rename[c] || c }.select do |column|
59
+ to_column_names.include?(column)
60
+ end
61
+
62
+ unless columns.empty?
63
+ # index name can't be the same
64
+ opts = { :name => name.gsub(/(_?)(#{from})_/, "\\1#{to}_") }
65
+ opts[:unique] = true if index.unique
66
+ add_index(to, columns, opts)
67
+ end
68
+ end
69
+ end
70
+
71
+ def copy_table_contents(from, to, columns, rename = {}) #:nodoc:
72
+ column_mappings = Hash[*columns.map {|name| [name, name]}.flatten]
73
+ rename.inject(column_mappings) {|map, a| map[a.last] = a.first; map}
74
+ from_columns = columns(from).collect {|col| col.name}
75
+ columns = columns.find_all{|col| from_columns.include?(column_mappings[col])}
76
+ quoted_columns = columns.map { |col| quote_column_name(col) } * ','
77
+
78
+ quoted_to = quote_table_name(to)
79
+ execute("SELECT * FROM #{quote_table_name(from)}").each do |row|
80
+ sql = "INSERT INTO #{quoted_to} (#{quoted_columns}) VALUES ("
81
+ sql << columns.map {|col| quote row[column_mappings[col]]} * ', '
82
+ sql << ')'
83
+ execute sql
84
+ end
85
+ end
86
+ end
87
+ end