activerecord-jdbc-adapter 0.9.0.1 → 0.9.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +31 -0
- data/Manifest.txt +7 -0
- data/README.txt +15 -2
- data/Rakefile +28 -30
- data/lib/active_record/connection_adapters/h2_adapter.rb +13 -1
- data/lib/active_record/connection_adapters/jdbc_adapter.rb +78 -96
- data/lib/jdbc_adapter/jdbc.rake +15 -5
- data/lib/jdbc_adapter/jdbc_adapter_internal.jar +0 -0
- data/lib/jdbc_adapter/jdbc_cachedb.rb +4 -4
- data/lib/jdbc_adapter/jdbc_db2.rb +5 -7
- data/lib/jdbc_adapter/jdbc_derby.rb +57 -30
- data/lib/jdbc_adapter/jdbc_firebird.rb +2 -2
- data/lib/jdbc_adapter/jdbc_hsqldb.rb +53 -46
- data/lib/jdbc_adapter/jdbc_informix.rb +4 -5
- data/lib/jdbc_adapter/jdbc_mimer.rb +2 -2
- data/lib/jdbc_adapter/jdbc_mssql.rb +25 -23
- data/lib/jdbc_adapter/jdbc_mysql.rb +20 -22
- data/lib/jdbc_adapter/jdbc_oracle.rb +115 -117
- data/lib/jdbc_adapter/jdbc_postgre.rb +129 -59
- data/lib/jdbc_adapter/jdbc_sqlite3.rb +149 -28
- data/lib/jdbc_adapter/jdbc_sybase.rb +13 -2
- data/lib/jdbc_adapter/missing_functionality_helper.rb +12 -3
- data/lib/jdbc_adapter/version.rb +1 -1
- data/src/java/jdbc_adapter/JdbcAdapterInternalService.java +6 -1101
- data/src/java/jdbc_adapter/JdbcDerbySpec.java +26 -23
- data/src/java/jdbc_adapter/JdbcMySQLSpec.java +79 -28
- data/src/java/jdbc_adapter/PostgresRubyJdbcConnection.java +35 -0
- data/src/java/jdbc_adapter/RubyJdbcConnection.java +1149 -0
- data/src/java/jdbc_adapter/SQLBlock.java +12 -3
- data/src/java/jdbc_adapter/Sqlite3RubyJdbcConnection.java +41 -0
- data/test/activerecord/connection_adapters/type_conversion_test.rb +1 -1
- data/test/db/derby.rb +0 -3
- data/test/db/h2.rb +0 -3
- data/test/db/hsqldb.rb +1 -4
- data/test/db/mysql.rb +1 -0
- data/test/db/oracle.rb +5 -0
- data/test/db/sqlite3.rb +7 -3
- data/test/derby_migration_test.rb +21 -0
- data/test/has_many_through.rb +11 -4
- data/test/jdbc_common.rb +13 -1
- data/test/models/data_types.rb +11 -1
- data/test/models/mixed_case.rb +20 -0
- data/test/mysql_multibyte_test.rb +4 -0
- data/test/oracle_simple_test.rb +1 -1
- data/test/postgres_mixed_case_test.rb +19 -0
- data/test/simple.rb +220 -41
- data/test/sqlite3_simple_test.rb +83 -0
- data/test/sybase_jtds_simple_test.rb +6 -0
- metadata +12 -10
@@ -1,7 +1,7 @@
|
|
1
1
|
module JdbcSpec
|
2
2
|
module Sybase
|
3
|
-
def self.
|
4
|
-
|
3
|
+
def self.adapter_matcher(name, *)
|
4
|
+
name =~ /sybase|tds/i ? self : false
|
5
5
|
end
|
6
6
|
|
7
7
|
def add_limit_offset!(sql, options) # :nodoc:
|
@@ -35,5 +35,16 @@ module JdbcSpec
|
|
35
35
|
!@limit.nil? && @limit == 0
|
36
36
|
end
|
37
37
|
|
38
|
+
def modify_types(tp) #:nodoc:
|
39
|
+
tp[:primary_key] = "NUMERIC(22,0) IDENTITY PRIMARY KEY"
|
40
|
+
tp[:integer][:limit] = nil
|
41
|
+
tp[:boolean] = {:name => "bit"}
|
42
|
+
tp[:binary] = {:name => "image"}
|
43
|
+
tp
|
44
|
+
end
|
45
|
+
|
46
|
+
def remove_index(table_name, options = {})
|
47
|
+
execute "DROP INDEX #{table_name}.#{index_name(table_name, options)}"
|
48
|
+
end
|
38
49
|
end
|
39
50
|
end
|
@@ -34,13 +34,13 @@ module JdbcSpec
|
|
34
34
|
yield @definition if block_given?
|
35
35
|
end
|
36
36
|
|
37
|
-
copy_table_indexes(from, to)
|
37
|
+
copy_table_indexes(from, to, options)
|
38
38
|
copy_table_contents(from, to,
|
39
39
|
@definition.columns,
|
40
40
|
options[:rename] || {})
|
41
41
|
end
|
42
42
|
|
43
|
-
def copy_table_indexes(from, to) #:nodoc:
|
43
|
+
def copy_table_indexes(from, to, options={}) #:nodoc:
|
44
44
|
indexes(from).each do |index|
|
45
45
|
name = index.name.downcase
|
46
46
|
if to == "altered_#{from}"
|
@@ -52,7 +52,16 @@ module JdbcSpec
|
|
52
52
|
# index name can't be the same
|
53
53
|
opts = { :name => name.gsub(/_(#{from})_/, "_#{to}_") }
|
54
54
|
opts[:unique] = true if index.unique
|
55
|
-
|
55
|
+
if options[:rename]
|
56
|
+
new_columns = index.columns.map {|column_name|
|
57
|
+
(options[:rename][column_name] ||
|
58
|
+
options[:rename][column_name.to_sym] ||
|
59
|
+
column_name)
|
60
|
+
}
|
61
|
+
else
|
62
|
+
new_columns = index.columns
|
63
|
+
end
|
64
|
+
add_index(to, new_columns, opts)
|
56
65
|
end
|
57
66
|
end
|
58
67
|
|
data/lib/jdbc_adapter/version.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
-
|
1
|
+
/*
|
2
|
+
**** BEGIN LICENSE BLOCK *****
|
2
3
|
* Copyright (c) 2006-2009 Nick Sieger <nick@nicksieger.com>
|
3
4
|
* Copyright (c) 2006-2007 Ola Bini <ola.bini@gmail.com>
|
5
|
+
* Copyright (c) 2008-2009 Thomas E Enebo <enebo@acm.org>
|
4
6
|
*
|
5
7
|
* Permission is hereby granted, free of charge, to any person obtaining
|
6
8
|
* a copy of this software and associated documentation files (the
|
@@ -25,59 +27,21 @@
|
|
25
27
|
package jdbc_adapter;
|
26
28
|
|
27
29
|
import java.io.IOException;
|
28
|
-
import java.io.Reader;
|
29
|
-
import java.io.InputStream;
|
30
|
-
import java.io.ByteArrayInputStream;
|
31
|
-
import java.io.StringReader;
|
32
|
-
|
33
|
-
import java.sql.Connection;
|
34
|
-
import java.sql.DatabaseMetaData;
|
35
|
-
import java.sql.PreparedStatement;
|
36
|
-
import java.sql.ResultSetMetaData;
|
37
|
-
import java.sql.ResultSet;
|
38
|
-
import java.sql.SQLException;
|
39
|
-
import java.sql.Statement;
|
40
|
-
import java.sql.PreparedStatement;
|
41
|
-
import java.sql.Timestamp;
|
42
|
-
import java.sql.Types;
|
43
|
-
|
44
|
-
import java.text.DateFormat;
|
45
|
-
import java.text.SimpleDateFormat;
|
46
|
-
|
47
|
-
import java.util.ArrayList;
|
48
|
-
import java.util.Calendar;
|
49
|
-
import java.util.Date;
|
50
|
-
import java.util.List;
|
51
30
|
|
52
31
|
import org.jruby.Ruby;
|
53
|
-
import org.jruby.RubyArray;
|
54
32
|
import org.jruby.RubyClass;
|
55
|
-
import org.jruby.RubyHash;
|
56
33
|
import org.jruby.RubyModule;
|
57
|
-
import org.jruby.RubyNumeric;
|
58
34
|
import org.jruby.RubyObjectAdapter;
|
59
|
-
import org.jruby.RubyString;
|
60
|
-
import org.jruby.RubySymbol;
|
61
|
-
import org.jruby.RubyTime;
|
62
|
-
import org.jruby.anno.JRubyMethod;
|
63
|
-
import org.jruby.exceptions.RaiseException;
|
64
|
-
import org.jruby.javasupport.Java;
|
65
35
|
import org.jruby.javasupport.JavaEmbedUtils;
|
66
|
-
import org.jruby.javasupport.JavaObject;
|
67
|
-
import org.jruby.runtime.Arity;
|
68
|
-
import org.jruby.runtime.Block;
|
69
|
-
import org.jruby.runtime.ThreadContext;
|
70
|
-
import org.jruby.runtime.builtin.IRubyObject;
|
71
36
|
import org.jruby.runtime.load.BasicLibraryService;
|
72
|
-
import org.jruby.util.ByteList;
|
73
37
|
|
74
38
|
public class JdbcAdapterInternalService implements BasicLibraryService {
|
75
39
|
private static RubyObjectAdapter rubyApi;
|
76
40
|
|
77
41
|
public boolean basicLoad(final Ruby runtime) throws IOException {
|
78
|
-
|
79
|
-
|
80
|
-
|
42
|
+
RubyClass jdbcConnection = RubyJdbcConnection.createJdbcConnectionClass(runtime);
|
43
|
+
PostgresRubyJdbcConnection.createPostgresJdbcConnectionClass(runtime, jdbcConnection);
|
44
|
+
Sqlite3RubyJdbcConnection.createSqlite3JdbcConnectionClass(runtime, jdbcConnection);
|
81
45
|
RubyModule jdbcSpec = runtime.getOrCreateModule("JdbcSpec");
|
82
46
|
|
83
47
|
rubyApi = JavaEmbedUtils.newObjectAdapter();
|
@@ -85,1063 +49,4 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
85
49
|
JdbcDerbySpec.load(jdbcSpec, rubyApi);
|
86
50
|
return true;
|
87
51
|
}
|
88
|
-
|
89
|
-
private static int whitespace(int p, final int pend, ByteList bl) {
|
90
|
-
while(p < pend) {
|
91
|
-
switch(bl.bytes[p]) {
|
92
|
-
case ' ':
|
93
|
-
case '\n':
|
94
|
-
case '\r':
|
95
|
-
case '\t':
|
96
|
-
p++;
|
97
|
-
break;
|
98
|
-
default:
|
99
|
-
return p;
|
100
|
-
}
|
101
|
-
}
|
102
|
-
return p;
|
103
|
-
}
|
104
|
-
|
105
|
-
@JRubyMethod(name = "insert?", required = 1, meta = true)
|
106
|
-
public static IRubyObject insert_p(IRubyObject recv, IRubyObject _sql) {
|
107
|
-
ByteList bl = rubyApi.convertToRubyString(_sql).getByteList();
|
108
|
-
|
109
|
-
int p = bl.begin;
|
110
|
-
int pend = p + bl.realSize;
|
111
|
-
|
112
|
-
p = whitespace(p, pend, bl);
|
113
|
-
|
114
|
-
if(pend - p >= 6) {
|
115
|
-
switch(bl.bytes[p++]) {
|
116
|
-
case 'i':
|
117
|
-
case 'I':
|
118
|
-
switch(bl.bytes[p++]) {
|
119
|
-
case 'n':
|
120
|
-
case 'N':
|
121
|
-
switch(bl.bytes[p++]) {
|
122
|
-
case 's':
|
123
|
-
case 'S':
|
124
|
-
switch(bl.bytes[p++]) {
|
125
|
-
case 'e':
|
126
|
-
case 'E':
|
127
|
-
switch(bl.bytes[p++]) {
|
128
|
-
case 'r':
|
129
|
-
case 'R':
|
130
|
-
switch(bl.bytes[p++]) {
|
131
|
-
case 't':
|
132
|
-
case 'T':
|
133
|
-
return recv.getRuntime().getTrue();
|
134
|
-
}
|
135
|
-
}
|
136
|
-
}
|
137
|
-
}
|
138
|
-
}
|
139
|
-
}
|
140
|
-
}
|
141
|
-
return recv.getRuntime().getFalse();
|
142
|
-
}
|
143
|
-
|
144
|
-
@JRubyMethod(name = "select?", required = 1, meta = true)
|
145
|
-
public static IRubyObject select_p(IRubyObject recv, IRubyObject _sql) {
|
146
|
-
ByteList bl = rubyApi.convertToRubyString(_sql).getByteList();
|
147
|
-
|
148
|
-
int p = bl.begin;
|
149
|
-
int pend = p + bl.realSize;
|
150
|
-
|
151
|
-
p = whitespace(p, pend, bl);
|
152
|
-
|
153
|
-
if(pend - p >= 6) {
|
154
|
-
if(bl.bytes[p] == '(') {
|
155
|
-
p++;
|
156
|
-
p = whitespace(p, pend, bl);
|
157
|
-
}
|
158
|
-
if(pend - p >= 6) {
|
159
|
-
switch(bl.bytes[p++]) {
|
160
|
-
case 's':
|
161
|
-
case 'S':
|
162
|
-
switch(bl.bytes[p++]) {
|
163
|
-
case 'e':
|
164
|
-
case 'E':
|
165
|
-
switch(bl.bytes[p++]) {
|
166
|
-
case 'l':
|
167
|
-
case 'L':
|
168
|
-
switch(bl.bytes[p++]) {
|
169
|
-
case 'e':
|
170
|
-
case 'E':
|
171
|
-
switch(bl.bytes[p++]) {
|
172
|
-
case 'c':
|
173
|
-
case 'C':
|
174
|
-
switch(bl.bytes[p++]) {
|
175
|
-
case 't':
|
176
|
-
case 'T':
|
177
|
-
return recv.getRuntime().getTrue();
|
178
|
-
}
|
179
|
-
}
|
180
|
-
}
|
181
|
-
}
|
182
|
-
case 'h':
|
183
|
-
case 'H':
|
184
|
-
switch(bl.bytes[p++]) {
|
185
|
-
case 'o':
|
186
|
-
case 'O':
|
187
|
-
switch(bl.bytes[p++]) {
|
188
|
-
case 'w':
|
189
|
-
case 'W':
|
190
|
-
return recv.getRuntime().getTrue();
|
191
|
-
}
|
192
|
-
}
|
193
|
-
}
|
194
|
-
}
|
195
|
-
}
|
196
|
-
}
|
197
|
-
return recv.getRuntime().getFalse();
|
198
|
-
}
|
199
|
-
|
200
|
-
@JRubyMethod(name = "connection")
|
201
|
-
public static IRubyObject connection(IRubyObject recv) {
|
202
|
-
Connection c = getConnection(recv);
|
203
|
-
if (c == null) {
|
204
|
-
reconnect(recv);
|
205
|
-
}
|
206
|
-
return rubyApi.getInstanceVariable(recv, "@connection");
|
207
|
-
}
|
208
|
-
|
209
|
-
@JRubyMethod(name = "disconnect!")
|
210
|
-
public static IRubyObject disconnect(IRubyObject recv) {
|
211
|
-
setConnection(recv, null);
|
212
|
-
return recv;
|
213
|
-
}
|
214
|
-
|
215
|
-
@JRubyMethod(name = "reconnect!")
|
216
|
-
public static IRubyObject reconnect(IRubyObject recv) {
|
217
|
-
setConnection(recv, getConnectionFactory(recv).newConnection());
|
218
|
-
return recv;
|
219
|
-
}
|
220
|
-
|
221
|
-
@JRubyMethod(name = "with_connection_retry_guard", frame = true)
|
222
|
-
public static IRubyObject with_connection_retry_guard(final IRubyObject recv, final Block block) {
|
223
|
-
return withConnectionAndRetry(recv, new SQLBlock() {
|
224
|
-
public IRubyObject call(Connection c) throws SQLException {
|
225
|
-
return block.call(recv.getRuntime().getCurrentContext(), new IRubyObject[] {
|
226
|
-
wrappedConnection(recv, c)
|
227
|
-
});
|
228
|
-
}
|
229
|
-
});
|
230
|
-
}
|
231
|
-
|
232
|
-
private static IRubyObject withConnectionAndRetry(IRubyObject recv, SQLBlock block) {
|
233
|
-
int tries = 1;
|
234
|
-
int i = 0;
|
235
|
-
Throwable toWrap = null;
|
236
|
-
boolean autoCommit = false;
|
237
|
-
while (i < tries) {
|
238
|
-
Connection c = getConnection(recv, true);
|
239
|
-
try {
|
240
|
-
autoCommit = c.getAutoCommit();
|
241
|
-
return block.call(c);
|
242
|
-
} catch (Exception e) {
|
243
|
-
toWrap = e;
|
244
|
-
while (toWrap.getCause() != null && toWrap.getCause() != toWrap) {
|
245
|
-
toWrap = toWrap.getCause();
|
246
|
-
}
|
247
|
-
i++;
|
248
|
-
if (autoCommit) {
|
249
|
-
if (i == 1) {
|
250
|
-
tries = (int) rubyApi.convertToRubyInteger(config_value(recv, "retry_count")).getLongValue();
|
251
|
-
if (tries <= 0) {
|
252
|
-
tries = 1;
|
253
|
-
}
|
254
|
-
}
|
255
|
-
if (isConnectionBroken(recv, c)) {
|
256
|
-
reconnect(recv);
|
257
|
-
} else {
|
258
|
-
throw wrap(recv, toWrap);
|
259
|
-
}
|
260
|
-
}
|
261
|
-
}
|
262
|
-
}
|
263
|
-
throw wrap(recv, toWrap);
|
264
|
-
}
|
265
|
-
|
266
|
-
private static SQLBlock tableLookupBlock(final Ruby runtime,
|
267
|
-
final String catalog, final String schemapat,
|
268
|
-
final String tablepat, final String[] types) {
|
269
|
-
return new SQLBlock() {
|
270
|
-
public IRubyObject call(Connection c) throws SQLException {
|
271
|
-
ResultSet rs = null;
|
272
|
-
try {
|
273
|
-
DatabaseMetaData metadata = c.getMetaData();
|
274
|
-
String clzName = metadata.getClass().getName().toLowerCase();
|
275
|
-
boolean isOracle = clzName.indexOf("oracle") != -1 || clzName.indexOf("oci") != -1;
|
276
|
-
|
277
|
-
String realschema = schemapat;
|
278
|
-
String realtablepat = tablepat;
|
279
|
-
|
280
|
-
if(metadata.storesUpperCaseIdentifiers()) {
|
281
|
-
if (realschema != null) realschema = realschema.toUpperCase();
|
282
|
-
if (realtablepat != null) realtablepat = realtablepat.toUpperCase();
|
283
|
-
} else if(metadata.storesLowerCaseIdentifiers()) {
|
284
|
-
if (null != realschema) realschema = realschema.toLowerCase();
|
285
|
-
if (realtablepat != null) realtablepat = realtablepat.toLowerCase();
|
286
|
-
}
|
287
|
-
|
288
|
-
if (realschema == null && isOracle) {
|
289
|
-
ResultSet schemas = metadata.getSchemas();
|
290
|
-
String username = metadata.getUserName();
|
291
|
-
while (schemas.next()) {
|
292
|
-
if (schemas.getString(1).equalsIgnoreCase(username)) {
|
293
|
-
realschema = schemas.getString(1);
|
294
|
-
break;
|
295
|
-
}
|
296
|
-
}
|
297
|
-
schemas.close();
|
298
|
-
}
|
299
|
-
rs = metadata.getTables(catalog, realschema, realtablepat, types);
|
300
|
-
List arr = new ArrayList();
|
301
|
-
while (rs.next()) {
|
302
|
-
String name = rs.getString(3).toLowerCase();
|
303
|
-
// Handle stupid Oracle 10g RecycleBin feature
|
304
|
-
if (!isOracle || !name.startsWith("bin$")) {
|
305
|
-
arr.add(RubyString.newUnicodeString(runtime, name));
|
306
|
-
}
|
307
|
-
}
|
308
|
-
return runtime.newArray(arr);
|
309
|
-
} finally {
|
310
|
-
try { rs.close(); } catch (Exception e) { }
|
311
|
-
}
|
312
|
-
}
|
313
|
-
};
|
314
|
-
}
|
315
|
-
|
316
|
-
@JRubyMethod(name = "tables", rest = true)
|
317
|
-
public static IRubyObject tables(final IRubyObject recv, IRubyObject[] args) {
|
318
|
-
final Ruby runtime = recv.getRuntime();
|
319
|
-
final String catalog = getCatalog(args);
|
320
|
-
final String schemapat = getSchemaPattern(args);
|
321
|
-
final String tablepat = getTablePattern(args);
|
322
|
-
final String[] types = getTypes(args);
|
323
|
-
return withConnectionAndRetry(recv, tableLookupBlock(runtime, catalog,
|
324
|
-
schemapat, tablepat, types));
|
325
|
-
}
|
326
|
-
|
327
|
-
private static String getCatalog(IRubyObject[] args) {
|
328
|
-
if (args != null && args.length > 0) {
|
329
|
-
return convertToStringOrNull(args[0]);
|
330
|
-
}
|
331
|
-
return null;
|
332
|
-
}
|
333
|
-
|
334
|
-
private static String getSchemaPattern(IRubyObject[] args) {
|
335
|
-
if (args != null && args.length > 1) {
|
336
|
-
return convertToStringOrNull(args[1]);
|
337
|
-
}
|
338
|
-
return null;
|
339
|
-
}
|
340
|
-
|
341
|
-
private static String getTablePattern(IRubyObject[] args) {
|
342
|
-
if (args != null && args.length > 2) {
|
343
|
-
return convertToStringOrNull(args[2]);
|
344
|
-
}
|
345
|
-
return null;
|
346
|
-
}
|
347
|
-
|
348
|
-
private static String[] getTypes(IRubyObject[] args) {
|
349
|
-
String[] types = new String[]{"TABLE"};
|
350
|
-
if (args != null && args.length > 3) {
|
351
|
-
IRubyObject typearr = args[3];
|
352
|
-
if (typearr instanceof RubyArray) {
|
353
|
-
IRubyObject[] arr = rubyApi.convertToJavaArray(typearr);
|
354
|
-
types = new String[arr.length];
|
355
|
-
for (int i = 0; i < types.length; i++) {
|
356
|
-
types[i] = arr[i].toString();
|
357
|
-
}
|
358
|
-
} else {
|
359
|
-
types = new String[]{types.toString()};
|
360
|
-
}
|
361
|
-
}
|
362
|
-
return types;
|
363
|
-
}
|
364
|
-
|
365
|
-
@JRubyMethod(name = "native_database_types")
|
366
|
-
public static IRubyObject native_database_types(IRubyObject recv) {
|
367
|
-
return rubyApi.getInstanceVariable(recv, "@tps");
|
368
|
-
}
|
369
|
-
|
370
|
-
@JRubyMethod(name = "set_native_database_types")
|
371
|
-
public static IRubyObject set_native_database_types(IRubyObject recv) throws SQLException, IOException {
|
372
|
-
Ruby runtime = recv.getRuntime();
|
373
|
-
IRubyObject types = unmarshal_result_downcase(recv, getConnection(recv, true).getMetaData().getTypeInfo());
|
374
|
-
IRubyObject typeConverter = ((RubyModule) (runtime.getModule("ActiveRecord").getConstant("ConnectionAdapters"))).getConstant("JdbcTypeConverter");
|
375
|
-
IRubyObject value = rubyApi.callMethod(rubyApi.callMethod(typeConverter, "new", types), "choose_best_types");
|
376
|
-
rubyApi.setInstanceVariable(recv, "@native_types", value);
|
377
|
-
return runtime.getNil();
|
378
|
-
}
|
379
|
-
|
380
|
-
@JRubyMethod(name = "database_name")
|
381
|
-
public static IRubyObject database_name(IRubyObject recv) throws SQLException {
|
382
|
-
String name = getConnection(recv, true).getCatalog();
|
383
|
-
if(null == name) {
|
384
|
-
name = getConnection(recv, true).getMetaData().getUserName();
|
385
|
-
if(null == name) {
|
386
|
-
name = "db1";
|
387
|
-
}
|
388
|
-
}
|
389
|
-
return recv.getRuntime().newString(name);
|
390
|
-
}
|
391
|
-
|
392
|
-
@JRubyMethod(name = "begin")
|
393
|
-
public static IRubyObject begin(IRubyObject recv) throws SQLException {
|
394
|
-
getConnection(recv, true).setAutoCommit(false);
|
395
|
-
return recv.getRuntime().getNil();
|
396
|
-
}
|
397
|
-
|
398
|
-
@JRubyMethod(name = "commit")
|
399
|
-
public static IRubyObject commit(IRubyObject recv) throws SQLException {
|
400
|
-
Connection c = getConnection(recv, true);
|
401
|
-
if (!c.getAutoCommit()) {
|
402
|
-
try {
|
403
|
-
c.commit();
|
404
|
-
} finally {
|
405
|
-
c.setAutoCommit(true);
|
406
|
-
}
|
407
|
-
}
|
408
|
-
return recv.getRuntime().getNil();
|
409
|
-
}
|
410
|
-
|
411
|
-
@JRubyMethod(name = "rollback")
|
412
|
-
public static IRubyObject rollback(IRubyObject recv) throws SQLException {
|
413
|
-
Connection c = getConnection(recv, true);
|
414
|
-
if (!c.getAutoCommit()) {
|
415
|
-
try {
|
416
|
-
c.rollback();
|
417
|
-
} finally {
|
418
|
-
c.setAutoCommit(true);
|
419
|
-
}
|
420
|
-
}
|
421
|
-
return recv.getRuntime().getNil();
|
422
|
-
}
|
423
|
-
|
424
|
-
@JRubyMethod(name = {"columns", "columns_internal"}, required = 1, optional = 2)
|
425
|
-
public static IRubyObject columns_internal(final IRubyObject recv, final IRubyObject[] args) throws SQLException, IOException {
|
426
|
-
return withConnectionAndRetry(recv, new SQLBlock() {
|
427
|
-
public IRubyObject call(Connection c) throws SQLException {
|
428
|
-
ResultSet results = null;
|
429
|
-
try {
|
430
|
-
String table_name = rubyApi.convertToRubyString(args[0]).getUnicodeValue();
|
431
|
-
String schemaName = null;
|
432
|
-
|
433
|
-
int index = table_name.indexOf(".");
|
434
|
-
if(index != -1) {
|
435
|
-
schemaName = table_name.substring(0, index);
|
436
|
-
table_name = table_name.substring(index + 1);
|
437
|
-
}
|
438
|
-
|
439
|
-
DatabaseMetaData metadata = c.getMetaData();
|
440
|
-
String clzName = metadata.getClass().getName().toLowerCase();
|
441
|
-
boolean isDerby = clzName.indexOf("derby") != -1;
|
442
|
-
boolean isOracle = clzName.indexOf("oracle") != -1 || clzName.indexOf("oci") != -1;
|
443
|
-
|
444
|
-
if(args.length>2) {
|
445
|
-
schemaName = args[2].toString();
|
446
|
-
}
|
447
|
-
|
448
|
-
if(metadata.storesUpperCaseIdentifiers()) {
|
449
|
-
if (null != schemaName) schemaName = schemaName.toUpperCase();
|
450
|
-
table_name = table_name.toUpperCase();
|
451
|
-
} else if(metadata.storesLowerCaseIdentifiers()) {
|
452
|
-
if (null != schemaName) schemaName = schemaName.toLowerCase();
|
453
|
-
table_name = table_name.toLowerCase();
|
454
|
-
}
|
455
|
-
|
456
|
-
if(schemaName == null && (isDerby || isOracle)) {
|
457
|
-
ResultSet schemas = metadata.getSchemas();
|
458
|
-
String username = metadata.getUserName();
|
459
|
-
while(schemas.next()) {
|
460
|
-
if(schemas.getString(1).equalsIgnoreCase(username)) {
|
461
|
-
schemaName = schemas.getString(1);
|
462
|
-
break;
|
463
|
-
}
|
464
|
-
}
|
465
|
-
schemas.close();
|
466
|
-
}
|
467
|
-
|
468
|
-
RubyArray matchingTables = (RubyArray) tableLookupBlock(recv.getRuntime(),
|
469
|
-
c.getCatalog(), schemaName, table_name, new String[]{"TABLE","VIEW"}).call(c);
|
470
|
-
if (matchingTables.isEmpty()) {
|
471
|
-
throw new SQLException("Table " + table_name + " does not exist");
|
472
|
-
}
|
473
|
-
|
474
|
-
results = metadata.getColumns(c.getCatalog(),schemaName,table_name,null);
|
475
|
-
return unmarshal_columns(recv, metadata, results);
|
476
|
-
} finally {
|
477
|
-
try { if (results != null) results.close(); } catch (SQLException sqx) {}
|
478
|
-
}
|
479
|
-
}
|
480
|
-
});
|
481
|
-
}
|
482
|
-
|
483
|
-
private static final java.util.regex.Pattern HAS_SMALL = java.util.regex.Pattern.compile("[a-z]");
|
484
|
-
private static IRubyObject unmarshal_columns(IRubyObject recv, DatabaseMetaData metadata, ResultSet rs) throws SQLException {
|
485
|
-
try {
|
486
|
-
List columns = new ArrayList();
|
487
|
-
String clzName = metadata.getClass().getName().toLowerCase();
|
488
|
-
boolean isDerby = clzName.indexOf("derby") != -1;
|
489
|
-
boolean isOracle = clzName.indexOf("oracle") != -1 || clzName.indexOf("oci") != -1;
|
490
|
-
Ruby runtime = recv.getRuntime();
|
491
|
-
|
492
|
-
IRubyObject adapter = rubyApi.callMethod(recv, "adapter");
|
493
|
-
RubyHash tps = (RubyHash) rubyApi.callMethod(adapter, "native_database_types");
|
494
|
-
|
495
|
-
IRubyObject jdbcCol = ((RubyModule)(runtime.getModule("ActiveRecord").getConstant("ConnectionAdapters"))).getConstant("JdbcColumn");
|
496
|
-
|
497
|
-
while(rs.next()) {
|
498
|
-
String column_name = rs.getString(4);
|
499
|
-
if(metadata.storesUpperCaseIdentifiers() && !HAS_SMALL.matcher(column_name).find()) {
|
500
|
-
column_name = column_name.toLowerCase();
|
501
|
-
}
|
502
|
-
|
503
|
-
String prec = rs.getString(7);
|
504
|
-
String scal = rs.getString(9);
|
505
|
-
int precision = -1;
|
506
|
-
int scale = -1;
|
507
|
-
if(prec != null) {
|
508
|
-
precision = Integer.parseInt(prec);
|
509
|
-
if(scal != null) {
|
510
|
-
scale = Integer.parseInt(scal);
|
511
|
-
}
|
512
|
-
else if(isOracle && rs.getInt(5) == java.sql.Types.DECIMAL) { // NUMBER type in Oracle
|
513
|
-
prec = null;
|
514
|
-
}
|
515
|
-
}
|
516
|
-
String type = rs.getString(6);
|
517
|
-
if(prec != null && precision > 0) {
|
518
|
-
type += "(" + precision;
|
519
|
-
if(scal != null && scale > 0) {
|
520
|
-
type += "," + scale;
|
521
|
-
}
|
522
|
-
type += ")";
|
523
|
-
}
|
524
|
-
String def = rs.getString(13);
|
525
|
-
IRubyObject _def;
|
526
|
-
if(def == null || (isOracle && def.toLowerCase().trim().equals("null"))) {
|
527
|
-
_def = runtime.getNil();
|
528
|
-
} else {
|
529
|
-
if(isOracle) {
|
530
|
-
def = def.trim();
|
531
|
-
}
|
532
|
-
if((isDerby || isOracle) && def.length() > 0 && def.charAt(0) == '\'') {
|
533
|
-
def = def.substring(1, def.length()-1);
|
534
|
-
}
|
535
|
-
_def = RubyString.newUnicodeString(runtime, def);
|
536
|
-
}
|
537
|
-
IRubyObject config = rubyApi.getInstanceVariable(recv, "@config");
|
538
|
-
IRubyObject c = rubyApi.callMethod(jdbcCol, "new",
|
539
|
-
new IRubyObject[]{
|
540
|
-
config, RubyString.newUnicodeString(runtime, column_name),
|
541
|
-
_def, RubyString.newUnicodeString(runtime, type),
|
542
|
-
runtime.newBoolean(!rs.getString(18).trim().equals("NO"))
|
543
|
-
});
|
544
|
-
columns.add(c);
|
545
|
-
|
546
|
-
IRubyObject tp = (IRubyObject)tps.fastARef(rubyApi.callMethod(c,"type"));
|
547
|
-
if(tp != null && !tp.isNil() && rubyApi.callMethod(tp, "[]", runtime.newSymbol("limit")).isNil()) {
|
548
|
-
rubyApi.callMethod(c, "limit=", runtime.getNil());
|
549
|
-
if(!rubyApi.callMethod(c, "type").equals(runtime.newSymbol("decimal"))) {
|
550
|
-
rubyApi.callMethod(c, "precision=", runtime.getNil());
|
551
|
-
}
|
552
|
-
}
|
553
|
-
}
|
554
|
-
return runtime.newArray(columns);
|
555
|
-
} finally {
|
556
|
-
try {
|
557
|
-
rs.close();
|
558
|
-
} catch(Exception e) {}
|
559
|
-
}
|
560
|
-
}
|
561
|
-
|
562
|
-
@JRubyMethod(name = "primary_keys", required = 1)
|
563
|
-
public static IRubyObject primary_keys(final IRubyObject recv, final IRubyObject _table_name) throws SQLException {
|
564
|
-
return withConnectionAndRetry(recv, new SQLBlock() {
|
565
|
-
public IRubyObject call(Connection c) throws SQLException {
|
566
|
-
DatabaseMetaData metadata = c.getMetaData();
|
567
|
-
String table_name = _table_name.toString();
|
568
|
-
if (metadata.storesUpperCaseIdentifiers()) {
|
569
|
-
table_name = table_name.toUpperCase();
|
570
|
-
} else if (metadata.storesLowerCaseIdentifiers()) {
|
571
|
-
table_name = table_name.toLowerCase();
|
572
|
-
}
|
573
|
-
ResultSet result_set = metadata.getPrimaryKeys(null, null, table_name);
|
574
|
-
List keyNames = new ArrayList();
|
575
|
-
Ruby runtime = recv.getRuntime();
|
576
|
-
while (result_set.next()) {
|
577
|
-
String s1 = result_set.getString(4);
|
578
|
-
if (metadata.storesUpperCaseIdentifiers() && !HAS_SMALL.matcher(s1).find()) {
|
579
|
-
s1 = s1.toLowerCase();
|
580
|
-
}
|
581
|
-
keyNames.add(RubyString.newUnicodeString(runtime,s1));
|
582
|
-
}
|
583
|
-
|
584
|
-
try {
|
585
|
-
result_set.close();
|
586
|
-
} catch (Exception e) {
|
587
|
-
}
|
588
|
-
|
589
|
-
return runtime.newArray(keyNames);
|
590
|
-
}
|
591
|
-
});
|
592
|
-
}
|
593
|
-
|
594
|
-
@JRubyMethod(name = "execute_id_insert", required = 2)
|
595
|
-
public static IRubyObject execute_id_insert(IRubyObject recv, final IRubyObject sql, final IRubyObject id) throws SQLException {
|
596
|
-
return withConnectionAndRetry(recv, new SQLBlock() {
|
597
|
-
public IRubyObject call(Connection c) throws SQLException {
|
598
|
-
PreparedStatement ps = c.prepareStatement(rubyApi.convertToRubyString(sql).getUnicodeValue());
|
599
|
-
try {
|
600
|
-
ps.setLong(1, RubyNumeric.fix2long(id));
|
601
|
-
ps.executeUpdate();
|
602
|
-
} finally {
|
603
|
-
ps.close();
|
604
|
-
}
|
605
|
-
return id;
|
606
|
-
}
|
607
|
-
});
|
608
|
-
}
|
609
|
-
|
610
|
-
@JRubyMethod(name = "execute_update", required = 1)
|
611
|
-
public static IRubyObject execute_update(final IRubyObject recv, final IRubyObject sql) throws SQLException {
|
612
|
-
return withConnectionAndRetry(recv, new SQLBlock() {
|
613
|
-
public IRubyObject call(Connection c) throws SQLException {
|
614
|
-
Statement stmt = null;
|
615
|
-
try {
|
616
|
-
stmt = c.createStatement();
|
617
|
-
return recv.getRuntime().newFixnum((long)stmt.executeUpdate(rubyApi.convertToRubyString(sql).getUnicodeValue()));
|
618
|
-
} finally {
|
619
|
-
if (null != stmt) {
|
620
|
-
try {
|
621
|
-
stmt.close();
|
622
|
-
} catch (Exception e) {
|
623
|
-
}
|
624
|
-
}
|
625
|
-
}
|
626
|
-
}
|
627
|
-
});
|
628
|
-
}
|
629
|
-
|
630
|
-
@JRubyMethod(name = "execute_query", rest = true)
|
631
|
-
public static IRubyObject execute_query(final IRubyObject recv, IRubyObject[] args) throws SQLException, IOException {
|
632
|
-
final IRubyObject sql = args[0];
|
633
|
-
final int maxrows;
|
634
|
-
|
635
|
-
if (args.length > 1) {
|
636
|
-
maxrows = RubyNumeric.fix2int(args[1]);
|
637
|
-
} else {
|
638
|
-
maxrows = 0;
|
639
|
-
}
|
640
|
-
|
641
|
-
return withConnectionAndRetry(recv, new SQLBlock() {
|
642
|
-
public IRubyObject call(Connection c) throws SQLException {
|
643
|
-
Statement stmt = null;
|
644
|
-
try {
|
645
|
-
stmt = c.createStatement();
|
646
|
-
stmt.setMaxRows(maxrows);
|
647
|
-
return unmarshal_result(recv, stmt.executeQuery(rubyApi.convertToRubyString(sql).getUnicodeValue()));
|
648
|
-
} finally {
|
649
|
-
if (null != stmt) {
|
650
|
-
try {
|
651
|
-
stmt.close();
|
652
|
-
} catch (Exception e) {
|
653
|
-
}
|
654
|
-
}
|
655
|
-
}
|
656
|
-
}
|
657
|
-
});
|
658
|
-
}
|
659
|
-
|
660
|
-
@JRubyMethod(name = "execute_insert", required = 1)
|
661
|
-
public static IRubyObject execute_insert(final IRubyObject recv, final IRubyObject sql) throws SQLException {
|
662
|
-
return withConnectionAndRetry(recv, new SQLBlock() {
|
663
|
-
public IRubyObject call(Connection c) throws SQLException {
|
664
|
-
Statement stmt = null;
|
665
|
-
try {
|
666
|
-
stmt = c.createStatement();
|
667
|
-
stmt.executeUpdate(rubyApi.convertToRubyString(sql).getUnicodeValue(), Statement.RETURN_GENERATED_KEYS);
|
668
|
-
return unmarshal_id_result(recv.getRuntime(), stmt.getGeneratedKeys());
|
669
|
-
} finally {
|
670
|
-
if (null != stmt) {
|
671
|
-
try {
|
672
|
-
stmt.close();
|
673
|
-
} catch (Exception e) {
|
674
|
-
}
|
675
|
-
}
|
676
|
-
}
|
677
|
-
}
|
678
|
-
});
|
679
|
-
}
|
680
|
-
|
681
|
-
public static IRubyObject unmarshal_result_downcase(IRubyObject recv, ResultSet rs) throws SQLException, IOException {
|
682
|
-
List results = new ArrayList();
|
683
|
-
Ruby runtime = recv.getRuntime();
|
684
|
-
try {
|
685
|
-
ResultSetMetaData metadata = rs.getMetaData();
|
686
|
-
int col_count = metadata.getColumnCount();
|
687
|
-
IRubyObject[] col_names = new IRubyObject[col_count];
|
688
|
-
int[] col_types = new int[col_count];
|
689
|
-
int[] col_scale = new int[col_count];
|
690
|
-
|
691
|
-
for(int i=0;i<col_count;i++) {
|
692
|
-
col_names[i] = RubyString.newUnicodeString(runtime, metadata.getColumnLabel(i+1).toLowerCase());
|
693
|
-
col_types[i] = metadata.getColumnType(i+1);
|
694
|
-
col_scale[i] = metadata.getScale(i+1);
|
695
|
-
}
|
696
|
-
|
697
|
-
while(rs.next()) {
|
698
|
-
RubyHash row = RubyHash.newHash(runtime);
|
699
|
-
for(int i=0;i<col_count;i++) {
|
700
|
-
rubyApi.callMethod(row, "[]=", new IRubyObject[] {
|
701
|
-
col_names[i], jdbc_to_ruby(runtime, i+1, col_types[i], col_scale[i], rs)
|
702
|
-
});
|
703
|
-
}
|
704
|
-
results.add(row);
|
705
|
-
}
|
706
|
-
} finally {
|
707
|
-
try {
|
708
|
-
rs.close();
|
709
|
-
} catch(Exception e) {}
|
710
|
-
}
|
711
|
-
|
712
|
-
return runtime.newArray(results);
|
713
|
-
}
|
714
|
-
|
715
|
-
public static IRubyObject unmarshal_result(IRubyObject recv, ResultSet rs) throws SQLException {
|
716
|
-
Ruby runtime = recv.getRuntime();
|
717
|
-
List results = new ArrayList();
|
718
|
-
try {
|
719
|
-
ResultSetMetaData metadata = rs.getMetaData();
|
720
|
-
boolean storesUpper = rs.getStatement().getConnection().getMetaData().storesUpperCaseIdentifiers();
|
721
|
-
int col_count = metadata.getColumnCount();
|
722
|
-
IRubyObject[] col_names = new IRubyObject[col_count];
|
723
|
-
int[] col_types = new int[col_count];
|
724
|
-
int[] col_scale = new int[col_count];
|
725
|
-
|
726
|
-
for(int i=0;i<col_count;i++) {
|
727
|
-
String s1 = metadata.getColumnLabel(i+1);
|
728
|
-
if(storesUpper && !HAS_SMALL.matcher(s1).find()) {
|
729
|
-
s1 = s1.toLowerCase();
|
730
|
-
}
|
731
|
-
col_names[i] = RubyString.newUnicodeString(runtime, s1);
|
732
|
-
col_types[i] = metadata.getColumnType(i+1);
|
733
|
-
col_scale[i] = metadata.getScale(i+1);
|
734
|
-
}
|
735
|
-
|
736
|
-
while(rs.next()) {
|
737
|
-
RubyHash row = RubyHash.newHash(runtime);
|
738
|
-
for(int i=0;i<col_count;i++) {
|
739
|
-
rubyApi.callMethod(row, "[]=", new IRubyObject[] {
|
740
|
-
col_names[i], jdbc_to_ruby(runtime, i+1, col_types[i], col_scale[i], rs)
|
741
|
-
});
|
742
|
-
}
|
743
|
-
results.add(row);
|
744
|
-
}
|
745
|
-
} finally {
|
746
|
-
try {
|
747
|
-
rs.close();
|
748
|
-
} catch(Exception e) {}
|
749
|
-
}
|
750
|
-
return runtime.newArray(results);
|
751
|
-
}
|
752
|
-
|
753
|
-
@JRubyMethod(name = "unmarshal_result", required = 1)
|
754
|
-
public static IRubyObject unmarshal_result(IRubyObject recv, IRubyObject resultset, Block row_filter) throws SQLException, IOException {
|
755
|
-
Ruby runtime = recv.getRuntime();
|
756
|
-
ResultSet rs = intoResultSet(resultset);
|
757
|
-
List results = new ArrayList();
|
758
|
-
try {
|
759
|
-
ResultSetMetaData metadata = rs.getMetaData();
|
760
|
-
int col_count = metadata.getColumnCount();
|
761
|
-
IRubyObject[] col_names = new IRubyObject[col_count];
|
762
|
-
int[] col_types = new int[col_count];
|
763
|
-
int[] col_scale = new int[col_count];
|
764
|
-
|
765
|
-
for (int i=0;i<col_count;i++) {
|
766
|
-
col_names[i] = RubyString.newUnicodeString(runtime, metadata.getColumnLabel(i+1));
|
767
|
-
col_types[i] = metadata.getColumnType(i+1);
|
768
|
-
col_scale[i] = metadata.getScale(i+1);
|
769
|
-
}
|
770
|
-
|
771
|
-
if (row_filter.isGiven()) {
|
772
|
-
while (rs.next()) {
|
773
|
-
if (row_filter.yield(runtime.getCurrentContext(),resultset).isTrue()) {
|
774
|
-
RubyHash row = RubyHash.newHash(runtime);
|
775
|
-
for (int i=0;i<col_count;i++) {
|
776
|
-
rubyApi.callMethod(row, "[]=", new IRubyObject[] {
|
777
|
-
col_names[i], jdbc_to_ruby(runtime, i+1, col_types[i], col_scale[i], rs)
|
778
|
-
});
|
779
|
-
}
|
780
|
-
results.add(row);
|
781
|
-
}
|
782
|
-
}
|
783
|
-
} else {
|
784
|
-
while (rs.next()) {
|
785
|
-
RubyHash row = RubyHash.newHash(runtime);
|
786
|
-
for (int i=0;i<col_count;i++) {
|
787
|
-
rubyApi.callMethod(row, "[]=", new IRubyObject[] {
|
788
|
-
col_names[i], jdbc_to_ruby(runtime, i+1, col_types[i], col_scale[i], rs)
|
789
|
-
});
|
790
|
-
}
|
791
|
-
results.add(row);
|
792
|
-
}
|
793
|
-
}
|
794
|
-
|
795
|
-
} finally {
|
796
|
-
try {
|
797
|
-
rs.close();
|
798
|
-
} catch(Exception e) {}
|
799
|
-
}
|
800
|
-
|
801
|
-
return runtime.newArray(results);
|
802
|
-
}
|
803
|
-
|
804
|
-
private static IRubyObject jdbc_to_ruby(Ruby runtime, int row, int type, int scale, ResultSet rs) throws SQLException {
|
805
|
-
try {
|
806
|
-
int n;
|
807
|
-
switch (type) {
|
808
|
-
case Types.BINARY:
|
809
|
-
case Types.BLOB:
|
810
|
-
case Types.LONGVARBINARY:
|
811
|
-
case Types.VARBINARY:
|
812
|
-
InputStream is = rs.getBinaryStream(row);
|
813
|
-
if (is == null || rs.wasNull()) {
|
814
|
-
return runtime.getNil();
|
815
|
-
}
|
816
|
-
ByteList str = new ByteList(2048);
|
817
|
-
byte[] buf = new byte[2048];
|
818
|
-
|
819
|
-
while ((n = is.read(buf)) != -1) {
|
820
|
-
str.append(buf, 0, n);
|
821
|
-
}
|
822
|
-
is.close();
|
823
|
-
|
824
|
-
return runtime.newString(str);
|
825
|
-
case Types.LONGVARCHAR:
|
826
|
-
case Types.CLOB:
|
827
|
-
Reader rss = rs.getCharacterStream(row);
|
828
|
-
if (rss == null || rs.wasNull()) {
|
829
|
-
return runtime.getNil();
|
830
|
-
}
|
831
|
-
StringBuffer str2 = new StringBuffer(2048);
|
832
|
-
char[] cuf = new char[2048];
|
833
|
-
while ((n = rss.read(cuf)) != -1) {
|
834
|
-
str2.append(cuf, 0, n);
|
835
|
-
}
|
836
|
-
rss.close();
|
837
|
-
return RubyString.newUnicodeString(runtime, str2.toString());
|
838
|
-
case Types.TIMESTAMP:
|
839
|
-
Timestamp time = rs.getTimestamp(row);
|
840
|
-
if (time == null || rs.wasNull()) {
|
841
|
-
return runtime.getNil();
|
842
|
-
}
|
843
|
-
String sttr = time.toString();
|
844
|
-
if (sttr.endsWith(" 00:00:00.0")) {
|
845
|
-
sttr = sttr.substring(0, sttr.length() - (" 00:00:00.0".length()));
|
846
|
-
}
|
847
|
-
return RubyString.newUnicodeString(runtime, sttr);
|
848
|
-
default:
|
849
|
-
String vs = rs.getString(row);
|
850
|
-
if (vs == null || rs.wasNull()) {
|
851
|
-
return runtime.getNil();
|
852
|
-
}
|
853
|
-
|
854
|
-
return RubyString.newUnicodeString(runtime, vs);
|
855
|
-
}
|
856
|
-
} catch (IOException ioe) {
|
857
|
-
throw (SQLException) new SQLException(ioe.getMessage()).initCause(ioe);
|
858
|
-
}
|
859
|
-
}
|
860
|
-
|
861
|
-
public static IRubyObject unmarshal_id_result(Ruby runtime, ResultSet rs) throws SQLException {
|
862
|
-
try {
|
863
|
-
if(rs.next()) {
|
864
|
-
if(rs.getMetaData().getColumnCount() > 0) {
|
865
|
-
return runtime.newFixnum(rs.getLong(1));
|
866
|
-
}
|
867
|
-
}
|
868
|
-
return runtime.getNil();
|
869
|
-
} finally {
|
870
|
-
try {
|
871
|
-
rs.close();
|
872
|
-
} catch(Exception e) {}
|
873
|
-
}
|
874
|
-
}
|
875
|
-
|
876
|
-
private static String convertToStringOrNull(IRubyObject obj) {
|
877
|
-
if (obj.isNil()) {
|
878
|
-
return null;
|
879
|
-
}
|
880
|
-
return obj.toString();
|
881
|
-
}
|
882
|
-
|
883
|
-
private static int getTypeValueFor(Ruby runtime, IRubyObject type) throws SQLException {
|
884
|
-
if(!(type instanceof RubySymbol)) {
|
885
|
-
type = rubyApi.callMethod(type, "class");
|
886
|
-
}
|
887
|
-
if(type == runtime.newSymbol("string")) {
|
888
|
-
return Types.VARCHAR;
|
889
|
-
} else if(type == runtime.newSymbol("text")) {
|
890
|
-
return Types.CLOB;
|
891
|
-
} else if(type == runtime.newSymbol("integer")) {
|
892
|
-
return Types.INTEGER;
|
893
|
-
} else if(type == runtime.newSymbol("decimal")) {
|
894
|
-
return Types.DECIMAL;
|
895
|
-
} else if(type == runtime.newSymbol("float")) {
|
896
|
-
return Types.FLOAT;
|
897
|
-
} else if(type == runtime.newSymbol("datetime")) {
|
898
|
-
return Types.TIMESTAMP;
|
899
|
-
} else if(type == runtime.newSymbol("timestamp")) {
|
900
|
-
return Types.TIMESTAMP;
|
901
|
-
} else if(type == runtime.newSymbol("time")) {
|
902
|
-
return Types.TIME;
|
903
|
-
} else if(type == runtime.newSymbol("date")) {
|
904
|
-
return Types.DATE;
|
905
|
-
} else if(type == runtime.newSymbol("binary")) {
|
906
|
-
return Types.BLOB;
|
907
|
-
} else if(type == runtime.newSymbol("boolean")) {
|
908
|
-
return Types.BOOLEAN;
|
909
|
-
} else {
|
910
|
-
return -1;
|
911
|
-
}
|
912
|
-
}
|
913
|
-
|
914
|
-
private final static DateFormat FORMAT = new SimpleDateFormat("%y-%M-%d %H:%m:%s");
|
915
|
-
|
916
|
-
private static void setValue(PreparedStatement ps, int index, Ruby runtime, ThreadContext context,
|
917
|
-
IRubyObject value, IRubyObject type) throws SQLException {
|
918
|
-
final int tp = getTypeValueFor(runtime, type);
|
919
|
-
if(value.isNil()) {
|
920
|
-
ps.setNull(index, tp);
|
921
|
-
return;
|
922
|
-
}
|
923
|
-
|
924
|
-
switch(tp) {
|
925
|
-
case Types.VARCHAR:
|
926
|
-
case Types.CLOB:
|
927
|
-
ps.setString(index, RubyString.objAsString(context, value).toString());
|
928
|
-
break;
|
929
|
-
case Types.INTEGER:
|
930
|
-
ps.setLong(index, RubyNumeric.fix2long(value));
|
931
|
-
break;
|
932
|
-
case Types.FLOAT:
|
933
|
-
ps.setDouble(index, ((RubyNumeric)value).getDoubleValue());
|
934
|
-
break;
|
935
|
-
case Types.TIMESTAMP:
|
936
|
-
case Types.TIME:
|
937
|
-
case Types.DATE:
|
938
|
-
if(!(value instanceof RubyTime)) {
|
939
|
-
try {
|
940
|
-
Date dd = FORMAT.parse(RubyString.objAsString(context, value).toString());
|
941
|
-
ps.setTimestamp(index, new java.sql.Timestamp(dd.getTime()), Calendar.getInstance());
|
942
|
-
} catch(Exception e) {
|
943
|
-
ps.setString(index, RubyString.objAsString(context, value).toString());
|
944
|
-
}
|
945
|
-
} else {
|
946
|
-
RubyTime rubyTime = (RubyTime) value;
|
947
|
-
java.util.Date date = rubyTime.getJavaDate();
|
948
|
-
long millis = date.getTime();
|
949
|
-
long micros = rubyTime.microseconds() - millis / 1000;
|
950
|
-
java.sql.Timestamp ts = new java.sql.Timestamp(millis);
|
951
|
-
java.util.Calendar cal = Calendar.getInstance();
|
952
|
-
cal.setTime(date);
|
953
|
-
ts.setNanos((int)(micros * 1000));
|
954
|
-
ps.setTimestamp(index, ts, cal);
|
955
|
-
}
|
956
|
-
break;
|
957
|
-
case Types.BOOLEAN:
|
958
|
-
ps.setBoolean(index, value.isTrue());
|
959
|
-
break;
|
960
|
-
default: throw new RuntimeException("type " + type + " not supported in _bind yet");
|
961
|
-
}
|
962
|
-
}
|
963
|
-
|
964
|
-
private static void setValuesOnPS(PreparedStatement ps, Ruby runtime, ThreadContext context,
|
965
|
-
IRubyObject values, IRubyObject types) throws SQLException {
|
966
|
-
RubyArray vals = (RubyArray)values;
|
967
|
-
RubyArray tps = (RubyArray)types;
|
968
|
-
|
969
|
-
for(int i=0, j=vals.getLength(); i<j; i++) {
|
970
|
-
setValue(ps, i+1, runtime, context, vals.eltInternal(i), tps.eltInternal(i));
|
971
|
-
}
|
972
|
-
}
|
973
|
-
|
974
|
-
/*
|
975
|
-
* sql, values, types, name = nil, pk = nil, id_value = nil, sequence_name = nil
|
976
|
-
*/
|
977
|
-
@JRubyMethod(name = "insert_bind", required = 3, rest = true)
|
978
|
-
public static IRubyObject insert_bind(final ThreadContext context, IRubyObject recv, final IRubyObject[] args) throws SQLException {
|
979
|
-
final Ruby runtime = recv.getRuntime();
|
980
|
-
return withConnectionAndRetry(recv, new SQLBlock() {
|
981
|
-
public IRubyObject call(Connection c) throws SQLException {
|
982
|
-
PreparedStatement ps = null;
|
983
|
-
try {
|
984
|
-
ps = c.prepareStatement(rubyApi.convertToRubyString(args[0]).toString(), Statement.RETURN_GENERATED_KEYS);
|
985
|
-
setValuesOnPS(ps, runtime, context, args[1], args[2]);
|
986
|
-
ps.executeUpdate();
|
987
|
-
return unmarshal_id_result(runtime, ps.getGeneratedKeys());
|
988
|
-
} finally {
|
989
|
-
try {
|
990
|
-
ps.close();
|
991
|
-
} catch (Exception e) {
|
992
|
-
}
|
993
|
-
}
|
994
|
-
}
|
995
|
-
});
|
996
|
-
}
|
997
|
-
|
998
|
-
/*
|
999
|
-
* sql, values, types, name = nil
|
1000
|
-
*/
|
1001
|
-
@JRubyMethod(name = "update_bind", required = 3, rest = true)
|
1002
|
-
public static IRubyObject update_bind(final ThreadContext context, IRubyObject recv, final IRubyObject[] args) throws SQLException {
|
1003
|
-
final Ruby runtime = recv.getRuntime();
|
1004
|
-
Arity.checkArgumentCount(runtime, args, 3, 4);
|
1005
|
-
return withConnectionAndRetry(recv, new SQLBlock() {
|
1006
|
-
public IRubyObject call(Connection c) throws SQLException {
|
1007
|
-
PreparedStatement ps = null;
|
1008
|
-
try {
|
1009
|
-
ps = c.prepareStatement(rubyApi.convertToRubyString(args[0]).toString());
|
1010
|
-
setValuesOnPS(ps, runtime, context, args[1], args[2]);
|
1011
|
-
ps.executeUpdate();
|
1012
|
-
} finally {
|
1013
|
-
try {
|
1014
|
-
ps.close();
|
1015
|
-
} catch (Exception e) {
|
1016
|
-
}
|
1017
|
-
}
|
1018
|
-
return runtime.getNil();
|
1019
|
-
}
|
1020
|
-
});
|
1021
|
-
}
|
1022
|
-
|
1023
|
-
/*
|
1024
|
-
* (is binary?, colname, tablename, primary key, id, value)
|
1025
|
-
*/
|
1026
|
-
@JRubyMethod(name = "write_large_object", required = 6)
|
1027
|
-
public static IRubyObject write_large_object(IRubyObject recv, final IRubyObject[] args)
|
1028
|
-
throws SQLException, IOException {
|
1029
|
-
final Ruby runtime = recv.getRuntime();
|
1030
|
-
return withConnectionAndRetry(recv, new SQLBlock() {
|
1031
|
-
public IRubyObject call(Connection c) throws SQLException {
|
1032
|
-
String sql = "UPDATE " + rubyApi.convertToRubyString(args[2])
|
1033
|
-
+ " SET " + rubyApi.convertToRubyString(args[1])
|
1034
|
-
+ " = ? WHERE " + rubyApi.convertToRubyString(args[3])
|
1035
|
-
+ "=" + rubyApi.convertToRubyString(args[4]);
|
1036
|
-
PreparedStatement ps = null;
|
1037
|
-
try {
|
1038
|
-
ps = c.prepareStatement(sql);
|
1039
|
-
if (args[0].isTrue()) { // binary
|
1040
|
-
ByteList outp = rubyApi.convertToRubyString(args[5]).getByteList();
|
1041
|
-
ps.setBinaryStream(1, new ByteArrayInputStream(outp.bytes,
|
1042
|
-
outp.begin, outp.realSize), outp.realSize);
|
1043
|
-
} else { // clob
|
1044
|
-
String ss = rubyApi.convertToRubyString(args[5]).getUnicodeValue();
|
1045
|
-
ps.setCharacterStream(1, new StringReader(ss), ss.length());
|
1046
|
-
}
|
1047
|
-
ps.executeUpdate();
|
1048
|
-
} finally {
|
1049
|
-
try {
|
1050
|
-
ps.close();
|
1051
|
-
} catch (Exception e) {
|
1052
|
-
}
|
1053
|
-
}
|
1054
|
-
return runtime.getNil();
|
1055
|
-
}
|
1056
|
-
});
|
1057
|
-
}
|
1058
|
-
|
1059
|
-
private static Connection getConnection(IRubyObject recv) {
|
1060
|
-
return getConnection(recv, false);
|
1061
|
-
}
|
1062
|
-
|
1063
|
-
private static Connection getConnection(IRubyObject recv, boolean error) {
|
1064
|
-
Connection conn = (Connection) recv.dataGetStruct();
|
1065
|
-
if(error && conn == null) {
|
1066
|
-
RubyClass err = recv.getRuntime().getModule("ActiveRecord").getClass("ConnectionNotEstablished");
|
1067
|
-
throw new RaiseException(recv.getRuntime(), err, "no connection available", false);
|
1068
|
-
}
|
1069
|
-
return conn;
|
1070
|
-
}
|
1071
|
-
|
1072
|
-
private static RuntimeException wrap(IRubyObject recv, Throwable exception) {
|
1073
|
-
RubyClass err = recv.getRuntime().getModule("ActiveRecord").getClass("ActiveRecordError");
|
1074
|
-
return (RuntimeException) new RaiseException(recv.getRuntime(), err, exception.getMessage(), false).initCause(exception);
|
1075
|
-
}
|
1076
|
-
|
1077
|
-
private static ResultSet intoResultSet(IRubyObject inp) {
|
1078
|
-
JavaObject jo;
|
1079
|
-
if (inp instanceof JavaObject) {
|
1080
|
-
jo = (JavaObject) inp;
|
1081
|
-
} else {
|
1082
|
-
jo = (JavaObject) rubyApi.getInstanceVariable(inp, "@java_object");
|
1083
|
-
}
|
1084
|
-
return (ResultSet) jo.getValue();
|
1085
|
-
}
|
1086
|
-
|
1087
|
-
private static boolean isConnectionBroken(IRubyObject recv, Connection c) {
|
1088
|
-
try {
|
1089
|
-
IRubyObject alive = config_value(recv, "connection_alive_sql");
|
1090
|
-
if (select_p(recv, alive).isTrue()) {
|
1091
|
-
String connectionSQL = rubyApi.convertToRubyString(alive).toString();
|
1092
|
-
Statement s = c.createStatement();
|
1093
|
-
try {
|
1094
|
-
s.execute(connectionSQL);
|
1095
|
-
} finally {
|
1096
|
-
try { s.close(); } catch (SQLException ignored) {}
|
1097
|
-
}
|
1098
|
-
return false;
|
1099
|
-
} else {
|
1100
|
-
return !c.isClosed();
|
1101
|
-
}
|
1102
|
-
} catch (SQLException sx) {
|
1103
|
-
return true;
|
1104
|
-
}
|
1105
|
-
}
|
1106
|
-
|
1107
|
-
private static IRubyObject setConnection(IRubyObject recv, Connection c) {
|
1108
|
-
Connection prev = getConnection(recv);
|
1109
|
-
if (prev != null) {
|
1110
|
-
try {
|
1111
|
-
prev.close();
|
1112
|
-
} catch(Exception e) {}
|
1113
|
-
}
|
1114
|
-
IRubyObject rubyconn = recv.getRuntime().getNil();
|
1115
|
-
if (c != null) {
|
1116
|
-
rubyconn = wrappedConnection(recv,c);
|
1117
|
-
}
|
1118
|
-
rubyApi.setInstanceVariable(recv, "@connection", rubyconn);
|
1119
|
-
recv.dataWrapStruct(c);
|
1120
|
-
return recv;
|
1121
|
-
}
|
1122
|
-
|
1123
|
-
private static IRubyObject wrappedConnection(IRubyObject recv, Connection c) {
|
1124
|
-
return Java.java_to_ruby(recv, JavaObject.wrap(recv.getRuntime(), c), Block.NULL_BLOCK);
|
1125
|
-
}
|
1126
|
-
|
1127
|
-
private static JdbcConnectionFactory getConnectionFactory(IRubyObject recv) throws RaiseException {
|
1128
|
-
IRubyObject connection_factory = rubyApi.getInstanceVariable(recv, "@connection_factory");
|
1129
|
-
JdbcConnectionFactory factory = null;
|
1130
|
-
try {
|
1131
|
-
factory = (JdbcConnectionFactory) JavaEmbedUtils.rubyToJava(
|
1132
|
-
recv.getRuntime(), connection_factory, JdbcConnectionFactory.class);
|
1133
|
-
} catch (Exception e) {
|
1134
|
-
factory = null;
|
1135
|
-
}
|
1136
|
-
if (factory == null) {
|
1137
|
-
throw recv.getRuntime().newRuntimeError("@connection_factory not set properly");
|
1138
|
-
}
|
1139
|
-
return factory;
|
1140
|
-
}
|
1141
|
-
|
1142
|
-
private static IRubyObject config_value(IRubyObject recv, String key) {
|
1143
|
-
Ruby runtime = recv.getRuntime();
|
1144
|
-
IRubyObject config_hash = rubyApi.getInstanceVariable(recv, "@config");
|
1145
|
-
return rubyApi.callMethod(config_hash, "[]", runtime.newSymbol(key));
|
1146
|
-
}
|
1147
52
|
}
|