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