activerecord-jdbc-adapter 0.9.1 → 0.9.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.
Files changed (52) hide show
  1. data/History.txt +33 -0
  2. data/Manifest.txt +17 -0
  3. data/README.txt +48 -20
  4. data/Rakefile +2 -169
  5. data/lib/active_record/connection_adapters/jdbc_adapter.rb +11 -5
  6. data/lib/active_record/connection_adapters/jdbc_adapter_spec.rb +12 -0
  7. data/lib/jdbc_adapter.rb +1 -1
  8. data/lib/jdbc_adapter/jdbc.rake +43 -30
  9. data/lib/jdbc_adapter/jdbc_adapter_internal.jar +0 -0
  10. data/lib/jdbc_adapter/jdbc_db2.rb +2 -2
  11. data/lib/jdbc_adapter/jdbc_derby.rb +11 -0
  12. data/lib/jdbc_adapter/jdbc_hsqldb.rb +6 -1
  13. data/lib/jdbc_adapter/jdbc_mimer.rb +14 -7
  14. data/lib/jdbc_adapter/jdbc_mssql.rb +18 -2
  15. data/lib/jdbc_adapter/jdbc_mysql.rb +3 -0
  16. data/lib/jdbc_adapter/jdbc_oracle.rb +24 -14
  17. data/lib/jdbc_adapter/jdbc_postgre.rb +38 -18
  18. data/lib/jdbc_adapter/jdbc_sqlite3.rb +96 -26
  19. data/lib/jdbc_adapter/missing_functionality_helper.rb +40 -34
  20. data/lib/jdbc_adapter/rake_tasks.rb +1 -1
  21. data/lib/jdbc_adapter/tsql_helper.rb +1 -0
  22. data/lib/jdbc_adapter/version.rb +1 -1
  23. data/lib/pg.rb +4 -0
  24. data/rails_generators/jdbc_generator.rb +15 -0
  25. data/rails_generators/templates/jdbc.rake +8 -0
  26. data/rails_generators/templates/jdbc.rb +7 -0
  27. data/rakelib/compile.rake +23 -0
  28. data/rakelib/package.rake +85 -0
  29. data/rakelib/rails.rake +41 -0
  30. data/rakelib/test.rake +71 -0
  31. data/src/java/jdbc_adapter/JdbcAdapterInternalService.java +1 -0
  32. data/src/java/jdbc_adapter/JdbcDerbySpec.java +11 -46
  33. data/src/java/jdbc_adapter/JdbcMySQLSpec.java +3 -2
  34. data/src/java/jdbc_adapter/MssqlRubyJdbcConnection.java +71 -0
  35. data/src/java/jdbc_adapter/PostgresRubyJdbcConnection.java +24 -4
  36. data/src/java/jdbc_adapter/RubyJdbcConnection.java +57 -44
  37. data/test/abstract_db_create.rb +45 -0
  38. data/test/db/mysql.rb +2 -2
  39. data/test/db/postgres.rb +2 -2
  40. data/test/helper.rb +5 -0
  41. data/test/jdbc_adapter/jdbc_db2_test.rb +5 -0
  42. data/test/jdbc_common.rb +2 -0
  43. data/test/models/entry.rb +3 -0
  44. data/test/models/validates_uniqueness_of_string.rb +19 -0
  45. data/test/mysql_db_create_test.rb +25 -0
  46. data/test/mysql_nonstandard_primary_key_test.rb +42 -0
  47. data/test/mysql_simple_test.rb +5 -0
  48. data/test/postgres_db_create_test.rb +21 -0
  49. data/test/postgres_nonseq_pkey_test.rb +40 -0
  50. data/test/simple.rb +62 -1
  51. data/test/sqlite3_simple_test.rb +153 -10
  52. metadata +26 -5
@@ -2,7 +2,7 @@ module JdbcSpec
2
2
  module DB2
3
3
  def self.adapter_matcher(name, config)
4
4
  if name =~ /db2/i
5
- return cfg[:url] =~ /^jdbc:derby:net:/ ? ::JdbcSpec::Derby : self
5
+ return config[:url] =~ /^jdbc:derby:net:/ ? ::JdbcSpec::Derby : self
6
6
  end
7
7
  false
8
8
  end
@@ -50,7 +50,7 @@ module JdbcSpec
50
50
  end
51
51
 
52
52
  def modify_types(tp)
53
- tp[:primary_key] = 'int generated by default as identity (start with 42) primary key'
53
+ tp[:primary_key] = 'int not null generated by default as identity (start with 1) primary key'
54
54
  tp[:string][:limit] = 255
55
55
  tp[:integer][:limit] = nil
56
56
  tp[:boolean][:limit] = nil
@@ -3,6 +3,7 @@ require 'jdbc_adapter/missing_functionality_helper'
3
3
  module ::JdbcSpec
4
4
  module ActiveRecordExtensions
5
5
  def derby_connection(config)
6
+ require File.dirname(__FILE__) + "/../active_record/connection_adapters/derby_adapter"
6
7
  config[:url] ||= "jdbc:derby:#{config[:database]};create=true"
7
8
  config[:driver] ||= "org.apache.derby.jdbc.EmbeddedDriver"
8
9
  embedded_driver(config)
@@ -400,6 +401,16 @@ module ::JdbcSpec
400
401
  '0'
401
402
  end
402
403
 
404
+ def add_limit_offset!(sql, options) #:nodoc:
405
+ if options[:offset]
406
+ sql << " OFFSET #{options[:offset]} ROWS"
407
+ end
408
+ if options[:limit]
409
+ #ROWS/ROW and FIRST/NEXT mean the same
410
+ sql << " FETCH FIRST #{options[:limit]} ROWS ONLY"
411
+ end
412
+ end
413
+
403
414
  private
404
415
  # Derby appears to define schemas using the username
405
416
  def derby_schema
@@ -1,12 +1,14 @@
1
1
  module ::JdbcSpec
2
2
  module ActiveRecordExtensions
3
3
  def hsqldb_connection(config)
4
+ require File.dirname(__FILE__) + "/../active_record/connection_adapters/hsqldb_adapter"
4
5
  config[:url] ||= "jdbc:hsqldb:#{config[:database]}"
5
6
  config[:driver] ||= "org.hsqldb.jdbcDriver"
6
7
  embedded_driver(config)
7
8
  end
8
9
 
9
10
  def h2_connection(config)
11
+ require File.dirname(__FILE__) + "/../active_record/connection_adapters/h2_adapter"
10
12
  config[:url] ||= "jdbc:h2:#{config[:database]}"
11
13
  config[:driver] ||= "org.h2.Driver"
12
14
  embedded_driver(config)
@@ -82,10 +84,13 @@ module ::JdbcSpec
82
84
  "''"
83
85
  elsif column && column.type == :binary
84
86
  "'#{value.unpack("H*")}'"
87
+ elsif column.respond_to?(:primary) && column.primary
88
+ value.to_i.to_s
85
89
  else
86
90
  "'#{quote_string(value)}'"
87
91
  end
88
- else super
92
+ else
93
+ super
89
94
  end
90
95
  end
91
96
 
@@ -73,13 +73,20 @@ module JdbcSpec
73
73
  return "X'#{quote_string(value.unpack("C*").collect {|v| v.to_s(16)}.join)}'"
74
74
  end
75
75
  case value
76
- when String : %Q{'#{quote_string(value)}'}
77
- when NilClass : 'NULL'
78
- when TrueClass : '1'
79
- when FalseClass : '0'
80
- when Numeric : value.to_s
81
- when Date, Time : %Q{TIMESTAMP '#{value.strftime("%Y-%m-%d %H:%M:%S")}'}
82
- else %Q{'#{quote_string(value.to_yaml)}'}
76
+ when String
77
+ %Q{'#{quote_string(value)}'}
78
+ when NilClass
79
+ 'NULL'
80
+ when TrueClass
81
+ '1'
82
+ when FalseClass
83
+ '0'
84
+ when Numeric
85
+ value.to_s
86
+ when Date, Time
87
+ %Q{TIMESTAMP '#{value.strftime("%Y-%m-%d %H:%M:%S")}'}
88
+ else
89
+ %Q{'#{quote_string(value.to_yaml)}'}
83
90
  end
84
91
  end
85
92
 
@@ -31,6 +31,10 @@ module ::JdbcSpec
31
31
  [/sqlserver|tds/i, lambda {|cfg,col| col.extend(::JdbcSpec::MsSQL::Column)}]
32
32
  end
33
33
 
34
+ def self.jdbc_connection_class
35
+ ::ActiveRecord::ConnectionAdapters::MssqlJdbcConnection
36
+ end
37
+
34
38
  module Column
35
39
  attr_accessor :identity, :is_special
36
40
 
@@ -69,7 +73,7 @@ module ::JdbcSpec
69
73
 
70
74
  # JRUBY-2011: Match balanced quotes and parenthesis - 'text',('text') or (text)
71
75
  def unquote_string(value)
72
- value.sub(/^\((.*)\)$/,'\1').sub(/^'(.*)'$/,'\1')
76
+ value.to_s.sub(/^\((.*)\)$/,'\1').sub(/^'(.*)'$/,'\1')
73
77
  end
74
78
 
75
79
  def unquote(value)
@@ -116,7 +120,7 @@ module ::JdbcSpec
116
120
  value = column.type == :integer ? value.to_i : value.to_f
117
121
  value.to_s
118
122
  else
119
- "'#{quote_string(value)}'" # ' (for ruby-mode)
123
+ "N'#{quote_string(value)}'" # ' (for ruby-mode)
120
124
  end
121
125
  when TrueClass then '1'
122
126
  when FalseClass then '0'
@@ -138,6 +142,14 @@ module ::JdbcSpec
138
142
  "[#{name}]"
139
143
  end
140
144
 
145
+ def quoted_true
146
+ quote true
147
+ end
148
+
149
+ def quoted_false
150
+ quote false
151
+ end
152
+
141
153
  def change_order_direction(order)
142
154
  order.split(",").collect {|fragment|
143
155
  case fragment
@@ -249,6 +261,10 @@ module ::JdbcSpec
249
261
  end
250
262
  end
251
263
 
264
+ #SELECT .. FOR UPDATE is not supported on Microsoft SQL Server
265
+ def add_lock!(sql, options)
266
+ sql
267
+ end
252
268
 
253
269
  private
254
270
  # Turns IDENTITY_INSERT ON for table during execution of the block
@@ -5,7 +5,10 @@ module ::JdbcSpec
5
5
  $LOADED_FEATURES << "active_record/connection_adapters/mysql_adapter.rb"
6
6
 
7
7
  module ActiveRecordExtensions
8
+ add_method_to_remove_from_ar_base(:mysql_connection)
9
+
8
10
  def mysql_connection(config)
11
+ require File.dirname(__FILE__) + "/../active_record/connection_adapters/mysql_adapter"
9
12
  config[:port] ||= 3306
10
13
  url_options = "zeroDateTimeBehavior=convertToNull&jdbcCompliantTruncation=false&useUnicode=true&characterEncoding="
11
14
  url_options << (config[:encoding] || 'utf8')
@@ -26,6 +26,9 @@ module ::JdbcSpec
26
26
  ActiveRecord::Base.after_save :after_save_with_oracle_lob
27
27
  @lob_callback_added = true
28
28
  end
29
+ mod.class_eval do
30
+ alias_chained_method :insert, :query_dirty, :jdbc_oracle_insert
31
+ end
29
32
  end
30
33
 
31
34
  def self.adapter_matcher(name, *)
@@ -67,14 +70,14 @@ module ::JdbcSpec
67
70
  private
68
71
  def simplified_type(field_type)
69
72
  case field_type
70
- when /^number\(1\)$/i : :boolean
71
- when /char/i : :string
72
- when /float|double/i : :float
73
- when /int/i : :integer
74
- when /num|dec|real/i : @scale == 0 ? :integer : :decimal
75
- when /date|time/i : :datetime
76
- when /clob/i : :text
77
- when /blob/i : :binary
73
+ when /^number\(1\)$/i then :boolean
74
+ when /char/i then :string
75
+ when /float|double/i then :float
76
+ when /int/i then :integer
77
+ when /num|dec|real/i then @scale == 0 ? :integer : :decimal
78
+ when /date|time/i then :datetime
79
+ when /clob/i then :text
80
+ when /blob/i then :binary
78
81
  end
79
82
  end
80
83
 
@@ -87,6 +90,9 @@ module ::JdbcSpec
87
90
 
88
91
  return nil if value == "null"
89
92
 
93
+ # sysdate default should be treated like a null value
94
+ return nil if value.downcase == "sysdate"
95
+
90
96
  # jdbc returns column default strings with actual single quotes around the value.
91
97
  return $1 if value =~ /^'(.*)'$/
92
98
 
@@ -132,8 +138,8 @@ module ::JdbcSpec
132
138
  recreate_database(name)
133
139
  end
134
140
 
135
- def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
136
- if id_value # Pre-assigned id
141
+ def jdbc_oracle_insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
142
+ if id_value || pk.nil? # Pre-assigned id or table without a primary key
137
143
  execute sql, name
138
144
  else # Assume the sql contains a bind-variable for the id
139
145
  # Extract the table from the insert sql. Yuck.
@@ -153,7 +159,7 @@ module ::JdbcSpec
153
159
 
154
160
  def _execute(sql, name = nil)
155
161
  case sql.strip
156
- when /\A\(?\s*(select|show)/i:
162
+ when /\A\(?\s*(select|show)/i then
157
163
  @connection.execute_query(sql)
158
164
  else
159
165
  @connection.execute_update(sql)
@@ -308,13 +314,13 @@ module ::JdbcSpec
308
314
  # see: abstract/quoting.rb
309
315
 
310
316
  # Camelcase column names need to be quoted.
311
- # Nonquoted identifiers can contain only alphanumeric characters from your
317
+ # Nonquoted identifiers can contain only alphanumeric characters from your
312
318
  # database character set and the underscore (_), dollar sign ($), and pound sign (#).
313
319
  # Database links can also contain periods (.) and "at" signs (@).
314
320
  # Oracle strongly discourages you from using $ and # in nonquoted identifiers.
315
321
  # Source: http://download.oracle.com/docs/cd/B28359_01/server.111/b28286/sql_elements008.htm
316
322
  def quote_column_name(name) #:nodoc:
317
- name.to_s =~ /^[a-z_$#]+$/ ? name.to_s : "\"#{name}\""
323
+ name.to_s =~ /^[a-z0-9_$#]+$/ ? name.to_s : "\"#{name}\""
318
324
  end
319
325
 
320
326
  def quote_string(string) #:nodoc:
@@ -329,6 +335,9 @@ module ::JdbcSpec
329
335
  %Q{empty_#{ column.sql_type.downcase rescue 'blob' }()}
330
336
  end
331
337
  else
338
+ if column.respond_to?(:primary) && column.primary
339
+ return value.to_i.to_s
340
+ end
332
341
  quoted = super
333
342
  if value.acts_like?(:date) || value.acts_like?(:time)
334
343
  quoted = "#{quoted_date(value)}"
@@ -353,7 +362,7 @@ module ::JdbcSpec
353
362
  # In Oracle, schemas are created under your username:
354
363
  # http://www.oracle.com/technology/obe/2day_dba/schema/schema.htm
355
364
  def oracle_schema
356
- @config[:username].to_s
365
+ @config[:username].to_s if @config[:username]
357
366
  end
358
367
 
359
368
  def select(sql, name=nil)
@@ -365,3 +374,4 @@ module ::JdbcSpec
365
374
  end
366
375
  end
367
376
  end
377
+
@@ -4,7 +4,10 @@ module ::JdbcSpec
4
4
  $LOADED_FEATURES << "active_record/connection_adapters/postgresql_adapter.rb"
5
5
 
6
6
  module ActiveRecordExtensions
7
+ add_method_to_remove_from_ar_base(:postgresql_connection)
8
+
7
9
  def postgresql_connection(config)
10
+ require File.dirname(__FILE__) + "/../active_record/connection_adapters/postgresql_adapter"
8
11
  config[:host] ||= "localhost"
9
12
  config[:port] ||= 5432
10
13
  config[:url] ||= "jdbc:postgresql://#{config[:host]}:#{config[:port]}/#{config[:database]}"
@@ -87,10 +90,12 @@ module ::JdbcSpec
87
90
  def postgresql_version
88
91
  @postgresql_version ||=
89
92
  begin
90
- select('SELECT version()').to_a[0][0] =~ /PostgreSQL (\d+)\.(\d+)\.(\d+)/
91
- ($1.to_i * 10000) + ($2.to_i * 100) + $3.to_i
92
- rescue
93
- 0
93
+ value = select_value('SELECT version()')
94
+ if value =~ /PostgreSQL (\d+)\.(\d+)\.(\d+)/
95
+ ($1.to_i * 10000) + ($2.to_i * 100) + $3.to_i
96
+ else
97
+ 0
98
+ end
94
99
  end
95
100
  end
96
101
 
@@ -217,28 +222,36 @@ module ::JdbcSpec
217
222
  table = sql.split(" ", 4)[2].gsub('"', '')
218
223
 
219
224
  # Try an insert with 'returning id' if available (PG >= 8.2)
220
- if supports_insert_with_returning?
225
+ if supports_insert_with_returning? && id_value.nil? && false # FIXME:
226
+ # Disabled, as it causes:
227
+ # ActiveRecord::ActiveRecordError: A result was returned when none was expected
228
+ # This was previously disabled because postgresql_version returned 0
221
229
  pk, sequence_name = *pk_and_sequence_for(table) unless pk
222
230
  if pk
223
- id = select_value("#{sql} RETURNING #{quote_column_name(pk)}")
224
- clear_query_cache
225
- return id
231
+ id_value = select_value("#{sql} RETURNING #{quote_column_name(pk)}")
232
+ clear_query_cache #FIXME: Why now?
233
+ return id_value
226
234
  end
227
235
  end
228
236
 
229
- # Otherwise, insert then grab last_insert_id.
237
+ # Otherwise, plain insert
230
238
  execute(sql, name)
231
239
 
232
- # If neither pk nor sequence name is given, look them up.
233
- unless pk || sequence_name
234
- pk, sequence_name = *pk_and_sequence_for(table)
235
- end
240
+ # Don't need to look up id_value if we already have it.
241
+ # (and can't in case of non-sequence PK)
242
+ unless id_value
243
+ # If neither pk nor sequence name is given, look them up.
244
+ unless pk || sequence_name
245
+ pk, sequence_name = *pk_and_sequence_for(table)
246
+ end
236
247
 
237
- # If a pk is given, fallback to default sequence name.
238
- # Don't fetch last insert id for a table without a pk.
239
- if pk && sequence_name ||= default_sequence_name(table, pk)
240
- last_insert_id(table, sequence_name)
248
+ # If a pk is given, fallback to default sequence name.
249
+ # Don't fetch last insert id for a table without a pk.
250
+ if pk && sequence_name ||= default_sequence_name(table, pk)
251
+ id_value = last_insert_id(table, sequence_name)
252
+ end
241
253
  end
254
+ id_value
242
255
  end
243
256
 
244
257
  def columns(table_name, name=nil)
@@ -332,7 +345,7 @@ module ::JdbcSpec
332
345
 
333
346
  def _execute(sql, name = nil)
334
347
  case sql.strip
335
- when /\A\(?\s*(select|show)/i:
348
+ when /\A\(?\s*(select|show)/i then
336
349
  @connection.execute_query(sql)
337
350
  else
338
351
  @connection.execute_update(sql)
@@ -445,6 +458,13 @@ module ::JdbcSpec
445
458
  execute "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} SET DEFAULT '#{default}'"
446
459
  end
447
460
 
461
+ def change_column_null(table_name, column_name, null, default = nil)
462
+ unless null || default.nil?
463
+ execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
464
+ end
465
+ execute("ALTER TABLE #{quote_table_name(table_name)} ALTER #{quote_column_name(column_name)} #{null ? 'DROP' : 'SET'} NOT NULL")
466
+ end
467
+
448
468
  def rename_column(table_name, column_name, new_column_name) #:nodoc:
449
469
  execute "ALTER TABLE #{quote_table_name(table_name)} RENAME COLUMN #{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}"
450
470
  end
@@ -1,6 +1,13 @@
1
1
  module ::JdbcSpec
2
+ # Don't need to load native postgres adapter
3
+ $LOADED_FEATURES << "active_record/connection_adapters/sqlite3_adapter.rb"
4
+
2
5
  module ActiveRecordExtensions
6
+ add_method_to_remove_from_ar_base(:sqlite3_connection)
7
+
3
8
  def sqlite3_connection(config)
9
+ require File.dirname(__FILE__) + "/../active_record/connection_adapters/sqlite3_adapter"
10
+
4
11
  parse_sqlite3_config!(config)
5
12
 
6
13
  config[:url] ||= "jdbc:sqlite:#{config[:database]}"
@@ -34,12 +41,15 @@ module ::JdbcSpec
34
41
  end
35
42
 
36
43
  module Column
44
+ def init_column(name, default, *args)
45
+ @default = '' if default =~ /NULL/
46
+ end
37
47
 
38
48
  def type_cast(value)
39
49
  return nil if value.nil?
40
50
  case type
41
51
  when :string then value
42
- when :integer then defined?(value.to_i) ? value.to_i : (value ? 1 : 0)
52
+ when :integer then JdbcSpec::SQLite3::Column.cast_to_integer(value)
43
53
  when :primary_key then defined?(value.to_i) ? value.to_i : (value ? 1 : 0)
44
54
  when :float then value.to_f
45
55
  when :datetime then JdbcSpec::SQLite3::Column.cast_to_date_or_time(value)
@@ -51,11 +61,23 @@ module ::JdbcSpec
51
61
  end
52
62
  end
53
63
 
64
+ def type_cast_code(var_name)
65
+ case type
66
+ when :integer then "JdbcSpec::SQLite3::Column.cast_to_integer(#{var_name})"
67
+ when :datetime then "JdbcSpec::SQLite3::Column.cast_to_date_or_time(#{var_name})"
68
+ when :date then "JdbcSpec::SQLite3::Column.cast_to_date_or_time(#{var_name})"
69
+ when :time then "JdbcSpec::SQLite3::Column.cast_to_time(#{var_name})"
70
+ else
71
+ super
72
+ end
73
+ end
74
+
54
75
  private
55
76
  def simplified_type(field_type)
56
77
  case field_type
57
78
  when /boolean/i then :boolean
58
- when /text/i then :string
79
+ when /text/i then :text
80
+ when /varchar/i then :string
59
81
  when /int/i then :integer
60
82
  when /float/i then :float
61
83
  when /real/i then @scale == 0 ? :integer : :decimal
@@ -89,6 +111,11 @@ module ::JdbcSpec
89
111
  value
90
112
  end
91
113
 
114
+ def self.cast_to_integer(value)
115
+ return nil if value =~ /NULL/ or value.to_s.empty? or value.nil?
116
+ return (value.to_i) ? value.to_i : (value ? 1 : 0)
117
+ end
118
+
92
119
  def self.cast_to_date_or_time(value)
93
120
  return value if value.is_a? Date
94
121
  return nil if value.blank?
@@ -125,7 +152,8 @@ module ::JdbcSpec
125
152
  end
126
153
 
127
154
  def modify_types(tp)
128
- tp[:primary_key] = "INTEGER PRIMARY KEY AUTOINCREMENT"
155
+ tp[:primary_key] = "INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL"
156
+ tp[:string] = { :name => "VARCHAR", :limit => 255 }
129
157
  tp[:float] = { :name => "REAL" }
130
158
  tp[:decimal] = { :name => "REAL" }
131
159
  tp[:datetime] = { :name => "DATETIME" }
@@ -142,6 +170,10 @@ module ::JdbcSpec
142
170
  when String
143
171
  if column && column.type == :binary
144
172
  "'#{quote_string(column.class.string_to_binary(value))}'"
173
+ elsif column && [:integer, :float].include?(column.type)
174
+ (column.type == :integer ? value.to_i : value.to_f).to_s
175
+ elsif column && column.respond_to?(:primary) && column.primary
176
+ value.to_i.to_s
145
177
  else
146
178
  "'#{quote_string(value)}'"
147
179
  end
@@ -184,34 +216,38 @@ module ::JdbcSpec
184
216
  end
185
217
  end
186
218
 
187
- def remove_column(table_name, column_name) #:nodoc:
188
- cols = columns(table_name).collect {|col| col.name}
189
- cols.delete(column_name)
190
- cols = cols.join(', ')
191
- table_backup = table_name + "_backup"
192
-
193
- @connection.begin
194
-
195
- execute "CREATE TEMPORARY TABLE #{table_backup}(#{cols})"
196
- insert "INSERT INTO #{table_backup} SELECT #{cols} FROM #{table_name}"
197
- execute "DROP TABLE #{table_name}"
198
- execute "CREATE TABLE #{table_name}(#{cols})"
199
- insert "INSERT INTO #{table_name} SELECT #{cols} FROM #{table_backup}"
200
- execute "DROP TABLE #{table_backup}"
201
-
202
- @connection.commit
219
+ def remove_column(table_name, *column_names) #:nodoc:
220
+ column_names.flatten.each do |column_name|
221
+ alter_table(table_name) do |definition|
222
+ definition.columns.delete(definition[column_name])
223
+ end
224
+ end
203
225
  end
226
+ alias :remove_columns :remove_column
204
227
 
205
228
  def change_column(table_name, column_name, type, options = {}) #:nodoc:
206
- execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} #{type_to_sql(type, options[:limit])}"
229
+ alter_table(table_name) do |definition|
230
+ include_default = options_include_default?(options)
231
+ definition[column_name].instance_eval do
232
+ self.type = type
233
+ self.limit = options[:limit] if options.include?(:limit)
234
+ self.default = options[:default] if include_default
235
+ self.null = options[:null] if options.include?(:null)
236
+ end
237
+ end
207
238
  end
208
239
 
209
240
  def change_column_default(table_name, column_name, default) #:nodoc:
210
- execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET DEFAULT #{quote(default)}"
241
+ alter_table(table_name) do |definition|
242
+ definition[column_name].default = default
243
+ end
211
244
  end
212
245
 
213
246
  def rename_column(table_name, column_name, new_column_name) #:nodoc:
214
- execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} RENAME TO #{new_column_name}"
247
+ unless columns(table_name).detect{|c| c.name == column_name.to_s }
248
+ raise ActiveRecord::ActiveRecordError, "Missing column #{table_name}.#{column_name}"
249
+ end
250
+ alter_table(table_name, :rename => {column_name.to_s => new_column_name.to_s})
215
251
  end
216
252
 
217
253
  def rename_table(name, new_name)
@@ -221,6 +257,7 @@ module ::JdbcSpec
221
257
  def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
222
258
  log(sql,name) do
223
259
  @connection.execute_update(sql)
260
+ clear_query_cache
224
261
  end
225
262
  table = sql.split(" ", 4)[2]
226
263
  id_value || last_insert_id(table, nil)
@@ -237,8 +274,16 @@ module ::JdbcSpec
237
274
  end
238
275
  end
239
276
 
240
- def tables
241
- @connection.tables.select {|row| row.to_s !~ /^sqlite_/i }
277
+ def tables(name = nil) #:nodoc:
278
+ sql = <<-SQL
279
+ SELECT name
280
+ FROM sqlite_master
281
+ WHERE type = 'table' AND NOT name = 'sqlite_sequence'
282
+ SQL
283
+
284
+ select_rows(sql, name).map do |row|
285
+ row[0]
286
+ end
242
287
  end
243
288
 
244
289
  def remove_index(table_name, options = {})
@@ -256,6 +301,11 @@ module ::JdbcSpec
256
301
  ::ActiveRecord::ConnectionAdapters::IndexDefinition.new(table_name, name, unique, cols)
257
302
  end
258
303
  end
304
+
305
+ def primary_key(table_name) #:nodoc:
306
+ column = table_structure(table_name).find {|field| field['pk'].to_i == 1}
307
+ column ? column['name'] : nil
308
+ end
259
309
 
260
310
  def recreate_database(name)
261
311
  tables.each{ |table| drop_table(table) }
@@ -269,7 +319,19 @@ module ::JdbcSpec
269
319
  ActiveRecord::ConnectionAdapters::JdbcConnection::insert?(sql) ? last_insert_id(sql.split(" ", 4)[2], nil) : affected_rows
270
320
  end
271
321
  end
272
-
322
+
323
+ def select(sql, name=nil)
324
+ execute(sql, name).map do |row|
325
+ record = {}
326
+ row.each_key do |key|
327
+ if key.is_a?(String)
328
+ record[key.sub(/^"?\w+"?\./, '')] = row[key]
329
+ end
330
+ end
331
+ record
332
+ end
333
+ end
334
+
273
335
  def table_structure(table_name)
274
336
  returning structure = @connection.execute_query("PRAGMA table_info(#{quote_table_name(table_name)})") do
275
337
  raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
@@ -278,9 +340,17 @@ module ::JdbcSpec
278
340
 
279
341
  def columns(table_name, name = nil) #:nodoc:
280
342
  table_structure(table_name).map do |field|
281
- ::ActiveRecord::ConnectionAdapters::JdbcColumn.new(@config, field['name'], field['dflt_value'], field['type'], field['notnull'] == "0")
343
+ ::ActiveRecord::ConnectionAdapters::JdbcColumn.new(@config, field['name'], field['dflt_value'], field['type'], field['notnull'] == 0)
282
344
  end
283
345
  end
346
+
347
+ # SELECT ... FOR UPDATE is redundant since the table is locked.
348
+ def add_lock!(sql, options) #:nodoc:
349
+ sql
350
+ end
351
+
352
+ protected
353
+ include JdbcSpec::MissingFunctionalityHelper
284
354
  end
285
355
  end
286
356