activerecord-jdbc-adapter 0.7.2 → 0.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,17 @@
1
+ == 0.8
2
+
3
+ - NOTE: This release is only compatible with JRuby 1.1RC3 or later.
4
+ - Because of recent API changes in trunk in preparation for JRuby 1.1, this release is not
5
+ backward compatible with previous JRuby releases. Hence the version bump.
6
+ - Internal: convert Java methods to be defined with annotations
7
+ - Fix problem with reserved words coming back pre-quoted from #indexes in postgres
8
+ - JRUBY-2205: Fix N^2 allocation of bytelists for mysql quoting (taw)
9
+ - Attempt a fix for Rubyforge 18059
10
+ - Upgrade derby to 10.3.2.1
11
+ - Fix db:create etc. in the case where JDBC is loaded in Rails' preinitializer.rb
12
+ - Fix db:drop to actually work
13
+ - Fix for Rubyforge #11567 (Matt Williams)
14
+
1
15
  == 0.7.2
2
16
 
3
17
  - JRUBY-1905: add_column for derby, hsqldb, and postgresql (Stephen Bannasch)
@@ -1,5 +1,5 @@
1
- Copyright (c) 2006-2007 Nick Sieger <nick@nicksieger.com>
2
- Copyright (c) 2006-2007 Ola Bini <ola@ologix.com>
1
+ Copyright (c) 2006-2008 Nick Sieger <nick@nicksieger.com>
2
+ Copyright (c) 2006-2008 Ola Bini <ola.bini@gmail.com>
3
3
 
4
4
  Permission is hereby granted, free of charge, to any person obtaining
5
5
  a copy of this software and associated documentation files (the
@@ -2,7 +2,7 @@ History.txt
2
2
  Manifest.txt
3
3
  README.txt
4
4
  Rakefile
5
- LICENSE
5
+ LICENSE.txt
6
6
  lib/active_record/connection_adapters/derby_adapter.rb
7
7
  lib/active_record/connection_adapters/h2_adapter.rb
8
8
  lib/active_record/connection_adapters/hsqldb_adapter.rb
@@ -60,11 +60,14 @@ test/models/add_not_null_column_to_table.rb
60
60
  test/models/auto_id.rb
61
61
  test/models/data_types.rb
62
62
  test/models/entry.rb
63
+ test/models/reserved_word.rb
63
64
  test/mysql_multibyte_test.rb
64
65
  test/mysql_simple_test.rb
65
66
  test/oracle_simple_test.rb
67
+ test/postgres_reserved_test.rb
66
68
  test/postgres_simple_test.rb
67
69
  test/simple.rb
70
+ lib/jdbc_adapter/jdbc.rake
68
71
  src/java/jdbc_adapter/JdbcAdapterInternalService.java
69
72
  src/java/jdbc_adapter/JdbcConnectionFactory.java
70
73
  src/java/jdbc_adapter/JdbcDerbySpec.java
data/Rakefile CHANGED
@@ -20,7 +20,7 @@ task :java_compile do
20
20
  pkg_classes = File.join(*%w(pkg classes))
21
21
  jar_name = File.join(*%w(lib jdbc_adapter jdbc_adapter_internal.jar))
22
22
  mkdir_p pkg_classes
23
- sh "javac -target 1.4 -source 1.4 -d pkg/classes #{java_classpath_arg} #{FileList['src/java/**/*.java'].join(' ')}"
23
+ sh "javac -target 1.5 -source 1.5 -d pkg/classes #{java_classpath_arg} #{FileList['src/java/**/*.java'].join(' ')}"
24
24
  sh "jar cf #{jar_name} -C #{pkg_classes} ."
25
25
  end
26
26
  file "lib/jdbc_adapter/jdbc_adapter_internal.jar" => :java_compile
@@ -87,7 +87,7 @@ end
87
87
 
88
88
 
89
89
  MANIFEST = FileList["History.txt", "Manifest.txt", "README.txt",
90
- "Rakefile", "LICENSE", "lib/**/*.rb", "lib/jdbc_adapter/jdbc_adapter_internal.jar", "test/**/*.rb",
90
+ "Rakefile", "LICENSE.txt", "lib/**/*.rb", "lib/jdbc_adapter/jdbc_adapter_internal.jar", "test/**/*.rb",
91
91
  "lib/**/*.rake", "src/**/*.java"]
92
92
 
93
93
  file "Manifest.txt" => :manifest
@@ -342,19 +342,19 @@ module ActiveRecord
342
342
  next unless index_name
343
343
  index_name.downcase!
344
344
  column_name = resultset.get_string(Jdbc::IndexMetaData::COLUMN_NAME).downcase
345
-
345
+
346
346
  next if primary_keys.include? column_name
347
-
347
+
348
348
  # We are working on a new index
349
349
  if current_index != index_name
350
350
  current_index = index_name
351
351
  table_name = resultset.get_string(Jdbc::IndexMetaData::TABLE_NAME).downcase
352
352
  non_unique = resultset.get_boolean(Jdbc::IndexMetaData::NON_UNIQUE)
353
-
353
+
354
354
  # empty list for column names, we'll add to that in just a bit
355
355
  indexes << IndexDefinition.new(table_name, index_name, !non_unique, [])
356
356
  end
357
-
357
+
358
358
  # One or more columns can be associated with an index
359
359
  indexes.last.columns << column_name
360
360
  end
@@ -404,7 +404,19 @@ module ActiveRecord
404
404
 
405
405
  end
406
406
 
407
+ module ShadowCoreMethods
408
+ def alias_chained_method(meth, feature, target)
409
+ if instance_methods.include?("#{meth}_without_#{feature}")
410
+ alias_method "#{meth}_without_#{feature}".to_sym, target
411
+ else
412
+ alias_method meth, target
413
+ end
414
+ end
415
+ end
416
+
407
417
  class JdbcAdapter < AbstractAdapter
418
+ extend ShadowCoreMethods
419
+
408
420
  attr_reader :config
409
421
 
410
422
  ADAPTER_TYPES = ::JdbcSpec.constants.map{|c|
@@ -484,14 +496,15 @@ module ActiveRecord
484
496
  @connection.reconnect!
485
497
  @connection
486
498
  end
487
-
499
+
488
500
  def disconnect!
489
501
  @connection.disconnect!
490
502
  end
491
503
 
492
- def select_all(sql, name = nil)
504
+ def jdbc_select_all(sql, name = nil)
493
505
  select(sql, name)
494
506
  end
507
+ alias_chained_method :select_all, :query_cache, :jdbc_select_all
495
508
 
496
509
  def select_rows(sql, name = nil)
497
510
  rows = []
@@ -508,8 +521,7 @@ module ActiveRecord
508
521
  _execute(sql,name)
509
522
  end
510
523
  end
511
-
512
-
524
+
513
525
  # we need to do it this way, to allow Rails stupid tests to always work
514
526
  # even if we define a new execute method. Instead of mixing in a new
515
527
  # execute, an _execute should be mixed in.
@@ -523,18 +535,21 @@ module ActiveRecord
523
535
  end
524
536
  end
525
537
 
526
- def update(sql, name = nil) #:nodoc:
538
+ def jdbc_update(sql, name = nil) #:nodoc:
527
539
  execute(sql, name)
528
540
  end
541
+ alias_chained_method :update, :query_dirty, :jdbc_update
529
542
 
530
- def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
543
+ def jdbc_insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
531
544
  id = execute(sql, name = nil)
532
545
  id_value || id
533
546
  end
547
+ alias_chained_method :insert, :query_dirty, :jdbc_insert
534
548
 
535
- def columns(table_name, name = nil)
549
+ def jdbc_columns(table_name, name = nil)
536
550
  @connection.columns(table_name.to_s)
537
551
  end
552
+ alias_chained_method :columns, :query_cache, :jdbc_columns
538
553
 
539
554
  def tables
540
555
  @connection.tables
@@ -0,0 +1,78 @@
1
+ def redefine_task(*args, &block)
2
+ task_name = Hash === args.first ? args.first.keys[0] : args.first
3
+ existing_task = Rake.application.lookup task_name
4
+ if existing_task
5
+ class << existing_task; public :instance_variable_set; end
6
+ existing_task.instance_variable_set "@prerequisites", FileList[]
7
+ existing_task.instance_variable_set "@actions", []
8
+ end
9
+ task(*args, &block)
10
+ end
11
+
12
+ namespace :db do
13
+ redefine_task :create => :environment do
14
+ create_database(ActiveRecord::Base.configurations[RAILS_ENV])
15
+ end
16
+
17
+ class << self; alias_method :previous_create_database, :create_database; end
18
+ def create_database(config)
19
+ begin
20
+ ActiveRecord::Base.establish_connection(config)
21
+ ActiveRecord::Base.connection
22
+ rescue
23
+ begin
24
+ url = config['url']
25
+ if url
26
+ if url =~ /^(.*\/)/
27
+ url = $1
28
+ end
29
+ end
30
+
31
+ ActiveRecord::Base.establish_connection(config.merge({'database' => nil, 'url' => url}))
32
+ ActiveRecord::Base.connection.create_database(config['database'])
33
+ ActiveRecord::Base.establish_connection(config)
34
+ rescue
35
+ previous_create_database(config)
36
+ end
37
+ end
38
+ end
39
+
40
+ redefine_task :drop => :environment do
41
+ config = ActiveRecord::Base.configurations[RAILS_ENV]
42
+ begin
43
+ ActiveRecord::Base.establish_connection(config)
44
+ db = ActiveRecord::Base.connection.database_name
45
+ ActiveRecord::Base.connection.drop_database(db)
46
+ rescue
47
+ drop_database(config)
48
+ end
49
+ end
50
+
51
+ namespace :structure do
52
+ redefine_task :dump => :environment do
53
+ abcs = ActiveRecord::Base.configurations
54
+ ActiveRecord::Base.establish_connection(abcs[RAILS_ENV])
55
+ File.open("db/#{RAILS_ENV}_structure.sql", "w+") { |f| f << ActiveRecord::Base.connection.structure_dump }
56
+ if ActiveRecord::Base.connection.supports_migrations?
57
+ File.open("db/#{RAILS_ENV}_structure.sql", "a") { |f| f << ActiveRecord::Base.connection.dump_schema_information }
58
+ end
59
+ end
60
+ end
61
+ namespace :test do
62
+ redefine_task :clone_structure => [ "db:structure:dump", "db:test:purge" ] do
63
+ abcs = ActiveRecord::Base.configurations
64
+ ActiveRecord::Base.establish_connection(:test)
65
+ ActiveRecord::Base.connection.execute('SET foreign_key_checks = 0') if abcs["test"]["adapter"] =~ /mysql/i
66
+ IO.readlines("db/#{RAILS_ENV}_structure.sql").join.split(";\n\n").each do |ddl|
67
+ ActiveRecord::Base.connection.execute(ddl)
68
+ end
69
+ end
70
+
71
+ redefine_task :purge => :environment do
72
+ abcs = ActiveRecord::Base.configurations
73
+ ActiveRecord::Base.establish_connection(:test)
74
+ db = ActiveRecord::Base.connection.database_name
75
+ ActiveRecord::Base.connection.recreate_database(db)
76
+ end
77
+ end
78
+ end
@@ -157,6 +157,17 @@ module ::JdbcSpec
157
157
  Integer(select_value("SELECT IDENTITY() FROM #{table}"))
158
158
  end
159
159
 
160
+ # Override normal #_execute: See Rubyforge #11567
161
+ def _execute(sql, name = nil)
162
+ if ::ActiveRecord::ConnectionAdapters::JdbcConnection::select?(sql)
163
+ @connection.execute_query(sql)
164
+ elsif ::ActiveRecord::ConnectionAdapters::JdbcConnection::insert?(sql)
165
+ insert(sql, name)
166
+ else
167
+ @connection.execute_update(sql)
168
+ end
169
+ end
170
+
160
171
  def add_limit_offset!(sql, options) #:nodoc:
161
172
  offset = options[:offset] || 0
162
173
  bef = sql[7..-1]
@@ -6,9 +6,6 @@ module ::JdbcSpec
6
6
 
7
7
  module ActiveRecordExtensions
8
8
  def mysql_connection(config)
9
- if config[:socket]
10
- warn "AR-JDBC MySQL on JRuby does not support sockets"
11
- end
12
9
  config[:port] ||= 3306
13
10
  if config[:url]
14
11
  config[:url] = config[:url]['?'] ? "#{config[:url]}&#{MySQL::URL_OPTIONS}" : "#{config[:url]}?#{MySQL::URL_OPTIONS}"
@@ -147,8 +144,12 @@ module ::JdbcSpec
147
144
  create_database(name)
148
145
  end
149
146
 
150
- def create_database(name) #:nodoc:
151
- execute "CREATE DATABASE `#{name}`"
147
+ def create_database(name, options = {}) #:nodoc:
148
+ if options[:collation]
149
+ execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}` COLLATE `#{options[:collation]}`"
150
+ else
151
+ execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}`"
152
+ end
152
153
  end
153
154
 
154
155
  def drop_database(name) #:nodoc:
@@ -177,7 +177,41 @@ module ::JdbcSpec
177
177
  end
178
178
  @connection.columns_internal(table_name, name, schema_name)
179
179
  end
180
-
180
+
181
+ # From postgresql_adapter.rb
182
+ def indexes(table_name, name = nil)
183
+ result = select_rows(<<-SQL, name)
184
+ SELECT i.relname, d.indisunique, a.attname
185
+ FROM pg_class t, pg_class i, pg_index d, pg_attribute a
186
+ WHERE i.relkind = 'i'
187
+ AND d.indexrelid = i.oid
188
+ AND d.indisprimary = 'f'
189
+ AND t.oid = d.indrelid
190
+ AND t.relname = '#{table_name}'
191
+ AND a.attrelid = t.oid
192
+ AND ( d.indkey[0]=a.attnum OR d.indkey[1]=a.attnum
193
+ OR d.indkey[2]=a.attnum OR d.indkey[3]=a.attnum
194
+ OR d.indkey[4]=a.attnum OR d.indkey[5]=a.attnum
195
+ OR d.indkey[6]=a.attnum OR d.indkey[7]=a.attnum
196
+ OR d.indkey[8]=a.attnum OR d.indkey[9]=a.attnum )
197
+ ORDER BY i.relname
198
+ SQL
199
+
200
+ current_index = nil
201
+ indexes = []
202
+
203
+ result.each do |row|
204
+ if current_index != row[0]
205
+ indexes << ::ActiveRecord::ConnectionAdapters::IndexDefinition.new(table_name, row[0], row[1] == "t", [])
206
+ current_index = row[0]
207
+ end
208
+
209
+ indexes.last.columns << row[2]
210
+ end
211
+
212
+ indexes
213
+ end
214
+
181
215
  def last_insert_id(table, sequence_name)
182
216
  Integer(select_value("SELECT currval('#{sequence_name}')"))
183
217
  end
@@ -1,82 +1,10 @@
1
- if defined?(namespace) && RUBY_PLATFORM =~ /java/ && ENV["SKIP_AR_JDBC_RAKE_REDEFINES"].nil?
2
- def redefine_task(*args, &block)
3
- task_name = Hash === args.first ? args.first.keys[0] : args.first
4
- existing_task = Rake.application.lookup task_name
5
- if existing_task
6
- class << existing_task; public :instance_variable_set; end
7
- existing_task.instance_variable_set "@prerequisites", FileList[]
8
- existing_task.instance_variable_set "@actions", []
9
- end
10
- task(*args, &block)
11
- end
12
-
13
- namespace :db do
14
- redefine_task :create => :environment do
15
- create_database(ActiveRecord::Base.configurations[RAILS_ENV])
16
- end
17
-
18
- def create_database(config)
19
- begin
20
- ActiveRecord::Base.establish_connection(config)
21
- ActiveRecord::Base.connection
22
- rescue
23
- begin
24
- url = config['url']
25
- if url
26
- if url =~ /^(.*\/)/
27
- url = $1
28
- end
29
- end
30
-
31
- ActiveRecord::Base.establish_connection(config.merge({'database' => nil, 'url' => url}))
32
- ActiveRecord::Base.connection.create_database(config['database'])
33
- ActiveRecord::Base.establish_connection(config)
34
- rescue
35
- if (config['driver'] || config['adapter']) =~ /postgr/
36
- `createdb "#{config['database']}" -E utf8`
37
- else
38
- warn "couldn't create database #{config['database']}"
39
- end
40
- end
41
- end
42
- end
43
-
44
- redefine_task :drop => :environment do
45
- begin
46
- config = ActiveRecord::Base.configurations[environment_name]
47
- ActiveRecord::Base.establish_connection(config)
48
- db = ActiveRecord::Base.connection.database_name
49
- ActiveRecord::Base.connection.recreate_database(db)
50
- rescue
51
- end
52
- end
53
-
54
- namespace :structure do
55
- redefine_task :dump => :environment do
56
- abcs = ActiveRecord::Base.configurations
57
- ActiveRecord::Base.establish_connection(abcs[RAILS_ENV])
58
- File.open("db/#{RAILS_ENV}_structure.sql", "w+") { |f| f << ActiveRecord::Base.connection.structure_dump }
59
- if ActiveRecord::Base.connection.supports_migrations?
60
- File.open("db/#{RAILS_ENV}_structure.sql", "a") { |f| f << ActiveRecord::Base.connection.dump_schema_information }
61
- end
62
- end
63
- end
64
- namespace :test do
65
- redefine_task :clone_structure => [ "db:structure:dump", "db:test:purge" ] do
66
- abcs = ActiveRecord::Base.configurations
67
- ActiveRecord::Base.establish_connection(:test)
68
- ActiveRecord::Base.connection.execute('SET foreign_key_checks = 0') if abcs["test"]["adapter"] =~ /mysql/i
69
- IO.readlines("db/#{RAILS_ENV}_structure.sql").join.split(";\n\n").each do |ddl|
70
- ActiveRecord::Base.connection.execute(ddl)
71
- end
72
- end
73
-
74
- redefine_task :purge => :environment do
75
- abcs = ActiveRecord::Base.configurations
76
- ActiveRecord::Base.establish_connection(:test)
77
- db = ActiveRecord::Base.connection.database_name
78
- ActiveRecord::Base.connection.recreate_database(db)
79
- end
80
- end
1
+ if defined?(Rake.application) && Rake.application && ENV["SKIP_AR_JDBC_RAKE_REDEFINES"].nil?
2
+ jdbc_rakefile = File.dirname(__FILE__) + "/jdbc.rake"
3
+ if Rake.application.lookup("environment")
4
+ # rails tasks already defined; load the override tasks now
5
+ load jdbc_rakefile
6
+ else
7
+ # rails tasks not loaded yet; load as an import
8
+ Rake.application.add_import(jdbc_rakefile)
81
9
  end
82
10
  end
@@ -1,5 +1,5 @@
1
1
  module JdbcAdapter
2
2
  module Version
3
- VERSION = "0.7.2"
3
+ VERSION = "0.8"
4
4
  end
5
5
  end
@@ -59,14 +59,13 @@ import org.jruby.RubyObjectAdapter;
59
59
  import org.jruby.RubyString;
60
60
  import org.jruby.RubySymbol;
61
61
  import org.jruby.RubyTime;
62
- import org.jruby.
63
- exceptions.RaiseException;
62
+ import org.jruby.anno.JRubyMethod;
63
+ import org.jruby.exceptions.RaiseException;
64
64
  import org.jruby.javasupport.Java;
65
65
  import org.jruby.javasupport.JavaEmbedUtils;
66
66
  import org.jruby.javasupport.JavaObject;
67
67
  import org.jruby.runtime.Arity;
68
68
  import org.jruby.runtime.Block;
69
- import org.jruby.runtime.CallbackFactory;
70
69
  import org.jruby.runtime.ThreadContext;
71
70
  import org.jruby.runtime.builtin.IRubyObject;
72
71
  import org.jruby.runtime.load.BasicLibraryService;
@@ -76,43 +75,14 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
76
75
  private static RubyObjectAdapter rubyApi;
77
76
 
78
77
  public boolean basicLoad(final Ruby runtime) throws IOException {
79
- RubyClass cJdbcConn = ((RubyModule)(runtime.getModule("ActiveRecord").getConstant("ConnectionAdapters"))).
78
+ RubyModule jdbcConnection = ((RubyModule)(runtime.getModule("ActiveRecord").getConstant("ConnectionAdapters"))).
80
79
  defineClassUnder("JdbcConnection",runtime.getObject(),runtime.getObject().getAllocator());
81
-
82
- CallbackFactory cf = runtime.callbackFactory(JdbcAdapterInternalService.class);
83
- cJdbcConn.defineMethod("unmarshal_result",cf.getSingletonMethod("unmarshal_result", IRubyObject.class));
84
- cJdbcConn.defineMethod("with_connection_retry_guard",cf.getSingletonMethod("with_connection_retry_guard"));
85
- cJdbcConn.defineFastMethod("connection",cf.getFastSingletonMethod("connection"));
86
- cJdbcConn.defineFastMethod("reconnect!",cf.getFastSingletonMethod("reconnect"));
87
- cJdbcConn.defineFastMethod("disconnect!",cf.getFastSingletonMethod("disconnect"));
88
- cJdbcConn.defineFastMethod("execute_update",cf.getFastSingletonMethod("execute_update", IRubyObject.class));
89
- cJdbcConn.defineFastMethod("execute_query",cf.getFastOptSingletonMethod("execute_query"));
90
- cJdbcConn.defineFastMethod("execute_insert",cf.getFastSingletonMethod("execute_insert", IRubyObject.class));
91
- cJdbcConn.defineFastMethod("execute_id_insert",cf.getFastSingletonMethod("execute_id_insert", IRubyObject.class, IRubyObject.class));
92
- cJdbcConn.defineFastMethod("primary_keys",cf.getFastSingletonMethod("primary_keys", IRubyObject.class));
93
- cJdbcConn.defineFastMethod("set_native_database_types",cf.getFastSingletonMethod("set_native_database_types"));
94
- cJdbcConn.defineFastMethod("native_database_types",cf.getFastSingletonMethod("native_database_types"));
95
- cJdbcConn.defineFastMethod("begin",cf.getFastSingletonMethod("begin"));
96
- cJdbcConn.defineFastMethod("commit",cf.getFastSingletonMethod("commit"));
97
- cJdbcConn.defineFastMethod("rollback",cf.getFastSingletonMethod("rollback"));
98
- cJdbcConn.defineFastMethod("database_name",cf.getFastSingletonMethod("database_name"));
99
- cJdbcConn.defineFastMethod("columns",cf.getFastOptSingletonMethod("columns_internal"));
100
- cJdbcConn.defineFastMethod("columns_internal",cf.getFastOptSingletonMethod("columns_internal"));
101
- cJdbcConn.defineFastMethod("tables",cf.getFastOptSingletonMethod("tables"));
102
-
103
- cJdbcConn.defineFastMethod("insert_bind",cf.getFastOptSingletonMethod("insert_bind"));
104
- cJdbcConn.defineFastMethod("update_bind",cf.getFastOptSingletonMethod("update_bind"));
105
-
106
- cJdbcConn.defineFastMethod("write_large_object",cf.getFastOptSingletonMethod("write_large_object"));
107
-
108
- cJdbcConn.getMetaClass().defineFastMethod("insert?",cf.getFastSingletonMethod("insert_p", IRubyObject.class));
109
- cJdbcConn.getMetaClass().defineFastMethod("select?",cf.getFastSingletonMethod("select_p", IRubyObject.class));
110
-
80
+ jdbcConnection.defineAnnotatedMethods(JdbcAdapterInternalService.class);
111
81
  RubyModule jdbcSpec = runtime.getOrCreateModule("JdbcSpec");
112
82
 
113
83
  rubyApi = JavaEmbedUtils.newObjectAdapter();
114
- JdbcMySQLSpec.load(runtime, jdbcSpec);
115
- JdbcDerbySpec.load(runtime, jdbcSpec, rubyApi);
84
+ JdbcMySQLSpec.load(jdbcSpec);
85
+ JdbcDerbySpec.load(jdbcSpec, rubyApi);
116
86
  return true;
117
87
  }
118
88
 
@@ -132,6 +102,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
132
102
  return p;
133
103
  }
134
104
 
105
+ @JRubyMethod(name = "insert?", required = 1, meta = true)
135
106
  public static IRubyObject insert_p(IRubyObject recv, IRubyObject _sql) {
136
107
  ByteList bl = rubyApi.convertToRubyString(_sql).getByteList();
137
108
 
@@ -170,6 +141,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
170
141
  return recv.getRuntime().getFalse();
171
142
  }
172
143
 
144
+ @JRubyMethod(name = "select?", required = 1, meta = true)
173
145
  public static IRubyObject select_p(IRubyObject recv, IRubyObject _sql) {
174
146
  ByteList bl = rubyApi.convertToRubyString(_sql).getByteList();
175
147
 
@@ -225,6 +197,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
225
197
  return recv.getRuntime().getFalse();
226
198
  }
227
199
 
200
+ @JRubyMethod(name = "connection")
228
201
  public static IRubyObject connection(IRubyObject recv) {
229
202
  Connection c = getConnection(recv);
230
203
  if (c == null) {
@@ -233,16 +206,19 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
233
206
  return rubyApi.getInstanceVariable(recv, "@connection");
234
207
  }
235
208
 
209
+ @JRubyMethod(name = "disconnect!")
236
210
  public static IRubyObject disconnect(IRubyObject recv) {
237
211
  setConnection(recv, null);
238
212
  return recv;
239
213
  }
240
214
 
215
+ @JRubyMethod(name = "reconnect!")
241
216
  public static IRubyObject reconnect(IRubyObject recv) {
242
217
  setConnection(recv, getConnectionFactory(recv).newConnection());
243
218
  return recv;
244
219
  }
245
220
 
221
+ @JRubyMethod(name = "with_connection_retry_guard", frame = true)
246
222
  public static IRubyObject with_connection_retry_guard(final IRubyObject recv, final Block block) {
247
223
  return withConnectionAndRetry(recv, new SQLBlock() {
248
224
  public IRubyObject call(Connection c) throws SQLException {
@@ -323,6 +299,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
323
299
  };
324
300
  }
325
301
 
302
+ @JRubyMethod(name = "tables", rest = true)
326
303
  public static IRubyObject tables(final IRubyObject recv, IRubyObject[] args) {
327
304
  final Ruby runtime = recv.getRuntime();
328
305
  final String catalog = getCatalog(args);
@@ -371,10 +348,12 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
371
348
  return types;
372
349
  }
373
350
 
351
+ @JRubyMethod(name = "native_database_types")
374
352
  public static IRubyObject native_database_types(IRubyObject recv) {
375
353
  return rubyApi.getInstanceVariable(recv, "@tps");
376
354
  }
377
355
 
356
+ @JRubyMethod(name = "set_native_database_types")
378
357
  public static IRubyObject set_native_database_types(IRubyObject recv) throws SQLException, IOException {
379
358
  Ruby runtime = recv.getRuntime();
380
359
  IRubyObject types = unmarshal_result_downcase(recv, getConnection(recv).getMetaData().getTypeInfo());
@@ -384,6 +363,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
384
363
  return runtime.getNil();
385
364
  }
386
365
 
366
+ @JRubyMethod(name = "database_name")
387
367
  public static IRubyObject database_name(IRubyObject recv) throws SQLException {
388
368
  String name = getConnection(recv).getCatalog();
389
369
  if(null == name) {
@@ -395,11 +375,13 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
395
375
  return recv.getRuntime().newString(name);
396
376
  }
397
377
 
378
+ @JRubyMethod(name = "begin")
398
379
  public static IRubyObject begin(IRubyObject recv) throws SQLException {
399
380
  getConnection(recv).setAutoCommit(false);
400
381
  return recv.getRuntime().getNil();
401
382
  }
402
383
 
384
+ @JRubyMethod(name = "commit")
403
385
  public static IRubyObject commit(IRubyObject recv) throws SQLException {
404
386
  try {
405
387
  getConnection(recv).commit();
@@ -409,6 +391,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
409
391
  }
410
392
  }
411
393
 
394
+ @JRubyMethod(name = "rollback")
412
395
  public static IRubyObject rollback(IRubyObject recv) throws SQLException {
413
396
  try {
414
397
  getConnection(recv).rollback();
@@ -418,6 +401,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
418
401
  }
419
402
  }
420
403
 
404
+ @JRubyMethod(name = {"columns", "columns_internal"}, required = 1, optional = 2)
421
405
  public static IRubyObject columns_internal(final IRubyObject recv, final IRubyObject[] args) throws SQLException, IOException {
422
406
  return withConnectionAndRetry(recv, new SQLBlock() {
423
407
  public IRubyObject call(Connection c) throws SQLException {
@@ -549,6 +533,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
549
533
  }
550
534
  }
551
535
 
536
+ @JRubyMethod(name = "primary_keys", required = 1)
552
537
  public static IRubyObject primary_keys(final IRubyObject recv, final IRubyObject _table_name) throws SQLException {
553
538
  return withConnectionAndRetry(recv, new SQLBlock() {
554
539
  public IRubyObject call(Connection c) throws SQLException {
@@ -580,6 +565,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
580
565
  });
581
566
  }
582
567
 
568
+ @JRubyMethod(name = "execute_id_insert", required = 2)
583
569
  public static IRubyObject execute_id_insert(IRubyObject recv, final IRubyObject sql, final IRubyObject id) throws SQLException {
584
570
  return withConnectionAndRetry(recv, new SQLBlock() {
585
571
  public IRubyObject call(Connection c) throws SQLException {
@@ -595,6 +581,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
595
581
  });
596
582
  }
597
583
 
584
+ @JRubyMethod(name = "execute_update", required = 1)
598
585
  public static IRubyObject execute_update(final IRubyObject recv, final IRubyObject sql) throws SQLException {
599
586
  return withConnectionAndRetry(recv, new SQLBlock() {
600
587
  public IRubyObject call(Connection c) throws SQLException {
@@ -614,6 +601,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
614
601
  });
615
602
  }
616
603
 
604
+ @JRubyMethod(name = "execute_query", rest = true)
617
605
  public static IRubyObject execute_query(final IRubyObject recv, IRubyObject[] args) throws SQLException, IOException {
618
606
  final IRubyObject sql = args[0];
619
607
  final int maxrows;
@@ -643,6 +631,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
643
631
  });
644
632
  }
645
633
 
634
+ @JRubyMethod(name = "execute_insert", required = 1)
646
635
  public static IRubyObject execute_insert(final IRubyObject recv, final IRubyObject sql) throws SQLException {
647
636
  return withConnectionAndRetry(recv, new SQLBlock() {
648
637
  public IRubyObject call(Connection c) throws SQLException {
@@ -735,6 +724,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
735
724
  return runtime.newArray(results);
736
725
  }
737
726
 
727
+ @JRubyMethod(name = "unmarshal_result", required = 1)
738
728
  public static IRubyObject unmarshal_result(IRubyObject recv, IRubyObject resultset, Block row_filter) throws SQLException, IOException {
739
729
  Ruby runtime = recv.getRuntime();
740
730
  ResultSet rs = intoResultSet(resultset);
@@ -897,7 +887,8 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
897
887
 
898
888
  private final static DateFormat FORMAT = new SimpleDateFormat("%y-%M-%d %H:%m:%s");
899
889
 
900
- private static void setValue(PreparedStatement ps, int index, Ruby runtime, IRubyObject value, IRubyObject type) throws SQLException {
890
+ private static void setValue(PreparedStatement ps, int index, Ruby runtime, ThreadContext context,
891
+ IRubyObject value, IRubyObject type) throws SQLException {
901
892
  final int tp = getTypeValueFor(runtime, type);
902
893
  if(value.isNil()) {
903
894
  ps.setNull(index, tp);
@@ -907,7 +898,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
907
898
  switch(tp) {
908
899
  case Types.VARCHAR:
909
900
  case Types.CLOB:
910
- ps.setString(index, RubyString.objAsString(value).toString());
901
+ ps.setString(index, RubyString.objAsString(context, value).toString());
911
902
  break;
912
903
  case Types.INTEGER:
913
904
  ps.setLong(index, RubyNumeric.fix2long(value));
@@ -920,10 +911,10 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
920
911
  case Types.DATE:
921
912
  if(!(value instanceof RubyTime)) {
922
913
  try {
923
- Date dd = FORMAT.parse(RubyString.objAsString(value).toString());
914
+ Date dd = FORMAT.parse(RubyString.objAsString(context, value).toString());
924
915
  ps.setTimestamp(index, new java.sql.Timestamp(dd.getTime()), Calendar.getInstance());
925
916
  } catch(Exception e) {
926
- ps.setString(index, RubyString.objAsString(value).toString());
917
+ ps.setString(index, RubyString.objAsString(context, value).toString());
927
918
  }
928
919
  } else {
929
920
  RubyTime rubyTime = (RubyTime) value;
@@ -944,27 +935,28 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
944
935
  }
945
936
  }
946
937
 
947
- private static void setValuesOnPS(PreparedStatement ps, Ruby runtime, IRubyObject values, IRubyObject types) throws SQLException {
938
+ private static void setValuesOnPS(PreparedStatement ps, Ruby runtime, ThreadContext context,
939
+ IRubyObject values, IRubyObject types) throws SQLException {
948
940
  RubyArray vals = (RubyArray)values;
949
941
  RubyArray tps = (RubyArray)types;
950
942
 
951
943
  for(int i=0, j=vals.getLength(); i<j; i++) {
952
- setValue(ps, i+1, runtime, vals.eltInternal(i), tps.eltInternal(i));
944
+ setValue(ps, i+1, runtime, context, vals.eltInternal(i), tps.eltInternal(i));
953
945
  }
954
946
  }
955
947
 
956
948
  /*
957
949
  * sql, values, types, name = nil, pk = nil, id_value = nil, sequence_name = nil
958
950
  */
959
- public static IRubyObject insert_bind(IRubyObject recv, final IRubyObject[] args) throws SQLException {
951
+ @JRubyMethod(name = "insert_bind", required = 3, rest = true)
952
+ public static IRubyObject insert_bind(final ThreadContext context, IRubyObject recv, final IRubyObject[] args) throws SQLException {
960
953
  final Ruby runtime = recv.getRuntime();
961
- Arity.checkArgumentCount(runtime, args, 3, 7);
962
954
  return withConnectionAndRetry(recv, new SQLBlock() {
963
955
  public IRubyObject call(Connection c) throws SQLException {
964
956
  PreparedStatement ps = null;
965
957
  try {
966
958
  ps = c.prepareStatement(rubyApi.convertToRubyString(args[0]).toString(), Statement.RETURN_GENERATED_KEYS);
967
- setValuesOnPS(ps, runtime, args[1], args[2]);
959
+ setValuesOnPS(ps, runtime, context, args[1], args[2]);
968
960
  ps.executeUpdate();
969
961
  return unmarshal_id_result(runtime, ps.getGeneratedKeys());
970
962
  } finally {
@@ -980,7 +972,8 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
980
972
  /*
981
973
  * sql, values, types, name = nil
982
974
  */
983
- public static IRubyObject update_bind(IRubyObject recv, final IRubyObject[] args) throws SQLException {
975
+ @JRubyMethod(name = "update_bind", required = 3, rest = true)
976
+ public static IRubyObject update_bind(final ThreadContext context, IRubyObject recv, final IRubyObject[] args) throws SQLException {
984
977
  final Ruby runtime = recv.getRuntime();
985
978
  Arity.checkArgumentCount(runtime, args, 3, 4);
986
979
  return withConnectionAndRetry(recv, new SQLBlock() {
@@ -988,7 +981,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
988
981
  PreparedStatement ps = null;
989
982
  try {
990
983
  ps = c.prepareStatement(rubyApi.convertToRubyString(args[0]).toString());
991
- setValuesOnPS(ps, runtime, args[1], args[2]);
984
+ setValuesOnPS(ps, runtime, context, args[1], args[2]);
992
985
  ps.executeUpdate();
993
986
  } finally {
994
987
  try {
@@ -1004,10 +997,10 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
1004
997
  /*
1005
998
  * (is binary?, colname, tablename, primary key, id, value)
1006
999
  */
1000
+ @JRubyMethod(name = "write_large_object", required = 6)
1007
1001
  public static IRubyObject write_large_object(IRubyObject recv, final IRubyObject[] args)
1008
1002
  throws SQLException, IOException {
1009
1003
  final Ruby runtime = recv.getRuntime();
1010
- Arity.checkArgumentCount(runtime, args, 6, 6);
1011
1004
  return withConnectionAndRetry(recv, new SQLBlock() {
1012
1005
  public IRubyObject call(Connection c) throws SQLException {
1013
1006
  String sql = "UPDATE " + rubyApi.convertToRubyString(args[2])
@@ -35,83 +35,76 @@ import org.jruby.RubyBigDecimal;
35
35
  import org.jruby.RubyRange;
36
36
  import org.jruby.RubyNumeric;
37
37
 
38
- import org.jruby.runtime.Arity;
39
- import org.jruby.runtime.CallbackFactory;
40
- import org.jruby.runtime.MethodIndex;
41
38
  import org.jruby.runtime.builtin.IRubyObject;
42
39
 
43
40
  import org.jruby.util.ByteList;
44
41
 
45
42
  import java.sql.SQLException;
46
43
  import org.jruby.RubyObjectAdapter;
44
+ import org.jruby.anno.JRubyMethod;
45
+ import org.jruby.runtime.ThreadContext;
47
46
 
48
47
  public class JdbcDerbySpec {
49
48
  private static RubyObjectAdapter rubyApi;
50
- public static void load(Ruby runtime, RubyModule jdbcSpec, RubyObjectAdapter adapter) {
49
+ public static void load(RubyModule jdbcSpec, RubyObjectAdapter adapter) {
51
50
  RubyModule derby = jdbcSpec.defineModuleUnder("Derby");
52
- CallbackFactory cf = runtime.callbackFactory(JdbcDerbySpec.class);
53
- derby.defineFastMethod("quote_string",cf.getFastSingletonMethod("quote_string",IRubyObject.class));
54
- derby.defineFastMethod("quote",cf.getFastOptSingletonMethod("quote"));
55
- derby.defineFastMethod("_execute",cf.getFastOptSingletonMethod("_execute"));
56
- derby.defineFastMethod("add_limit_offset!",cf.getFastSingletonMethod("add_limit_offset", IRubyObject.class, IRubyObject.class));
57
- derby.defineFastMethod("select_all",cf.getFastOptSingletonMethod("select_all"));
58
- derby.defineFastMethod("select_one",cf.getFastOptSingletonMethod("select_one"));
59
- RubyModule col = derby.defineModuleUnder("Column");
60
- col.defineFastMethod("type_cast",cf.getFastSingletonMethod("type_cast", IRubyObject.class));
51
+ derby.defineAnnotatedMethods(JdbcDerbySpec.class);
52
+ RubyModule column = derby.defineModuleUnder("Column");
53
+ column.defineAnnotatedMethods(Column.class);
61
54
  rubyApi = adapter;
62
55
  }
63
56
 
64
- /*
65
- * JdbcSpec::Derby::Column.type_cast(value)
66
- */
67
- public static IRubyObject type_cast(IRubyObject recv, IRubyObject value) {
68
- Ruby runtime = recv.getRuntime();
57
+ public static class Column {
58
+ @JRubyMethod(name = "type_cast", required = 1)
59
+ public static IRubyObject type_cast(IRubyObject recv, IRubyObject value) {
60
+ Ruby runtime = recv.getRuntime();
69
61
 
70
- if (value.isNil() || ((value instanceof RubyString) && value.toString().trim().equalsIgnoreCase("null"))) {
71
- return runtime.getNil();
72
- }
62
+ if (value.isNil() || ((value instanceof RubyString) && value.toString().trim().equalsIgnoreCase("null"))) {
63
+ return runtime.getNil();
64
+ }
73
65
 
74
- String type = rubyApi.getInstanceVariable(recv,"@type").toString();
66
+ String type = rubyApi.getInstanceVariable(recv, "@type").toString();
75
67
 
76
- switch(type.charAt(0)) {
77
- case 's': //string
78
- return value;
79
- case 't': //text, timestamp, time
80
- if(type.equals("text")) {
81
- return value;
82
- } else {
83
- return rubyApi.callMethod(recv, "cast_to_time", value);
84
- }
85
- case 'i': //integer
86
- case 'p': //primary key
87
- if (value.respondsTo("to_i")) {
88
- return rubyApi.callMethod(value, "to_i");
89
- } else {
90
- return runtime.newFixnum(value.isTrue() ? 1 : 0 );
91
- }
92
- case 'd': //decimal, datetime, date
93
- if(type.equals("datetime")) {
94
- return rubyApi.callMethod(recv, "cast_to_date_or_time", value);
95
- } else if(type.equals("date")) {
96
- return rubyApi.callMethod(recv.getMetaClass(), "string_to_date", value);
97
- } else {
98
- return rubyApi.callMethod(recv.getMetaClass(), "value_to_decimal", value);
99
- }
100
- case 'f': //float
101
- return rubyApi.callMethod(value,"to_f");
102
- case 'b': //binary, boolean
103
- if (type.equals("binary")) {
104
- return rubyApi.callMethod(recv, "value_to_binary", value);
105
- } else {
106
- return rubyApi.callMethod(recv.getMetaClass(), "value_to_boolean", value);
68
+ switch (type.charAt(0)) {
69
+ case 's': //string
70
+ return value;
71
+ case 't': //text, timestamp, time
72
+ if (type.equals("text")) {
73
+ return value;
74
+ } else {
75
+ return rubyApi.callMethod(recv, "cast_to_time", value);
76
+ }
77
+ case 'i': //integer
78
+ case 'p': //primary key
79
+ if (value.respondsTo("to_i")) {
80
+ return rubyApi.callMethod(value, "to_i");
81
+ } else {
82
+ return runtime.newFixnum(value.isTrue() ? 1 : 0);
83
+ }
84
+ case 'd': //decimal, datetime, date
85
+ if (type.equals("datetime")) {
86
+ return rubyApi.callMethod(recv, "cast_to_date_or_time", value);
87
+ } else if (type.equals("date")) {
88
+ return rubyApi.callMethod(recv.getMetaClass(), "string_to_date", value);
89
+ } else {
90
+ return rubyApi.callMethod(recv.getMetaClass(), "value_to_decimal", value);
91
+ }
92
+ case 'f': //float
93
+ return rubyApi.callMethod(value, "to_f");
94
+ case 'b': //binary, boolean
95
+ if (type.equals("binary")) {
96
+ return rubyApi.callMethod(recv, "value_to_binary", value);
97
+ } else {
98
+ return rubyApi.callMethod(recv.getMetaClass(), "value_to_boolean", value);
99
+ }
107
100
  }
101
+ return value;
108
102
  }
109
- return value;
110
103
  }
111
104
 
112
- public static IRubyObject quote(IRubyObject recv, IRubyObject[] args) {
105
+ @JRubyMethod(name = "quote", required = 1, optional = 1)
106
+ public static IRubyObject quote(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
113
107
  Ruby runtime = recv.getRuntime();
114
- Arity.checkArgumentCount(runtime, args, 1, 2);
115
108
  IRubyObject value = args[0];
116
109
  if (args.length > 1) {
117
110
  IRubyObject col = args[1];
@@ -128,21 +121,21 @@ public class JdbcDerbySpec {
128
121
  if (only_digits((RubyString)value)) {
129
122
  return value;
130
123
  } else {
131
- return super_quote(recv, runtime, value, col);
124
+ return super_quote(context, recv, runtime, value, col);
132
125
  }
133
126
  }
134
127
  } else if ((value instanceof RubyFloat) || (value instanceof RubyFixnum) || (value instanceof RubyBignum)) {
135
128
  if (type == runtime.newSymbol("string")) {
136
- return quote_string_with_surround(runtime, "'", RubyString.objAsString(value), "'");
129
+ return quote_string_with_surround(runtime, "'", RubyString.objAsString(context, value), "'");
137
130
  }
138
131
  }
139
132
  }
140
- return super_quote(recv, runtime, value, runtime.getNil());
133
+ return super_quote(context, recv, runtime, value, runtime.getNil());
141
134
  }
142
135
 
143
136
  private final static ByteList NULL = new ByteList("NULL".getBytes());
144
137
 
145
- public static IRubyObject super_quote(IRubyObject recv, Ruby runtime, IRubyObject value, IRubyObject col) {
138
+ private static IRubyObject super_quote(ThreadContext context, IRubyObject recv, Ruby runtime, IRubyObject value, IRubyObject col) {
146
139
  if (value.respondsTo("quoted_id")) {
147
140
  return rubyApi.callMethod(value, "quoted_id");
148
141
  }
@@ -151,11 +144,11 @@ public class JdbcDerbySpec {
151
144
  RubyModule multibyteChars = (RubyModule)
152
145
  ((RubyModule) ((RubyModule) runtime.getModule("ActiveSupport")).getConstant("Multibyte")).getConstantAt("Chars");
153
146
  if (value instanceof RubyString || rubyApi.isKindOf(value, multibyteChars)) {
154
- RubyString svalue = RubyString.objAsString(value);
147
+ RubyString svalue = RubyString.objAsString(context, value);
155
148
  if (type == runtime.newSymbol("binary") && col.getType().respondsTo("string_to_binary")) {
156
149
  return quote_string_with_surround(runtime, "'", (RubyString)(rubyApi.callMethod(col.getType(), "string_to_binary", svalue)), "'");
157
150
  } else if (type == runtime.newSymbol("integer") || type == runtime.newSymbol("float")) {
158
- return RubyString.objAsString(((type == runtime.newSymbol("integer")) ?
151
+ return RubyString.objAsString(context, ((type == runtime.newSymbol("integer")) ?
159
152
  rubyApi.callMethod(svalue, "to_i") :
160
153
  rubyApi.callMethod(svalue, "to_f")));
161
154
  } else {
@@ -168,11 +161,11 @@ public class JdbcDerbySpec {
168
161
  (type == runtime.newSymbol(":integer")) ? runtime.newString("1") : rubyApi.callMethod(recv, "quoted_true") :
169
162
  (type == runtime.newSymbol(":integer")) ? runtime.newString("0") : rubyApi.callMethod(recv, "quoted_false"));
170
163
  } else if((value instanceof RubyFloat) || (value instanceof RubyFixnum) || (value instanceof RubyBignum)) {
171
- return RubyString.objAsString(value);
164
+ return RubyString.objAsString(context, value);
172
165
  } else if(value instanceof RubyBigDecimal) {
173
166
  return rubyApi.callMethod(value, "to_s", runtime.newString("F"));
174
167
  } else if (rubyApi.isKindOf(value, runtime.getModule("Date"))) {
175
- return quote_string_with_surround(runtime, "'", RubyString.objAsString(value), "'");
168
+ return quote_string_with_surround(runtime, "'", RubyString.objAsString(context, value), "'");
176
169
  } else if (rubyApi.isKindOf(value, runtime.getModule("Time")) || rubyApi.isKindOf(value, runtime.getModule("DateTime"))) {
177
170
  return quote_string_with_surround(runtime, "'", (RubyString)(rubyApi.callMethod(recv, "quoted_date", value)), "'");
178
171
  } else {
@@ -182,7 +175,7 @@ public class JdbcDerbySpec {
182
175
 
183
176
  private final static ByteList TWO_SINGLE = new ByteList(new byte[]{'\'','\''});
184
177
 
185
- public static IRubyObject quote_string_with_surround(Ruby runtime, String before, RubyString string, String after) {
178
+ private static IRubyObject quote_string_with_surround(Ruby runtime, String before, RubyString string, String after) {
186
179
  ByteList input = string.getByteList();
187
180
  ByteList output = new ByteList(before.getBytes());
188
181
  for(int i = input.begin; i< input.begin + input.realSize; i++) {
@@ -203,7 +196,7 @@ public class JdbcDerbySpec {
203
196
 
204
197
  private final static byte[] HEX = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
205
198
 
206
- public static IRubyObject hexquote_string_with_surround(Ruby runtime, String before, RubyString string, String after) {
199
+ private static IRubyObject hexquote_string_with_surround(Ruby runtime, String before, RubyString string, String after) {
207
200
  ByteList input = string.getByteList();
208
201
  ByteList output = new ByteList(before.getBytes());
209
202
  for(int i = input.begin; i< input.begin + input.realSize; i++) {
@@ -232,6 +225,7 @@ public class JdbcDerbySpec {
232
225
  return true;
233
226
  }
234
227
 
228
+ @JRubyMethod(name = "quote_string", required = 1)
235
229
  public static IRubyObject quote_string(IRubyObject recv, IRubyObject string) {
236
230
  boolean replacementFound = false;
237
231
  ByteList bl = ((RubyString) string).getByteList();
@@ -259,10 +253,12 @@ public class JdbcDerbySpec {
259
253
  }
260
254
  }
261
255
 
256
+ @JRubyMethod(name = "select_all", rest = true)
262
257
  public static IRubyObject select_all(IRubyObject recv, IRubyObject[] args) {
263
258
  return rubyApi.callMethod(recv, "execute", args);
264
259
  }
265
260
 
261
+ @JRubyMethod(name = "select_one", rest = true)
266
262
  public static IRubyObject select_one(IRubyObject recv, IRubyObject[] args) {
267
263
  IRubyObject limit = rubyApi.getInstanceVariable(recv, "@limit");
268
264
  if (limit == null || limit.isNil()) {
@@ -276,6 +272,7 @@ public class JdbcDerbySpec {
276
272
  }
277
273
  }
278
274
 
275
+ @JRubyMethod(name = "add_limit_offset!", required = 2)
279
276
  public static IRubyObject add_limit_offset(IRubyObject recv, IRubyObject sql, IRubyObject options) {
280
277
  IRubyObject limit = rubyApi.callMethod(options, "[]", recv.getRuntime().newSymbol("limit"));
281
278
  rubyApi.setInstanceVariable(recv, "@limit",limit);
@@ -283,7 +280,8 @@ public class JdbcDerbySpec {
283
280
  return rubyApi.setInstanceVariable(recv, "@offset",offset);
284
281
  }
285
282
 
286
- public static IRubyObject _execute(IRubyObject recv, IRubyObject[] args) throws SQLException, java.io.IOException {
283
+ @JRubyMethod(name = "_execute", required = 1, optional = 1)
284
+ public static IRubyObject _execute(ThreadContext context, IRubyObject recv, IRubyObject[] args) throws SQLException, java.io.IOException {
287
285
  Ruby runtime = recv.getRuntime();
288
286
  try {
289
287
  IRubyObject conn = rubyApi.getInstanceVariable(recv, "@connection");
@@ -302,11 +300,11 @@ public class JdbcDerbySpec {
302
300
  IRubyObject range;
303
301
  IRubyObject max;
304
302
  if (limit == null || limit.isNil() || RubyNumeric.fix2int(limit) == -1) {
305
- range = RubyRange.newRange(runtime, offset, runtime.newFixnum(-1), false);
303
+ range = RubyRange.newRange(runtime, context, offset, runtime.newFixnum(-1), false);
306
304
  max = RubyFixnum.zero(runtime);
307
305
  } else {
308
306
  IRubyObject v1 = rubyApi.callMethod(offset, "+", limit);
309
- range = RubyRange.newRange(runtime, offset, v1, true);
307
+ range = RubyRange.newRange(runtime, context, offset, v1, true);
310
308
  max = rubyApi.callMethod(v1, "+", RubyFixnum.one(runtime));
311
309
  }
312
310
  IRubyObject result = JdbcAdapterInternalService.execute_query(conn, new IRubyObject[]{args[0], max});
@@ -28,16 +28,15 @@ import org.jruby.Ruby;
28
28
  import org.jruby.RubyModule;
29
29
  import org.jruby.RubyString;
30
30
 
31
- import org.jruby.runtime.CallbackFactory;
31
+ import org.jruby.anno.JRubyMethod;
32
32
  import org.jruby.runtime.builtin.IRubyObject;
33
33
 
34
34
  import org.jruby.util.ByteList;
35
35
 
36
36
  public class JdbcMySQLSpec {
37
- public static void load(Ruby runtime, RubyModule jdbcSpec) {
37
+ public static void load(RubyModule jdbcSpec) {
38
38
  RubyModule mysql = jdbcSpec.defineModuleUnder("MySQL");
39
- CallbackFactory cf = runtime.callbackFactory(JdbcMySQLSpec.class);
40
- mysql.defineFastMethod("quote_string",cf.getFastSingletonMethod("quote_string",IRubyObject.class));
39
+ mysql.defineAnnotatedMethods(JdbcMySQLSpec.class);
41
40
  }
42
41
 
43
42
  private final static ByteList ZERO = new ByteList(new byte[]{'\\','0'});
@@ -48,9 +47,11 @@ public class JdbcMySQLSpec {
48
47
  private final static ByteList SINGLE = new ByteList(new byte[]{'\\','\''});
49
48
  private final static ByteList ESCAPE = new ByteList(new byte[]{'\\','\\'});
50
49
 
50
+ @JRubyMethod(name = "quote_string", required = 1)
51
51
  public static IRubyObject quote_string(IRubyObject recv, IRubyObject string) {
52
- boolean replacementFound = false;
53
52
  ByteList bl = ((RubyString) string).getByteList();
53
+ ByteList blNew = new ByteList();
54
+ int startOfExtend = bl.begin;
54
55
 
55
56
  for(int i = bl.begin; i < bl.begin + bl.realSize; i++) {
56
57
  ByteList rep = null;
@@ -64,23 +65,18 @@ public class JdbcMySQLSpec {
64
65
  case '\\': rep = ESCAPE; break;
65
66
  default: continue;
66
67
  }
67
-
68
- // On first replacement allocate a different bytelist so we don't manip original
69
- if(!replacementFound) {
70
- i-= bl.begin;
71
- bl = new ByteList(bl);
72
- replacementFound = true;
73
- }
74
-
75
- bl.replace(i, 1, rep);
76
- i+=1;
68
+ if(i > startOfExtend)
69
+ blNew.append(bl, startOfExtend, i-startOfExtend);
70
+ blNew.append(rep, 0, 2);
71
+ startOfExtend = i+1;
77
72
  }
78
-
79
- if(!replacementFound) {
80
- return string;
73
+ // Nothing changed, can return original
74
+ if (startOfExtend == bl.begin) {
75
+ return string;
81
76
  }
77
+ if (bl.begin + bl.realSize > startOfExtend)
78
+ blNew.append(bl, startOfExtend, bl.begin + bl.realSize - startOfExtend);
82
79
 
83
-
84
- return recv.getRuntime().newStringShared(bl);
80
+ return recv.getRuntime().newStringShared(blNew);
85
81
  }
86
82
  }
@@ -13,6 +13,5 @@ ActiveRecord::Base.logger = logger
13
13
  at_exit {
14
14
  # Clean up derby files
15
15
  require 'fileutils'
16
- Dir.glob('derby-testdb/**/*') {|f| File.delete(f)}
17
16
  FileUtils.rm_rf('derby-testdb')
18
17
  }
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'active_record'
3
+
4
+ class CreateReservedWords < ActiveRecord::Migration
5
+ def self.up
6
+ create_table "reserved_words", :force => true do |t|
7
+ t.column :position, :integer
8
+ t.column :select, :integer
9
+ end
10
+ end
11
+
12
+ def self.down
13
+ drop_table "reserved_words"
14
+ end
15
+ end
16
+
17
+ class ReservedWord < ActiveRecord::Base
18
+ end
@@ -0,0 +1,22 @@
1
+ require 'jdbc_common'
2
+ require 'db/postgres'
3
+ require 'models/reserved_word'
4
+
5
+ class PostgresReservedWordsTest < Test::Unit::TestCase
6
+ def setup
7
+ CreateReservedWords.up
8
+ end
9
+ def teardown
10
+ CreateReservedWords.down
11
+ end
12
+
13
+ def test_quote_reserved_word_column
14
+ columns = ReservedWord.column_names - ["id"]
15
+ ReservedWord.connection.add_index :reserved_words, columns
16
+ indexes = ReservedWord.connection.indexes("reserved_words")
17
+ assert_equal 1, indexes.size
18
+ columns.each do |c|
19
+ assert indexes[0].columns.include?(c), "#{indexes[0].columns.inspect} does not include #{c.inspect}"
20
+ end
21
+ end
22
+ end
@@ -87,7 +87,7 @@ module SimpleTestMethods
87
87
 
88
88
  indexes = @connection.indexes(:entries)
89
89
  assert_equal(1, indexes.size)
90
- assert_equal "entries", indexes.first.table
90
+ assert_equal "entries", indexes.first.table.to_s
91
91
  assert_equal index_name, indexes.first.name
92
92
  assert !indexes.first.unique
93
93
  assert_equal ["updated_on"], indexes.first.columns
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-jdbc-adapter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.2
4
+ version: "0.8"
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Sieger, Ola Bini and JRuby contributors
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-02-12 00:00:00 -06:00
12
+ date: 2008-03-19 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -23,12 +23,13 @@ extra_rdoc_files:
23
23
  - History.txt
24
24
  - Manifest.txt
25
25
  - README.txt
26
+ - LICENSE.txt
26
27
  files:
27
28
  - History.txt
28
29
  - Manifest.txt
29
30
  - README.txt
30
31
  - Rakefile
31
- - LICENSE
32
+ - LICENSE.txt
32
33
  - lib/active_record/connection_adapters/derby_adapter.rb
33
34
  - lib/active_record/connection_adapters/h2_adapter.rb
34
35
  - lib/active_record/connection_adapters/hsqldb_adapter.rb
@@ -86,11 +87,14 @@ files:
86
87
  - test/models/auto_id.rb
87
88
  - test/models/data_types.rb
88
89
  - test/models/entry.rb
90
+ - test/models/reserved_word.rb
89
91
  - test/mysql_multibyte_test.rb
90
92
  - test/mysql_simple_test.rb
91
93
  - test/oracle_simple_test.rb
94
+ - test/postgres_reserved_test.rb
92
95
  - test/postgres_simple_test.rb
93
96
  - test/simple.rb
97
+ - lib/jdbc_adapter/jdbc.rake
94
98
  - src/java/jdbc_adapter/JdbcAdapterInternalService.java
95
99
  - src/java/jdbc_adapter/JdbcConnectionFactory.java
96
100
  - src/java/jdbc_adapter/JdbcDerbySpec.java