activerecord-jdbc-adapter 70.0.pre-java → 70.1-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +1 -1
- data/activerecord-jdbc-adapter.gemspec +1 -3
- data/lib/arel/visitors/compat.rb +5 -33
- data/lib/arel/visitors/h2.rb +1 -13
- data/lib/arel/visitors/hsqldb.rb +1 -21
- data/lib/arel/visitors/sql_server.rb +2 -103
- data/lib/arjdbc/abstract/core.rb +8 -9
- data/lib/arjdbc/abstract/database_statements.rb +8 -0
- data/lib/arjdbc/discover.rb +0 -67
- data/lib/arjdbc/jdbc/adapter.rb +1 -1
- data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
- data/lib/arjdbc/jdbc/column.rb +1 -26
- data/lib/arjdbc/jdbc.rb +0 -7
- data/lib/arjdbc/mysql/adapter.rb +2 -1
- data/lib/arjdbc/oracle/adapter.rb +4 -23
- data/lib/arjdbc/postgresql/adapter.rb +152 -3
- data/lib/arjdbc/postgresql/oid_types.rb +155 -108
- data/lib/arjdbc/sqlite3/adapter.rb +54 -36
- data/lib/arjdbc/tasks/database_tasks.rb +0 -15
- data/lib/arjdbc/util/serialized_attributes.rb +0 -22
- data/lib/arjdbc/util/table_copier.rb +2 -1
- data/lib/arjdbc/version.rb +1 -1
- data/rakelib/02-test.rake +3 -18
- data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +5 -0
- data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +5 -0
- metadata +5 -38
- data/lib/active_record/connection_adapters/as400_adapter.rb +0 -2
- data/lib/active_record/connection_adapters/db2_adapter.rb +0 -1
- data/lib/active_record/connection_adapters/derby_adapter.rb +0 -1
- data/lib/active_record/connection_adapters/informix_adapter.rb +0 -1
- data/lib/arel/visitors/db2.rb +0 -137
- data/lib/arel/visitors/derby.rb +0 -112
- data/lib/arel/visitors/firebird.rb +0 -79
- data/lib/arjdbc/db2/adapter.rb +0 -808
- data/lib/arjdbc/db2/as400.rb +0 -142
- data/lib/arjdbc/db2/column.rb +0 -131
- data/lib/arjdbc/db2/connection_methods.rb +0 -48
- data/lib/arjdbc/db2.rb +0 -4
- data/lib/arjdbc/derby/active_record_patch.rb +0 -13
- data/lib/arjdbc/derby/adapter.rb +0 -521
- data/lib/arjdbc/derby/connection_methods.rb +0 -20
- data/lib/arjdbc/derby/schema_creation.rb +0 -15
- data/lib/arjdbc/derby.rb +0 -3
- data/lib/arjdbc/firebird/adapter.rb +0 -413
- data/lib/arjdbc/firebird/connection_methods.rb +0 -23
- data/lib/arjdbc/firebird.rb +0 -4
- data/lib/arjdbc/informix/adapter.rb +0 -139
- data/lib/arjdbc/informix/connection_methods.rb +0 -9
- data/lib/arjdbc/sybase/adapter.rb +0 -47
- data/lib/arjdbc/sybase.rb +0 -2
- data/lib/arjdbc/tasks/db2_database_tasks.rb +0 -104
- data/lib/arjdbc/tasks/derby_database_tasks.rb +0 -95
- data/src/java/arjdbc/derby/DerbyModule.java +0 -178
- data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +0 -152
- data/src/java/arjdbc/firebird/FirebirdRubyJdbcConnection.java +0 -174
- data/src/java/arjdbc/informix/InformixRubyJdbcConnection.java +0 -75
@@ -1,104 +0,0 @@
|
|
1
|
-
require 'arjdbc/tasks/jdbc_database_tasks'
|
2
|
-
|
3
|
-
module ArJdbc
|
4
|
-
module Tasks
|
5
|
-
class DB2DatabaseTasks < JdbcDatabaseTasks
|
6
|
-
|
7
|
-
def create
|
8
|
-
raise "AR-JDBC adapter 'DB2' does not support create_database"
|
9
|
-
end
|
10
|
-
|
11
|
-
def purge
|
12
|
-
establish_connection(config)
|
13
|
-
connection.recreate_database
|
14
|
-
end
|
15
|
-
|
16
|
-
# NOTE: does not work correctly (on non AS400) due driver meta data issue
|
17
|
-
#
|
18
|
-
# also try db2move e.g. `db2move SAMPLE EXPORT -sn db2inst`
|
19
|
-
# - where SAMPLE is the database name
|
20
|
-
# - and -sn specified schema name
|
21
|
-
#
|
22
|
-
|
23
|
-
def structure_dump(filename)
|
24
|
-
establish_connection(config)
|
25
|
-
dump = File.open(filename, "w:utf-8")
|
26
|
-
|
27
|
-
schema_name = connection.schema.upcase if connection.schema
|
28
|
-
meta_data = connection.jdbc_connection.meta_data
|
29
|
-
tables_rs = meta_data.getTables(nil, schema_name, nil, ["TABLE"].to_java(:String))
|
30
|
-
|
31
|
-
have_scale = ArJdbc::DB2::HAVE_SCALE
|
32
|
-
have_precision = ArJdbc::DB2::HAVE_LIMIT + ArJdbc::DB2::HAVE_LIMIT
|
33
|
-
|
34
|
-
while tables_rs.next
|
35
|
-
table_name = tables_rs.getString('TABLE_NAME')
|
36
|
-
dump << "CREATE TABLE #{connection.quote_table_name(table_name)} (\n"
|
37
|
-
|
38
|
-
cols_rs = meta_data.getColumns(nil, schema_name, table_name, nil)
|
39
|
-
begin
|
40
|
-
first_col = true
|
41
|
-
while cols_rs.next
|
42
|
-
column_name = cols_rs.getString(4)
|
43
|
-
default = cols_rs.getString(13)
|
44
|
-
default = default.empty? ? "" : " DEFAULT #{default}" if default
|
45
|
-
type = cols_rs.getString(6)
|
46
|
-
precision, scale = cols_rs.getString(7), cols_rs.getString(9)
|
47
|
-
column_size = ""
|
48
|
-
if scale && have_scale.include?(type)
|
49
|
-
column_size = "(#{precision},#{scale})"
|
50
|
-
elsif precision && have_precision.include?(type)
|
51
|
-
column_size = "(#{precision})"
|
52
|
-
end
|
53
|
-
nulling = ( cols_rs.getString(18) == 'NO' ? " NOT NULL" : nil )
|
54
|
-
autoinc = ( cols_rs.getString(23) == 'YES' ? " GENERATED ALWAYS AS IDENTITY" : nil )
|
55
|
-
|
56
|
-
create_column = connection.quote_column_name(column_name)
|
57
|
-
create_column << " #{type}"
|
58
|
-
create_column << column_size
|
59
|
-
create_column << nulling.to_s
|
60
|
-
create_column << default.to_s
|
61
|
-
create_column << autoinc.to_s
|
62
|
-
|
63
|
-
create_column = first_col ? " #{create_column}" : ",\n #{create_column}"
|
64
|
-
dump << create_column
|
65
|
-
|
66
|
-
first_col = false
|
67
|
-
end
|
68
|
-
ensure
|
69
|
-
cols_rs.close
|
70
|
-
end
|
71
|
-
|
72
|
-
dump << "\n);\n\n"
|
73
|
-
|
74
|
-
pk_rs = meta_data.getPrimaryKeys(nil, schema_name, table_name)
|
75
|
-
primary_keys = {}
|
76
|
-
begin
|
77
|
-
while pk_rs.next
|
78
|
-
name = pk_rs.getString(6)
|
79
|
-
primary_keys[name] ||= []
|
80
|
-
primary_keys[name] << pk_rs.getString(4)
|
81
|
-
end
|
82
|
-
ensure
|
83
|
-
pk_rs.close
|
84
|
-
end
|
85
|
-
primary_keys.each do |constraint_name, cols|
|
86
|
-
dump << "ALTER TABLE #{connection.quote_table_name(table_name)}\n"
|
87
|
-
dump << " ADD CONSTRAINT #{constraint_name}\n"
|
88
|
-
dump << " PRIMARY KEY (#{cols.join(', ')});\n\n"
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
dump.close
|
93
|
-
end
|
94
|
-
|
95
|
-
def structure_load(filename)
|
96
|
-
establish_connection(config)
|
97
|
-
IO.read(filename).split(/;\n*/m).each do |ddl|
|
98
|
-
connection.execute ddl.sub(/;$/, '')
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
@@ -1,95 +0,0 @@
|
|
1
|
-
require 'arjdbc/tasks/jdbc_database_tasks'
|
2
|
-
|
3
|
-
module ArJdbc
|
4
|
-
module Tasks
|
5
|
-
class DerbyDatabaseTasks < JdbcDatabaseTasks
|
6
|
-
|
7
|
-
def create
|
8
|
-
establish_connection(config)
|
9
|
-
ActiveRecord::Base.connection
|
10
|
-
end
|
11
|
-
|
12
|
-
def drop
|
13
|
-
db_dir = expand_path resolve_database(config, true)
|
14
|
-
if File.exist?(db_dir)
|
15
|
-
FileUtils.rm_r(db_dir)
|
16
|
-
FileUtils.rmdir(db_dir) rescue nil
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
SIZEABLE = %w( VARCHAR CLOB BLOB )
|
21
|
-
|
22
|
-
def structure_dump(filename)
|
23
|
-
establish_connection(config)
|
24
|
-
dump = File.open(filename, "w:utf-8")
|
25
|
-
|
26
|
-
meta_data = connection.jdbc_connection.meta_data
|
27
|
-
tables_rs = meta_data.getTables(nil, nil, nil, ["TABLE"].to_java(:String))
|
28
|
-
|
29
|
-
while tables_rs.next
|
30
|
-
table_name = tables_rs.getString('TABLE_NAME') # getString(3)
|
31
|
-
dump << "CREATE TABLE #{connection.quote_table_name(table_name)} (\n"
|
32
|
-
|
33
|
-
columns_rs = meta_data.getColumns(nil, nil, table_name, nil)
|
34
|
-
first_col = true
|
35
|
-
while columns_rs.next
|
36
|
-
column_name = columns_rs.getString(4)
|
37
|
-
default = columns_rs.getString(13)
|
38
|
-
if default =~ /^GENERATED_/
|
39
|
-
default = column_auto_increment_def(table_name, column_name)
|
40
|
-
elsif default
|
41
|
-
default = " DEFAULT #{default}"
|
42
|
-
end
|
43
|
-
type = columns_rs.getString(6)
|
44
|
-
column_size = columns_rs.getString(7)
|
45
|
-
nulling = ( columns_rs.getString(18) == 'NO' ? " NOT NULL" : nil )
|
46
|
-
|
47
|
-
create_column = connection.quote_column_name(column_name)
|
48
|
-
create_column << " #{type}"
|
49
|
-
create_column << ( SIZEABLE.include?(type) ? "(#{column_size})" : "" )
|
50
|
-
create_column << nulling.to_s
|
51
|
-
create_column << default.to_s
|
52
|
-
|
53
|
-
create_column = first_col ? " #{create_column}" : ",\n #{create_column}"
|
54
|
-
dump << create_column
|
55
|
-
|
56
|
-
first_col = false
|
57
|
-
end
|
58
|
-
dump << "\n);\n\n"
|
59
|
-
end
|
60
|
-
|
61
|
-
dump.close
|
62
|
-
end
|
63
|
-
|
64
|
-
def structure_load(filename)
|
65
|
-
establish_connection(config)
|
66
|
-
IO.read(filename).split(/;\n*/m).each { |ddl| connection.execute(ddl) }
|
67
|
-
end
|
68
|
-
|
69
|
-
private
|
70
|
-
|
71
|
-
AUTO_INCREMENT_SQL = '' <<
|
72
|
-
"SELECT AUTOINCREMENTSTART, AUTOINCREMENTINC, COLUMNNAME, REFERENCEID, COLUMNDEFAULT " <<
|
73
|
-
"FROM SYS.SYSCOLUMNS WHERE REFERENCEID = " <<
|
74
|
-
"(SELECT T.TABLEID FROM SYS.SYSTABLES T WHERE T.TABLENAME = '%s') AND COLUMNNAME = '%s'"
|
75
|
-
|
76
|
-
def column_auto_increment_def(table_name, column_name)
|
77
|
-
sql = AUTO_INCREMENT_SQL % [ table_name, column_name ]
|
78
|
-
if data = connection.execute(sql).first
|
79
|
-
if start = data['autoincrementstart']
|
80
|
-
ai_def = ' GENERATED '
|
81
|
-
ai_def << ( data['columndefault'].nil? ? "ALWAYS" : "BY DEFAULT " )
|
82
|
-
ai_def << "AS IDENTITY (START WITH "
|
83
|
-
ai_def << start.to_s
|
84
|
-
ai_def << ", INCREMENT BY "
|
85
|
-
ai_def << data['autoincrementinc'].to_s
|
86
|
-
ai_def << ")"
|
87
|
-
return ai_def
|
88
|
-
end
|
89
|
-
end
|
90
|
-
''
|
91
|
-
end
|
92
|
-
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
@@ -1,178 +0,0 @@
|
|
1
|
-
/***** BEGIN LICENSE BLOCK *****
|
2
|
-
* Copyright (c) 2012-2013 Karol Bucek <self@kares.org>
|
3
|
-
* Copyright (c) 2006-2011 Nick Sieger <nick@nicksieger.com>
|
4
|
-
* Copyright (c) 2006-2007 Ola Bini <ola.bini@gmail.com>
|
5
|
-
*
|
6
|
-
* Permission is hereby granted, free of charge, to any person obtaining
|
7
|
-
* a copy of this software and associated documentation files (the
|
8
|
-
* "Software"), to deal in the Software without restriction, including
|
9
|
-
* without limitation the rights to use, copy, modify, merge, publish,
|
10
|
-
* distribute, sublicense, and/or sell copies of the Software, and to
|
11
|
-
* permit persons to whom the Software is furnished to do so, subject to
|
12
|
-
* the following conditions:
|
13
|
-
*
|
14
|
-
* The above copyright notice and this permission notice shall be
|
15
|
-
* included in all copies or substantial portions of the Software.
|
16
|
-
*
|
17
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
18
|
-
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
19
|
-
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
20
|
-
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
21
|
-
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
22
|
-
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
23
|
-
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
24
|
-
***** END LICENSE BLOCK *****/
|
25
|
-
|
26
|
-
package arjdbc.derby;
|
27
|
-
|
28
|
-
import static arjdbc.util.QuotingUtils.BYTES_0;
|
29
|
-
import static arjdbc.util.QuotingUtils.BYTES_1;
|
30
|
-
import static arjdbc.util.QuotingUtils.BYTES_SINGLE_Q_x2;
|
31
|
-
|
32
|
-
import org.jruby.Ruby;
|
33
|
-
import org.jruby.RubyModule;
|
34
|
-
import org.jruby.RubyString;
|
35
|
-
import org.jruby.anno.JRubyMethod;
|
36
|
-
import org.jruby.runtime.ThreadContext;
|
37
|
-
import org.jruby.runtime.builtin.IRubyObject;
|
38
|
-
import org.jruby.util.ByteList;
|
39
|
-
|
40
|
-
public class DerbyModule {
|
41
|
-
|
42
|
-
public static RubyModule load(final RubyModule arJdbc) {
|
43
|
-
RubyModule derby = arJdbc.defineModuleUnder("Derby");
|
44
|
-
derby.defineAnnotatedMethods( DerbyModule.class );
|
45
|
-
RubyModule column = derby.defineModuleUnder("Column");
|
46
|
-
column.defineAnnotatedMethods(Column.class);
|
47
|
-
return derby;
|
48
|
-
}
|
49
|
-
|
50
|
-
public static RubyModule load(final Ruby runtime) {
|
51
|
-
return load( arjdbc.ArJdbcModule.get(runtime) );
|
52
|
-
}
|
53
|
-
|
54
|
-
public static class Column {
|
55
|
-
|
56
|
-
@JRubyMethod(name = "type_cast", required = 1)
|
57
|
-
public static IRubyObject type_cast(final ThreadContext context,
|
58
|
-
final IRubyObject self, final IRubyObject value) {
|
59
|
-
|
60
|
-
if ( value.isNil() ||
|
61
|
-
( (value instanceof RubyString) && value.toString().trim().equalsIgnoreCase("null") ) ) {
|
62
|
-
return context.nil;
|
63
|
-
}
|
64
|
-
|
65
|
-
final String type = self.getInstanceVariables().getInstanceVariable("@type").toString();
|
66
|
-
|
67
|
-
switch (type.charAt(0)) {
|
68
|
-
case 's': //string
|
69
|
-
return value;
|
70
|
-
case 't': //text, timestamp, time
|
71
|
-
if ( type.equals("time") ) {
|
72
|
-
return self.getMetaClass().callMethod(context, "string_to_dummy_time", value);
|
73
|
-
}
|
74
|
-
if ( type.equals("timestamp") ) {
|
75
|
-
return self.getMetaClass().callMethod(context, "string_to_time", value);
|
76
|
-
}
|
77
|
-
return value; // text
|
78
|
-
case 'i': //integer
|
79
|
-
case 'p': //primary key
|
80
|
-
if ( value.respondsTo("to_i") ) {
|
81
|
-
return value.callMethod(context, "to_i");
|
82
|
-
}
|
83
|
-
return context.getRuntime().newFixnum( value.isTrue() ? 1 : 0 );
|
84
|
-
case 'd': //decimal, datetime, date
|
85
|
-
if ( type.equals("datetime") ) {
|
86
|
-
return self.getMetaClass().callMethod(context, "string_to_time", value);
|
87
|
-
}
|
88
|
-
if ( type.equals("date") ) {
|
89
|
-
return self.getMetaClass().callMethod(context, "string_to_date", value);
|
90
|
-
}
|
91
|
-
return self.getMetaClass().callMethod(context, "value_to_decimal", value);
|
92
|
-
case 'f': //float
|
93
|
-
return value.callMethod(context, "to_f");
|
94
|
-
case 'b': //binary, boolean
|
95
|
-
return type.equals("binary") ?
|
96
|
-
self.getMetaClass().callMethod(context, "binary_to_string", value) :
|
97
|
-
self.getMetaClass().callMethod(context, "value_to_boolean", value) ;
|
98
|
-
}
|
99
|
-
return value;
|
100
|
-
}
|
101
|
-
|
102
|
-
}
|
103
|
-
|
104
|
-
@JRubyMethod(name = "quote_binary", required = 1)
|
105
|
-
public static IRubyObject quote_binary(final ThreadContext context,
|
106
|
-
final IRubyObject self, final IRubyObject string) {
|
107
|
-
final byte[] empty = ByteList.NULL_ARRAY; // ""
|
108
|
-
return quoteStringHex(context.runtime, empty, string, empty);
|
109
|
-
}
|
110
|
-
|
111
|
-
private final static byte[] HEX = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
|
112
|
-
|
113
|
-
private static RubyString quoteStringHex(final Ruby runtime,
|
114
|
-
final byte[] before, final IRubyObject string, final byte[] after) {
|
115
|
-
|
116
|
-
final ByteList input = ((RubyString) string).getByteList();
|
117
|
-
final int size = input.getRealSize();
|
118
|
-
final ByteList output = new ByteList( before.length + size * 2 + after.length );
|
119
|
-
output.append( before );
|
120
|
-
|
121
|
-
final byte[] inputBytes = input.unsafeBytes();
|
122
|
-
|
123
|
-
int written = 0;
|
124
|
-
for (int i = input.getBegin(); i < input.getBegin() + size; i++) {
|
125
|
-
final byte b = inputBytes[i];
|
126
|
-
byte h = HEX[ ( ((char) b) >> 4 ) % 16 ];
|
127
|
-
byte l = HEX[ ( (char) b ) % 16 ];
|
128
|
-
output.append(h).append(l);
|
129
|
-
written += 2;
|
130
|
-
if ( written >= 16334 ) { // max hex length = 16334
|
131
|
-
output.append("'||X'".getBytes());
|
132
|
-
written = 0;
|
133
|
-
}
|
134
|
-
}
|
135
|
-
|
136
|
-
output.append( after );
|
137
|
-
return RubyString.newString(runtime, output);
|
138
|
-
}
|
139
|
-
|
140
|
-
@JRubyMethod(name = "quote_string", required = 1)
|
141
|
-
public static IRubyObject quote_string(final IRubyObject self, IRubyObject string) {
|
142
|
-
if ( ! ( string instanceof RubyString ) ) {
|
143
|
-
string = string.asString(); // e.g. Multibyte::Chars
|
144
|
-
}
|
145
|
-
|
146
|
-
ByteList bytes = ((RubyString) string).getByteList();
|
147
|
-
|
148
|
-
boolean newBytes = false;
|
149
|
-
for ( int i = 0; i < bytes.length(); i++ ) {
|
150
|
-
switch ( bytes.get(i) ) {
|
151
|
-
case '\'': break;
|
152
|
-
default: continue;
|
153
|
-
}
|
154
|
-
// on first replacement allocate so we don't manip original
|
155
|
-
if ( ! newBytes ) {
|
156
|
-
bytes = new ByteList(bytes);
|
157
|
-
newBytes = true;
|
158
|
-
}
|
159
|
-
bytes.replace(i, 1, BYTES_SINGLE_Q_x2);
|
160
|
-
i += 1;
|
161
|
-
}
|
162
|
-
|
163
|
-
return newBytes ? RubyString.newString(self.getRuntime(), bytes) : string;
|
164
|
-
}
|
165
|
-
|
166
|
-
@JRubyMethod(name = "quoted_true", required = 0, frame = false)
|
167
|
-
public static RubyString quoted_true(
|
168
|
-
final ThreadContext context, final IRubyObject self) {
|
169
|
-
return RubyString.newStringShared(context.runtime, BYTES_1);
|
170
|
-
}
|
171
|
-
|
172
|
-
@JRubyMethod(name = "quoted_false", required = 0, frame = false)
|
173
|
-
public static RubyString quoted_false(
|
174
|
-
final ThreadContext context, final IRubyObject self) {
|
175
|
-
return RubyString.newStringShared(context.runtime, BYTES_0);
|
176
|
-
}
|
177
|
-
|
178
|
-
}
|
@@ -1,152 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
* The MIT License
|
3
|
-
*
|
4
|
-
* Copyright 2013 Karol Bucek.
|
5
|
-
*
|
6
|
-
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
-
* of this software and associated documentation files (the "Software"), to deal
|
8
|
-
* in the Software without restriction, including without limitation the rights
|
9
|
-
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
-
* copies of the Software, and to permit persons to whom the Software is
|
11
|
-
* furnished to do so, subject to the following conditions:
|
12
|
-
*
|
13
|
-
* The above copyright notice and this permission notice shall be included in
|
14
|
-
* all copies or substantial portions of the Software.
|
15
|
-
*
|
16
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
-
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
-
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
-
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
-
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22
|
-
* THE SOFTWARE.
|
23
|
-
*/
|
24
|
-
package arjdbc.derby;
|
25
|
-
|
26
|
-
import arjdbc.jdbc.Callable;
|
27
|
-
import arjdbc.jdbc.DriverWrapper;
|
28
|
-
import arjdbc.jdbc.RubyJdbcConnection;
|
29
|
-
|
30
|
-
import java.sql.Connection;
|
31
|
-
import java.sql.PreparedStatement;
|
32
|
-
import java.sql.ResultSet;
|
33
|
-
import java.sql.SQLException;
|
34
|
-
|
35
|
-
import org.jruby.Ruby;
|
36
|
-
import org.jruby.RubyBoolean;
|
37
|
-
import org.jruby.RubyClass;
|
38
|
-
import org.jruby.RubyString;
|
39
|
-
import org.jruby.anno.JRubyMethod;
|
40
|
-
import org.jruby.exceptions.RaiseException;
|
41
|
-
import org.jruby.runtime.ObjectAllocator;
|
42
|
-
import org.jruby.runtime.ThreadContext;
|
43
|
-
import org.jruby.runtime.builtin.IRubyObject;
|
44
|
-
import org.jruby.util.ByteList;
|
45
|
-
|
46
|
-
/**
|
47
|
-
* ArJdbc::DerbyJdbcConnection
|
48
|
-
*
|
49
|
-
* @author kares
|
50
|
-
*/
|
51
|
-
public class DerbyRubyJdbcConnection extends RubyJdbcConnection {
|
52
|
-
private static final long serialVersionUID = 4809475910953623325L;
|
53
|
-
|
54
|
-
public DerbyRubyJdbcConnection(Ruby runtime, RubyClass metaClass) {
|
55
|
-
super(runtime, metaClass);
|
56
|
-
}
|
57
|
-
|
58
|
-
public static RubyClass createDerbyJdbcConnectionClass(Ruby runtime, RubyClass jdbcConnection) {
|
59
|
-
final RubyClass clazz = getConnectionAdapters(runtime). // ActiveRecord::ConnectionAdapters
|
60
|
-
defineClassUnder("DerbyJdbcConnection", jdbcConnection, ALLOCATOR);
|
61
|
-
clazz.defineAnnotatedMethods(DerbyRubyJdbcConnection.class);
|
62
|
-
return clazz;
|
63
|
-
}
|
64
|
-
|
65
|
-
public static RubyClass load(final Ruby runtime) {
|
66
|
-
RubyClass jdbcConnection = getJdbcConnection(runtime);
|
67
|
-
return createDerbyJdbcConnectionClass(runtime, jdbcConnection);
|
68
|
-
}
|
69
|
-
|
70
|
-
protected static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
|
71
|
-
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
|
72
|
-
return new DerbyRubyJdbcConnection(runtime, klass);
|
73
|
-
}
|
74
|
-
};
|
75
|
-
|
76
|
-
@Override
|
77
|
-
protected DriverWrapper newDriverWrapper(final ThreadContext context, final String driver) {
|
78
|
-
DriverWrapper driverWrapper = super.newDriverWrapper(context, driver);
|
79
|
-
|
80
|
-
final java.sql.Driver jdbcDriver = driverWrapper.getDriverInstance();
|
81
|
-
if ( jdbcDriver.getClass().getName().startsWith("org.apache.derby.") ) {
|
82
|
-
final int major = jdbcDriver.getMajorVersion();
|
83
|
-
final int minor = jdbcDriver.getMinorVersion();
|
84
|
-
if ( major < 10 || ( major == 10 && minor < 5 ) ) {
|
85
|
-
final RubyClass errorClass = getConnectionNotEstablished(context.runtime);
|
86
|
-
throw context.runtime.newRaiseException(errorClass,
|
87
|
-
"adapter requires Derby >= 10.5 got: " + major + "." + minor + "");
|
88
|
-
}
|
89
|
-
if ( major == 10 && minor < 8 ) { // 10.8 ~ supports JDBC 4.1
|
90
|
-
// config[:connection_alive_sql] ||= 'SELECT 1 FROM SYS.SYSSCHEMAS FETCH FIRST 1 ROWS ONLY'
|
91
|
-
setConfigValueIfNotSet(context, "connection_alive_sql", // FROM clause mandatory
|
92
|
-
context.runtime.newString("SELECT 1 FROM SYS.SYSSCHEMAS FETCH FIRST 1 ROWS ONLY"));
|
93
|
-
}
|
94
|
-
}
|
95
|
-
|
96
|
-
return driverWrapper;
|
97
|
-
}
|
98
|
-
|
99
|
-
@JRubyMethod(name = "select?", required = 1, meta = true, frame = false)
|
100
|
-
public static RubyBoolean select_p(final ThreadContext context,
|
101
|
-
final IRubyObject self, final IRubyObject sql) {
|
102
|
-
final RubyString sqlStr = sql.asString();
|
103
|
-
if ( isValues(sqlStr) ) return context.runtime.getTrue();
|
104
|
-
return arjdbc.jdbc.RubyJdbcConnection.select_p(context, self, sqlStr);
|
105
|
-
}
|
106
|
-
|
107
|
-
// Derby supports 'stand-alone' VALUES expressions
|
108
|
-
private static final byte[] VALUES = new byte[]{ 'v','a','l','u','e','s' };
|
109
|
-
|
110
|
-
private static boolean isValues(final RubyString sql) {
|
111
|
-
final ByteList sqlBytes = sql.getByteList();
|
112
|
-
return startsWithIgnoreCase(sqlBytes, VALUES);
|
113
|
-
}
|
114
|
-
|
115
|
-
@JRubyMethod(name = {"identity_val_local", "last_insert_id"})
|
116
|
-
public IRubyObject identity_val_local(final ThreadContext context)
|
117
|
-
throws SQLException {
|
118
|
-
return withConnection(context, new Callable<IRubyObject>() {
|
119
|
-
public IRubyObject call(final Connection connection) throws SQLException {
|
120
|
-
PreparedStatement statement = null; ResultSet genKeys = null;
|
121
|
-
try {
|
122
|
-
statement = connection.prepareStatement("values IDENTITY_VAL_LOCAL()");
|
123
|
-
genKeys = statement.executeQuery();
|
124
|
-
return doMapGeneratedKeys(context.getRuntime(), genKeys, true);
|
125
|
-
}
|
126
|
-
catch (final SQLException e) {
|
127
|
-
debugMessage(context.runtime, "failed to get generated keys: ", e);
|
128
|
-
throw e;
|
129
|
-
}
|
130
|
-
finally { close(genKeys); close(statement); }
|
131
|
-
}
|
132
|
-
});
|
133
|
-
}
|
134
|
-
|
135
|
-
@Override
|
136
|
-
protected boolean supportsGeneratedKeys(final Connection connection) throws SQLException {
|
137
|
-
return true; // driver reports false from supportsGetGeneratedKeys()
|
138
|
-
}
|
139
|
-
|
140
|
-
@Override
|
141
|
-
protected IRubyObject matchTables(final ThreadContext context,
|
142
|
-
final Connection connection,
|
143
|
-
final String catalog, String schemaPattern,
|
144
|
-
final String tablePattern, final String[] types,
|
145
|
-
final boolean checkExistsOnly) throws SQLException {
|
146
|
-
if (schemaPattern != null && schemaPattern.equals("")) {
|
147
|
-
schemaPattern = null; // Derby doesn't like empty-string schema name
|
148
|
-
}
|
149
|
-
return super.matchTables(context, connection, catalog, schemaPattern, tablePattern, types, checkExistsOnly);
|
150
|
-
}
|
151
|
-
|
152
|
-
}
|