activerecord-jdbc-adapter 0.9.5-java → 0.9.6-java

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,17 @@
1
+ == 0.9.6
2
+
3
+ - The Oracle release!
4
+ - Oracle should be working much better with this release. Also updated
5
+ to work with Rails 3.
6
+ - Get all unit tests running cleanly on Oracle, fixing previous
7
+ datetime/timezone issues.
8
+ - ACTIVERECORD_JDBC-83: Add :sequence_start_value option to
9
+ create_table, following oracle_enhanced adapter
10
+ - ACTIVERECORD_JDBC-33: Don't double-quote table names in oracle
11
+ - ACTIVERECORD_JDBC-17: Fix Oracle primary keys so that /^NUMBER$/ => :integer
12
+ - Fix remaining blockers ACTIVERECORD_JDBC-82, JRUBY-3675,
13
+ ACTIVERECORD_JDBC-22, ACTIVERECORD_JDBC-27, JRUBY-4759
14
+
1
15
  == 0.9.5
2
16
 
3
17
  - The MSSQL release, courtesy of Mike Williams and Lonely
@@ -56,21 +56,36 @@ module JdbcSpec
56
56
  jdbc_connection(config)
57
57
  end
58
58
  end
59
+
60
+ module QuotedPrimaryKeyExtension
61
+ def self.extended(base)
62
+ # Rails 3 method Rails 2 method
63
+ meth = [:arel_attributes_values, :attributes_with_quotes].detect do |m|
64
+ base.private_instance_methods.include?(m.to_s)
65
+ end
66
+ pk_hash_key = "self.class.primary_key"
67
+ pk_hash_value = '"?"'
68
+ if meth == :arel_attributes_values
69
+ pk_hash_key = "self.class.arel_table[#{pk_hash_key}]"
70
+ pk_hash_value = "Arel::SqlLiteral.new(#{pk_hash_value})"
71
+ end
72
+ if meth
73
+ base.module_eval %{
74
+ alias :#{meth}_pre_pk :#{meth}
75
+ def #{meth}(include_primary_key = true, *args) #:nodoc:
76
+ aq = #{meth}_pre_pk(include_primary_key, *args)
77
+ aq[#{pk_hash_key}] = #{pk_hash_value} if include_primary_key && aq[#{pk_hash_key}].nil?
78
+ aq
79
+ end
80
+ }
81
+ end
82
+ end
83
+ end
59
84
  end
60
85
 
61
86
  module ActiveRecord
62
87
  class Base
63
88
  extend JdbcSpec::ActiveRecordExtensions
64
- if respond_to?(:attributes_with_quotes)
65
- alias :attributes_with_quotes_pre_oracle :attributes_with_quotes
66
- def attributes_with_quotes(include_primary_key = true, *args) #:nodoc:
67
- aq = attributes_with_quotes_pre_oracle(include_primary_key, *args)
68
- if connection.class == ConnectionAdapters::JdbcAdapter && (connection.is_a?(JdbcSpec::Oracle) || connection.is_a?(JdbcSpec::Mimer))
69
- aq[self.class.primary_key] = "?" if include_primary_key && aq[self.class.primary_key].nil?
70
- end
71
- aq
72
- end
73
- end
74
89
  end
75
90
 
76
91
  module ConnectionAdapters
@@ -1,5 +1,9 @@
1
1
  module JdbcSpec
2
2
  module Mimer
3
+ def self.extended(mod)
4
+ ActiveRecord::Base.extend JdbcSpec::QuotedPrimaryKeyExtension
5
+ end
6
+
3
7
  def self.adapter_matcher(name, *)
4
8
  name =~ /mimer/i ? self : false
5
9
  end
@@ -26,8 +26,10 @@ module ::JdbcSpec
26
26
  ActiveRecord::Base.after_save :after_save_with_oracle_lob
27
27
  @lob_callback_added = true
28
28
  end
29
+ ActiveRecord::Base.extend JdbcSpec::QuotedPrimaryKeyExtension
29
30
  mod.class.class_eval do
30
- alias_chained_method :insert, :query_dirty, :jdbc_oracle_insert
31
+ alias_chained_method :insert, :query_dirty, :insert
32
+ alias_chained_method :columns, :query_cache, :columns
31
33
  end
32
34
  end
33
35
 
@@ -40,6 +42,13 @@ module ::JdbcSpec
40
42
  end
41
43
 
42
44
  module Column
45
+ def primary=(val)
46
+ super
47
+ if val && @sql_type =~ /^NUMBER$/i
48
+ @type = :integer
49
+ end
50
+ end
51
+
43
52
  def type_cast(value)
44
53
  return nil if value.nil?
45
54
  case type
@@ -63,8 +72,8 @@ module ::JdbcSpec
63
72
  end
64
73
 
65
74
  def self.guess_date_or_time(value)
66
- (value.hour == 0 && value.min == 0 && value.sec == 0) ?
67
- new_date(value.year, value.month, value.day) : value
75
+ (value && value.hour == 0 && value.min == 0 && value.sec == 0) ?
76
+ Date.new(value.year, value.month, value.day) : value
68
77
  end
69
78
 
70
79
  private
@@ -74,7 +83,7 @@ module ::JdbcSpec
74
83
  when /char/i then :string
75
84
  when /float|double/i then :float
76
85
  when /int/i then :integer
77
- when /num|dec|real/i then @scale == 0 ? :integer : :decimal
86
+ when /num|dec|real/i then extract_scale(field_type) == 0 ? :integer : :decimal
78
87
  when /date|time/i then :datetime
79
88
  when /clob/i then :text
80
89
  when /blob/i then :binary
@@ -115,8 +124,9 @@ module ::JdbcSpec
115
124
  def create_table(name, options = {}) #:nodoc:
116
125
  super(name, options)
117
126
  seq_name = options[:sequence_name] || "#{name}_seq"
127
+ start_value = options[:sequence_start_value] || 10000
118
128
  raise ActiveRecord::StatementInvalid.new("name #{seq_name} too long") if seq_name.length > table_alias_length
119
- execute "CREATE SEQUENCE #{seq_name} START WITH 10000" unless options[:id] == false
129
+ execute "CREATE SEQUENCE #{seq_name} START WITH #{start_value}" unless options[:id] == false
120
130
  end
121
131
 
122
132
  def rename_table(name, new_name) #:nodoc:
@@ -138,10 +148,14 @@ module ::JdbcSpec
138
148
  recreate_database(name)
139
149
  end
140
150
 
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
151
+ def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
152
+ if (id_value && !id_value.respond_to?(:to_sql)) || pk.nil?
153
+ # Pre-assigned id or table without a primary key
154
+ # Presence of #to_sql means an Arel literal bind variable
155
+ # that should use #execute_id_insert below
143
156
  execute sql, name
144
- else # Assume the sql contains a bind-variable for the id
157
+ else
158
+ # Assume the sql contains a bind-variable for the id
145
159
  # Extract the table from the insert sql. Yuck.
146
160
  table = sql.split(" ", 4)[2].gsub('"', '')
147
161
  sequence_name ||= default_sequence_name(table)
@@ -313,6 +327,12 @@ module ::JdbcSpec
313
327
  #
314
328
  # see: abstract/quoting.rb
315
329
 
330
+ # See ACTIVERECORD_JDBC-33 for details -- better to not quote
331
+ # table names, esp. if they have schemas.
332
+ def quote_table_name(name) #:nodoc:
333
+ name.to_s
334
+ end
335
+
316
336
  # Camelcase column names need to be quoted.
317
337
  # Nonquoted identifiers can contain only alphanumeric characters from your
318
338
  # database character set and the underscore (_), dollar sign ($), and pound sign (#).
@@ -335,7 +355,7 @@ module ::JdbcSpec
335
355
  %Q{empty_#{ column.sql_type.downcase rescue 'blob' }()}
336
356
  end
337
357
  else
338
- if column.respond_to?(:primary) && column.primary
358
+ if column.respond_to?(:primary) && column.primary && column.klass != String
339
359
  return value.to_i.to_s
340
360
  end
341
361
  quoted = super
@@ -347,7 +367,7 @@ module ::JdbcSpec
347
367
  end
348
368
 
349
369
  def quoted_date(value)
350
- %Q{TIMESTAMP'#{value.strftime("%Y-%m-%d %H:%M:%S")}'}
370
+ %Q{TIMESTAMP'#{super}'}
351
371
  end
352
372
 
353
373
  def quoted_true #:nodoc:
@@ -1,5 +1,5 @@
1
1
  module JdbcAdapter
2
2
  module Version
3
- VERSION = "0.9.5"
3
+ VERSION = "0.9.6"
4
4
  end
5
5
  end
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  **** BEGIN LICENSE BLOCK *****
3
- * Copyright (c) 2006-2009 Nick Sieger <nick@nicksieger.com>
3
+ * Copyright (c) 2006-2010 Nick Sieger <nick@nicksieger.com>
4
4
  * Copyright (c) 2006-2007 Ola Bini <ola.bini@gmail.com>
5
5
  * Copyright (c) 2008-2009 Thomas E Enebo <enebo@acm.org>
6
6
  *
@@ -117,7 +117,7 @@ public class RubyJdbcConnection extends RubyObject {
117
117
  throws SQLException, IOException {
118
118
  return (IRubyObject) withConnectionAndRetry(context, new SQLBlock() {
119
119
  public Object call(Connection c) throws SQLException {
120
- ResultSet results = null;
120
+ ResultSet results = null, pkeys = null;
121
121
  try {
122
122
  String table_name = rubyApi.convertToRubyString(args[0]).getUnicodeValue();
123
123
  String schemaName = null;
@@ -143,9 +143,11 @@ public class RubyJdbcConnection extends RubyObject {
143
143
  }
144
144
 
145
145
  results = metadata.getColumns(c.getCatalog(),schemaName,table_name,null);
146
- return unmarshal_columns(context, metadata, results);
146
+ pkeys = metadata.getPrimaryKeys(c.getCatalog(),schemaName,table_name);
147
+ return unmarshal_columns(context, metadata, results, pkeys);
147
148
  } finally {
148
149
  close(results);
150
+ close(pkeys);
149
151
  }
150
152
  }
151
153
  });
@@ -991,22 +993,28 @@ public class RubyJdbcConnection extends RubyObject {
991
993
  }
992
994
 
993
995
  private IRubyObject unmarshal_columns(ThreadContext context, DatabaseMetaData metadata,
994
- ResultSet rs) throws SQLException {
996
+ ResultSet rs, ResultSet pkeys) throws SQLException {
995
997
  try {
996
998
  Ruby runtime = context.getRuntime();
997
999
  List columns = new ArrayList();
1000
+ List pkeyNames = new ArrayList();
998
1001
  String clzName = metadata.getClass().getName().toLowerCase();
999
1002
  boolean isOracle = clzName.indexOf("oracle") != -1 || clzName.indexOf("oci") != -1;
1000
1003
 
1001
1004
  RubyHash types = (RubyHash) native_database_types();
1002
1005
  IRubyObject jdbcCol = getConnectionAdapters(runtime).getConstant("JdbcColumn");
1003
1006
 
1004
- while(rs.next()) {
1007
+ while (pkeys.next()) {
1008
+ pkeyNames.add(pkeys.getString(COLUMN_NAME));
1009
+ }
1010
+
1011
+ while (rs.next()) {
1012
+ String colName = rs.getString(COLUMN_NAME);
1005
1013
  IRubyObject column = jdbcCol.callMethod(context, "new",
1006
1014
  new IRubyObject[] {
1007
1015
  getInstanceVariable("@config"),
1008
1016
  RubyString.newUnicodeString(runtime,
1009
- caseConvertIdentifierForRails(metadata, rs.getString(COLUMN_NAME))),
1017
+ caseConvertIdentifierForRails(metadata, colName)),
1010
1018
  defaultValueFromResultSet(runtime, rs),
1011
1019
  RubyString.newUnicodeString(runtime, typeFromResultSet(rs, isOracle)),
1012
1020
  runtime.newBoolean(!rs.getString(IS_NULLABLE).trim().equals("NO"))
@@ -1014,12 +1022,15 @@ public class RubyJdbcConnection extends RubyObject {
1014
1022
  columns.add(column);
1015
1023
 
1016
1024
  IRubyObject tp = (IRubyObject)types.fastARef(column.callMethod(context,"type"));
1017
- if(tp != null && !tp.isNil() && tp.callMethod(context, "[]", runtime.newSymbol("limit")).isNil()) {
1025
+ if (tp != null && !tp.isNil() && tp.callMethod(context, "[]", runtime.newSymbol("limit")).isNil()) {
1018
1026
  column.callMethod(context, "limit=", runtime.getNil());
1019
1027
  if(!column.callMethod(context, "type").equals(runtime.newSymbol("decimal"))) {
1020
1028
  column.callMethod(context, "precision=", runtime.getNil());
1021
1029
  }
1022
1030
  }
1031
+ if (pkeyNames.contains(colName)) {
1032
+ column.callMethod(context, "primary=", runtime.getTrue());
1033
+ }
1023
1034
  }
1024
1035
  return runtime.newArray(columns);
1025
1036
  } finally {
@@ -6,24 +6,49 @@ class OracleSimpleTest < Test::Unit::TestCase
6
6
  end
7
7
 
8
8
  class OracleSpecificTest < Test::Unit::TestCase
9
- include MultibyteTestMethods
9
+ include MultibyteTestMethods # so we can get @java_con
10
10
 
11
11
  def setup
12
12
  super
13
- @java_con.createStatement.execute "CREATE TABLE DEFAULT_NUMBER (VALUE NUMBER)"
14
- @java_con.createStatement.execute "INSERT INTO DEFAULT_NUMBER (VALUE) VALUES (0.076)"
13
+ @java_con.createStatement.execute "CREATE TABLE DEFAULT_NUMBER (VALUE NUMBER, DATUM DATE)"
14
+ @java_con.createStatement.execute "INSERT INTO DEFAULT_NUMBER (VALUE, DATUM) VALUES (0.076, TIMESTAMP'2009-11-05 00:00:00')"
15
+ @java_con.createStatement.execute "CREATE SYNONYM POSTS FOR ENTRIES"
16
+ @klass = Class.new(ActiveRecord::Base)
17
+ @klass.set_table_name "DEFAULT_NUMBER"
15
18
  end
16
19
 
17
20
  def teardown
18
21
  @java_con.createStatement.execute "DROP TABLE DEFAULT_NUMBER"
22
+ @java_con.createStatement.execute "DROP SYNONYM POSTS"
19
23
  super
20
24
  end
21
25
 
22
-
23
26
  def test_default_number_precision
24
- klass = Class.new(ActiveRecord::Base)
25
- klass.set_table_name "DEFAULT_NUMBER"
26
- obj = klass.find(:first)
27
+ obj = @klass.find(:first)
27
28
  assert_equal 0.076, obj.value
28
29
  end
30
+
31
+ # JRUBY-3675, ACTIVERECORD_JDBC-22
32
+ def test_load_date
33
+ obj = @klass.find(:first)
34
+ assert_not_nil obj.datum, "no date"
35
+ end
36
+
37
+ def test_load_null_date
38
+ @java_con.createStatement.execute "UPDATE DEFAULT_NUMBER SET DATUM = NULL"
39
+ obj = @klass.find(:first)
40
+ assert obj.datum.nil?
41
+ end
42
+
43
+ def test_model_access_by_synonym
44
+ @klass.set_table_name "POSTS"
45
+ entry_columns = Entry.columns_hash
46
+ @klass.columns.each do |c|
47
+ ec = entry_columns[c.name]
48
+ assert ec
49
+ assert_equal ec.sql_type, c.sql_type
50
+ assert_equal ec.type, c.type
51
+ end
52
+ end
53
+
29
54
  end if defined?(JRUBY_VERSION)
@@ -105,6 +105,20 @@ module SimpleTestMethods
105
105
  end
106
106
 
107
107
  if Time.respond_to?(:zone)
108
+ def test_save_time_with_utc
109
+ current_zone = Time.zone
110
+ default_zone = ActiveRecord::Base.default_timezone
111
+ ActiveRecord::Base.default_timezone = Time.zone = :utc
112
+ now = Time.now
113
+ my_time = Time.local now.year, now.month, now.day, now.hour, now.min, now.sec
114
+ m = DbType.create! :sample_datetime => my_time
115
+ m.reload
116
+ assert_equal my_time, m.sample_datetime
117
+ rescue
118
+ Time.zone = current_zone
119
+ ActiveRecord::Base.default_timezone = default_zone
120
+ end
121
+
108
122
  def test_save_time
109
123
  t = Time.now
110
124
  #precision will only be expected to the second.
@@ -156,7 +170,12 @@ module SimpleTestMethods
156
170
  e.sample_date = date
157
171
  e.save!
158
172
  e = DbType.find(:first)
159
- assert_equal date, e.sample_date
173
+ if DbType.columns_hash["sample_date"].type == :datetime
174
+ # Oracle doesn't distinguish btw date/datetime
175
+ assert_equal date, e.sample_date.to_date
176
+ else
177
+ assert_equal date, e.sample_date
178
+ end
160
179
  end
161
180
 
162
181
  def test_boolean
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 9
8
- - 5
9
- version: 0.9.5
8
+ - 6
9
+ version: 0.9.6
10
10
  platform: java
11
11
  authors:
12
12
  - Nick Sieger, Ola Bini and JRuby contributors
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-04-22 00:00:00 -05:00
17
+ date: 2010-05-05 00:00:00 -05:00
18
18
  default_executable:
19
19
  dependencies: []
20
20