ActiveRecord-JDBC 0.4 → 0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +12 -0
- data/Manifest.txt +13 -0
- data/Rakefile +18 -10
- data/lib/active_record/connection_adapters/derby_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/h2_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/hsqldb_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/jdbc_adapter.rb +124 -56
- data/lib/active_record/connection_adapters/jndi_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/mysql_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/oracle_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +1 -0
- data/lib/jdbc_adapter/jdbc_db2.rb +21 -0
- data/lib/jdbc_adapter/jdbc_derby.rb +22 -101
- data/lib/jdbc_adapter/jdbc_firebird.rb +5 -1
- data/lib/jdbc_adapter/jdbc_hsqldb.rb +23 -1
- data/lib/jdbc_adapter/jdbc_mimer.rb +4 -2
- data/lib/jdbc_adapter/jdbc_mssql.rb +149 -67
- data/lib/jdbc_adapter/jdbc_mysql.rb +22 -2
- data/lib/jdbc_adapter/jdbc_oracle.rb +80 -15
- data/lib/jdbc_adapter/jdbc_postgre.rb +132 -4
- data/lib/jdbc_adapter_internal.jar +0 -0
- data/src/java/JDBCDerbySpec.java +323 -0
- data/src/java/JDBCMySQLSpec.java +83 -0
- data/src/java/JdbcAdapterInternalService.java +802 -0
- data/test/activerecord/connection_adapters/type_conversion_test.rb +1 -0
- data/test/db/derby.rb +2 -5
- data/test/db/h2.rb +2 -5
- data/test/db/hsqldb.rb +2 -6
- data/test/db/jdbc.rb +9 -0
- data/test/db/mysql.rb +4 -15
- data/test/db/postgres.rb +2 -3
- data/test/generic_jdbc_connection_test.rb +9 -0
- data/test/jdbc_adapter/jdbc_db2_test.rb +21 -0
- data/test/simple.rb +6 -8
- metadata +15 -2
@@ -0,0 +1,83 @@
|
|
1
|
+
/***** BEGIN LICENSE BLOCK *****
|
2
|
+
* Version: CPL 1.0/GPL 2.0/LGPL 2.1
|
3
|
+
*
|
4
|
+
* The contents of this file are subject to the Common Public
|
5
|
+
* License Version 1.0 (the "License"); you may not use this file
|
6
|
+
* except in compliance with the License. You may obtain a copy of
|
7
|
+
* the License at http://www.eclipse.org/legal/cpl-v10.html
|
8
|
+
*
|
9
|
+
* Software distributed under the License is distributed on an "AS
|
10
|
+
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
11
|
+
* implied. See the License for the specific language governing
|
12
|
+
* rights and limitations under the License.
|
13
|
+
*
|
14
|
+
* Copyright (C) 2007 Ola Bini <ola.bini@gmail.com>
|
15
|
+
*
|
16
|
+
* Alternatively, the contents of this file may be used under the terms of
|
17
|
+
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
18
|
+
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
19
|
+
* in which case the provisions of the GPL or the LGPL are applicable instead
|
20
|
+
* of those above. If you wish to allow use of your version of this file only
|
21
|
+
* under the terms of either the GPL or the LGPL, and not to allow others to
|
22
|
+
* use your version of this file under the terms of the CPL, indicate your
|
23
|
+
* decision by deleting the provisions above and replace them with the notice
|
24
|
+
* and other provisions required by the GPL or the LGPL. If you do not delete
|
25
|
+
* the provisions above, a recipient may use your version of this file under
|
26
|
+
* the terms of any one of the CPL, the GPL or the LGPL.
|
27
|
+
***** END LICENSE BLOCK *****/
|
28
|
+
|
29
|
+
import org.jruby.Ruby;
|
30
|
+
import org.jruby.RubyModule;
|
31
|
+
import org.jruby.RubyString;
|
32
|
+
|
33
|
+
import org.jruby.runtime.CallbackFactory;
|
34
|
+
import org.jruby.runtime.ThreadContext;
|
35
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
36
|
+
|
37
|
+
import org.jruby.util.ByteList;
|
38
|
+
|
39
|
+
public class JDBCMySQLSpec {
|
40
|
+
public static void load(Ruby runtime, RubyModule jdbcSpec) {
|
41
|
+
RubyModule mysql = jdbcSpec.defineModuleUnder("MySQL");
|
42
|
+
CallbackFactory cf = runtime.callbackFactory(JDBCMySQLSpec.class);
|
43
|
+
mysql.defineFastMethod("quote_string",cf.getFastSingletonMethod("quote_string",IRubyObject.class));
|
44
|
+
}
|
45
|
+
|
46
|
+
private final static ByteList ZERO = new ByteList(new byte[]{'\\','0'});
|
47
|
+
private final static ByteList NEWLINE = new ByteList(new byte[]{'\\','n'});
|
48
|
+
private final static ByteList CARRIAGE = new ByteList(new byte[]{'\\','r'});
|
49
|
+
private final static ByteList ZED = new ByteList(new byte[]{'\\','Z'});
|
50
|
+
private final static ByteList DBL = new ByteList(new byte[]{'\\','"'});
|
51
|
+
private final static ByteList SINGLE = new ByteList(new byte[]{'\\','\''});
|
52
|
+
private final static ByteList ESCAPE = new ByteList(new byte[]{'\\','\\'});
|
53
|
+
|
54
|
+
public static IRubyObject quote_string(IRubyObject recv, IRubyObject string) {
|
55
|
+
boolean replacementFound = false;
|
56
|
+
ByteList bl = ((RubyString) string).getByteList();
|
57
|
+
|
58
|
+
for(int i = bl.begin; i < bl.begin + bl.realSize; i++) {
|
59
|
+
ByteList rep = null;
|
60
|
+
switch (bl.bytes[i]) {
|
61
|
+
case 0: rep = ZERO; break;
|
62
|
+
case '\n': rep = NEWLINE; break;
|
63
|
+
case '\r': rep = CARRIAGE; break;
|
64
|
+
case 26: rep = ZED; break;
|
65
|
+
case '"': rep = DBL; break;
|
66
|
+
case '\'': rep = SINGLE; break;
|
67
|
+
case '\\': rep = ESCAPE; break;
|
68
|
+
default: continue;
|
69
|
+
}
|
70
|
+
|
71
|
+
// On first replacement allocate a different bytelist so we don't manip original
|
72
|
+
if(!replacementFound) {
|
73
|
+
i-= bl.begin;
|
74
|
+
bl = new ByteList(bl);
|
75
|
+
replacementFound = true;
|
76
|
+
}
|
77
|
+
|
78
|
+
bl.replace(i, 1, rep);
|
79
|
+
i+=1;
|
80
|
+
}
|
81
|
+
return recv.getRuntime().newStringShared(bl);
|
82
|
+
}
|
83
|
+
}
|
@@ -0,0 +1,802 @@
|
|
1
|
+
/***** BEGIN LICENSE BLOCK *****
|
2
|
+
* Version: CPL 1.0/GPL 2.0/LGPL 2.1
|
3
|
+
*
|
4
|
+
* The contents of this file are subject to the Common Public
|
5
|
+
* License Version 1.0 (the "License"); you may not use this file
|
6
|
+
* except in compliance with the License. You may obtain a copy of
|
7
|
+
* the License at http://www.eclipse.org/legal/cpl-v10.html
|
8
|
+
*
|
9
|
+
* Software distributed under the License is distributed on an "AS
|
10
|
+
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
11
|
+
* implied. See the License for the specific language governing
|
12
|
+
* rights and limitations under the License.
|
13
|
+
*
|
14
|
+
* Copyright (C) 2007 Ola Bini <ola@ologix.com>
|
15
|
+
*
|
16
|
+
* Alternatively, the contents of this file may be used under the terms of
|
17
|
+
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
18
|
+
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
19
|
+
* in which case the provisions of the GPL or the LGPL are applicable instead
|
20
|
+
* of those above. If you wish to allow use of your version of this file only
|
21
|
+
* under the terms of either the GPL or the LGPL, and not to allow others to
|
22
|
+
* use your version of this file under the terms of the CPL, indicate your
|
23
|
+
* decision by deleting the provisions above and replace them with the notice
|
24
|
+
* and other provisions required by the GPL or the LGPL. If you do not delete
|
25
|
+
* the provisions above, a recipient may use your version of this file under
|
26
|
+
* the terms of any one of the CPL, the GPL or the LGPL.
|
27
|
+
***** END LICENSE BLOCK *****/
|
28
|
+
import java.io.IOException;
|
29
|
+
import java.io.Reader;
|
30
|
+
import java.io.InputStream;
|
31
|
+
import java.io.ByteArrayInputStream;
|
32
|
+
import java.io.StringReader;
|
33
|
+
|
34
|
+
import java.sql.Connection;
|
35
|
+
import java.sql.DatabaseMetaData;
|
36
|
+
import java.sql.PreparedStatement;
|
37
|
+
import java.sql.ResultSetMetaData;
|
38
|
+
import java.sql.ResultSet;
|
39
|
+
import java.sql.SQLException;
|
40
|
+
import java.sql.Statement;
|
41
|
+
import java.sql.PreparedStatement;
|
42
|
+
import java.sql.Timestamp;
|
43
|
+
import java.sql.Types;
|
44
|
+
|
45
|
+
import java.text.DateFormat;
|
46
|
+
import java.text.SimpleDateFormat;
|
47
|
+
|
48
|
+
import java.util.ArrayList;
|
49
|
+
import java.util.Calendar;
|
50
|
+
import java.util.Date;
|
51
|
+
import java.util.List;
|
52
|
+
import java.util.Map;
|
53
|
+
import java.util.Iterator;
|
54
|
+
import java.util.HashMap;
|
55
|
+
|
56
|
+
import org.jruby.Ruby;
|
57
|
+
import org.jruby.RubyArray;
|
58
|
+
import org.jruby.RubyBigDecimal;
|
59
|
+
import org.jruby.RubyClass;
|
60
|
+
import org.jruby.RubyHash;
|
61
|
+
import org.jruby.RubyModule;
|
62
|
+
import org.jruby.RubyNumeric;
|
63
|
+
import org.jruby.RubyObject;
|
64
|
+
import org.jruby.RubyString;
|
65
|
+
import org.jruby.RubySymbol;
|
66
|
+
import org.jruby.RubyTime;
|
67
|
+
import org.jruby.javasupport.JavaObject;
|
68
|
+
import org.jruby.runtime.Arity;
|
69
|
+
import org.jruby.runtime.Block;
|
70
|
+
import org.jruby.runtime.CallbackFactory;
|
71
|
+
import org.jruby.runtime.ThreadContext;
|
72
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
73
|
+
import org.jruby.runtime.load.BasicLibraryService;
|
74
|
+
import org.jruby.util.ByteList;
|
75
|
+
|
76
|
+
public class JdbcAdapterInternalService implements BasicLibraryService {
|
77
|
+
public boolean basicLoad(final Ruby runtime) throws IOException {
|
78
|
+
RubyClass cJdbcConn = ((RubyModule)(runtime.getModule("ActiveRecord").getConstant("ConnectionAdapters"))).
|
79
|
+
defineClassUnder("JdbcConnection",runtime.getObject(),runtime.getObject().getAllocator());
|
80
|
+
|
81
|
+
CallbackFactory cf = runtime.callbackFactory(JdbcAdapterInternalService.class);
|
82
|
+
cJdbcConn.defineMethod("unmarshal_result",cf.getSingletonMethod("unmarshal_result", IRubyObject.class));
|
83
|
+
cJdbcConn.defineFastMethod("set_connection",cf.getFastSingletonMethod("set_connection", IRubyObject.class));
|
84
|
+
cJdbcConn.defineFastMethod("execute_update",cf.getFastSingletonMethod("execute_update", IRubyObject.class));
|
85
|
+
cJdbcConn.defineFastMethod("execute_query",cf.getFastOptSingletonMethod("execute_query"));
|
86
|
+
cJdbcConn.defineFastMethod("execute_insert",cf.getFastSingletonMethod("execute_insert", IRubyObject.class));
|
87
|
+
cJdbcConn.defineFastMethod("execute_id_insert",cf.getFastSingletonMethod("execute_id_insert", IRubyObject.class, IRubyObject.class));
|
88
|
+
cJdbcConn.defineFastMethod("primary_keys",cf.getFastSingletonMethod("primary_keys", IRubyObject.class));
|
89
|
+
cJdbcConn.defineFastMethod("set_native_database_types",cf.getFastSingletonMethod("set_native_database_types"));
|
90
|
+
cJdbcConn.defineFastMethod("native_database_types",cf.getFastSingletonMethod("native_database_types"));
|
91
|
+
cJdbcConn.defineFastMethod("begin",cf.getFastSingletonMethod("begin"));
|
92
|
+
cJdbcConn.defineFastMethod("commit",cf.getFastSingletonMethod("commit"));
|
93
|
+
cJdbcConn.defineFastMethod("rollback",cf.getFastSingletonMethod("rollback"));
|
94
|
+
cJdbcConn.defineFastMethod("database_name",cf.getFastSingletonMethod("database_name"));
|
95
|
+
cJdbcConn.defineFastMethod("columns",cf.getFastOptSingletonMethod("columns_internal"));
|
96
|
+
cJdbcConn.defineFastMethod("columns_internal",cf.getFastOptSingletonMethod("columns_internal"));
|
97
|
+
cJdbcConn.defineFastMethod("tables",cf.getFastOptSingletonMethod("tables"));
|
98
|
+
|
99
|
+
cJdbcConn.defineFastMethod("insert_bind",cf.getFastOptSingletonMethod("insert_bind"));
|
100
|
+
cJdbcConn.defineFastMethod("update_bind",cf.getFastOptSingletonMethod("update_bind"));
|
101
|
+
|
102
|
+
cJdbcConn.defineFastMethod("write_large_object",cf.getFastOptSingletonMethod("write_large_object"));
|
103
|
+
|
104
|
+
RubyModule jdbcSpec = runtime.getOrCreateModule("JdbcSpec");
|
105
|
+
JDBCMySQLSpec.load(runtime, jdbcSpec);
|
106
|
+
JDBCDerbySpec.load(runtime, jdbcSpec);
|
107
|
+
|
108
|
+
return true;
|
109
|
+
}
|
110
|
+
|
111
|
+
private static ResultSet intoResultSet(IRubyObject inp) {
|
112
|
+
return (ResultSet)((inp instanceof JavaObject ? ((JavaObject)inp) : (((JavaObject)(inp.getInstanceVariable("@java_object"))))).getValue());
|
113
|
+
}
|
114
|
+
|
115
|
+
public static IRubyObject set_connection(IRubyObject recv, IRubyObject conn) {
|
116
|
+
Connection c = (Connection)recv.dataGetStruct();
|
117
|
+
if(c != null) {
|
118
|
+
try {
|
119
|
+
c.close();
|
120
|
+
} catch(Exception e) {}
|
121
|
+
}
|
122
|
+
recv.setInstanceVariable("@connection",conn);
|
123
|
+
c = (Connection)(((JavaObject)conn.getInstanceVariable("@java_object")).getValue());
|
124
|
+
recv.dataWrapStruct(c);
|
125
|
+
return recv;
|
126
|
+
}
|
127
|
+
|
128
|
+
public static IRubyObject tables(IRubyObject recv, IRubyObject[] args) throws SQLException, IOException {
|
129
|
+
Ruby runtime = recv.getRuntime();
|
130
|
+
String catalog = null, schemapat = null, tablepat = null;
|
131
|
+
String[] types = new String[]{"TABLE"};
|
132
|
+
if (args != null) {
|
133
|
+
if (args.length > 0) {
|
134
|
+
catalog = convertToStringOrNull(args[0]);
|
135
|
+
}
|
136
|
+
if (args.length > 1) {
|
137
|
+
schemapat = convertToStringOrNull(args[1]);
|
138
|
+
}
|
139
|
+
if (args.length > 2) {
|
140
|
+
tablepat = convertToStringOrNull(args[2]);
|
141
|
+
}
|
142
|
+
if (args.length > 3) {
|
143
|
+
IRubyObject typearr = args[3];
|
144
|
+
if (typearr instanceof RubyArray) {
|
145
|
+
IRubyObject[] arr = ((RubyArray) typearr).toJavaArray();
|
146
|
+
types = new String[arr.length];
|
147
|
+
for (int i = 0; i < types.length; i++) {
|
148
|
+
types[i] = arr[i].toString();
|
149
|
+
}
|
150
|
+
} else {
|
151
|
+
types = new String[] {types.toString()};
|
152
|
+
}
|
153
|
+
}
|
154
|
+
}
|
155
|
+
while (true) {
|
156
|
+
Connection c = (Connection) recv.dataGetStruct();
|
157
|
+
ResultSet rs = null;
|
158
|
+
try {
|
159
|
+
rs = c.getMetaData().getTables(catalog, schemapat, tablepat, types);
|
160
|
+
List arr = new ArrayList();
|
161
|
+
while (rs.next()) {
|
162
|
+
arr.add(runtime.newString(rs.getString(3).toLowerCase()));
|
163
|
+
}
|
164
|
+
return runtime.newArray(arr);
|
165
|
+
} catch (SQLException e) {
|
166
|
+
if(c.isClosed()) {
|
167
|
+
recv = recv.callMethod(recv.getRuntime().getCurrentContext(),"reconnect!");
|
168
|
+
if(!((Connection)recv.dataGetStruct()).isClosed()) {
|
169
|
+
continue;
|
170
|
+
}
|
171
|
+
}
|
172
|
+
throw e;
|
173
|
+
} finally {
|
174
|
+
try {
|
175
|
+
rs.close();
|
176
|
+
} catch(Exception e) {}
|
177
|
+
}
|
178
|
+
|
179
|
+
}
|
180
|
+
}
|
181
|
+
|
182
|
+
public static IRubyObject native_database_types(IRubyObject recv) {
|
183
|
+
return recv.getInstanceVariable("@tps");
|
184
|
+
}
|
185
|
+
|
186
|
+
public static IRubyObject set_native_database_types(IRubyObject recv) throws SQLException, IOException {
|
187
|
+
Ruby runtime = recv.getRuntime();
|
188
|
+
ThreadContext ctx = runtime.getCurrentContext();
|
189
|
+
IRubyObject types = unmarshal_result_downcase(recv, ((Connection)recv.dataGetStruct()).getMetaData().getTypeInfo());
|
190
|
+
recv.setInstanceVariable("@native_types",
|
191
|
+
((RubyModule)(runtime.getModule("ActiveRecord").getConstant("ConnectionAdapters"))).
|
192
|
+
getConstant("JdbcTypeConverter").callMethod(ctx,"new", types).
|
193
|
+
callMethod(ctx, "choose_best_types"));
|
194
|
+
return runtime.getNil();
|
195
|
+
}
|
196
|
+
|
197
|
+
public static IRubyObject database_name(IRubyObject recv) throws SQLException {
|
198
|
+
String name = ((Connection)recv.dataGetStruct()).getCatalog();
|
199
|
+
if(null == name) {
|
200
|
+
name = ((Connection)recv.dataGetStruct()).getMetaData().getUserName();
|
201
|
+
if(null == name) {
|
202
|
+
name = "db1";
|
203
|
+
}
|
204
|
+
}
|
205
|
+
return recv.getRuntime().newString(name);
|
206
|
+
}
|
207
|
+
|
208
|
+
public static IRubyObject begin(IRubyObject recv) throws SQLException {
|
209
|
+
((Connection)recv.dataGetStruct()).setAutoCommit(false);
|
210
|
+
return recv.getRuntime().getNil();
|
211
|
+
}
|
212
|
+
|
213
|
+
public static IRubyObject commit(IRubyObject recv) throws SQLException {
|
214
|
+
try {
|
215
|
+
((Connection)recv.dataGetStruct()).commit();
|
216
|
+
return recv.getRuntime().getNil();
|
217
|
+
} finally {
|
218
|
+
((Connection)recv.dataGetStruct()).setAutoCommit(true);
|
219
|
+
}
|
220
|
+
}
|
221
|
+
|
222
|
+
public static IRubyObject rollback(IRubyObject recv) throws SQLException {
|
223
|
+
try {
|
224
|
+
((Connection)recv.dataGetStruct()).rollback();
|
225
|
+
return recv.getRuntime().getNil();
|
226
|
+
} finally {
|
227
|
+
((Connection)recv.dataGetStruct()).setAutoCommit(true);
|
228
|
+
}
|
229
|
+
}
|
230
|
+
|
231
|
+
public static IRubyObject columns_internal(IRubyObject recv, IRubyObject[] args) throws SQLException, IOException {
|
232
|
+
String table_name = args[0].convertToString().getUnicodeValue();
|
233
|
+
while(true) {
|
234
|
+
Connection c = (Connection)recv.dataGetStruct();
|
235
|
+
try {
|
236
|
+
DatabaseMetaData metadata = c.getMetaData();
|
237
|
+
String schemaName = null;
|
238
|
+
if(args.length>2) {
|
239
|
+
schemaName = args[2].toString();
|
240
|
+
}
|
241
|
+
if(metadata.storesUpperCaseIdentifiers()) {
|
242
|
+
table_name = table_name.toUpperCase();
|
243
|
+
} else if(metadata.storesLowerCaseIdentifiers()) {
|
244
|
+
table_name = table_name.toLowerCase();
|
245
|
+
}
|
246
|
+
if(schemaName == null) {
|
247
|
+
ResultSet schemas = metadata.getSchemas();
|
248
|
+
String username = metadata.getUserName();
|
249
|
+
while(schemas.next()) {
|
250
|
+
if(schemas.getString(1).equalsIgnoreCase(username)) {
|
251
|
+
schemaName = schemas.getString(1);
|
252
|
+
break;
|
253
|
+
}
|
254
|
+
}
|
255
|
+
schemas.close();
|
256
|
+
}
|
257
|
+
|
258
|
+
ResultSet results = metadata.getColumns(c.getCatalog(),schemaName,table_name,null);
|
259
|
+
return unmarshal_columns(recv, metadata, results);
|
260
|
+
} catch(SQLException e) {
|
261
|
+
if(c.isClosed()) {
|
262
|
+
recv = recv.callMethod(recv.getRuntime().getCurrentContext(),"reconnect!");
|
263
|
+
if(!((Connection)recv.dataGetStruct()).isClosed()) {
|
264
|
+
continue;
|
265
|
+
}
|
266
|
+
}
|
267
|
+
throw e;
|
268
|
+
}
|
269
|
+
}
|
270
|
+
}
|
271
|
+
|
272
|
+
private static final java.util.regex.Pattern HAS_SMALL = java.util.regex.Pattern.compile("[a-z]");
|
273
|
+
private static final java.util.regex.Pattern HAS_LARGE = java.util.regex.Pattern.compile("[A-Z]");
|
274
|
+
private static IRubyObject unmarshal_columns(IRubyObject recv, DatabaseMetaData metadata, ResultSet rs) throws SQLException, IOException {
|
275
|
+
try {
|
276
|
+
List columns = new ArrayList();
|
277
|
+
boolean isDerby = metadata.getClass().getName().indexOf("derby") != -1;
|
278
|
+
Ruby runtime = recv.getRuntime();
|
279
|
+
ThreadContext ctx = runtime.getCurrentContext();
|
280
|
+
|
281
|
+
RubyHash tps = ((RubyHash)(recv.callMethod(ctx, "adapter").callMethod(ctx,"native_database_types")));
|
282
|
+
|
283
|
+
IRubyObject jdbcCol = ((RubyModule)(runtime.getModule("ActiveRecord").getConstant("ConnectionAdapters"))).getConstant("JdbcColumn");
|
284
|
+
|
285
|
+
while(rs.next()) {
|
286
|
+
String column_name = rs.getString(4);
|
287
|
+
if(metadata.storesUpperCaseIdentifiers() && !HAS_SMALL.matcher(column_name).find()) {
|
288
|
+
column_name = column_name.toLowerCase();
|
289
|
+
}
|
290
|
+
|
291
|
+
String prec = rs.getString(7);
|
292
|
+
String scal = rs.getString(9);
|
293
|
+
int precision = -1;
|
294
|
+
int scale = -1;
|
295
|
+
if(prec != null) {
|
296
|
+
precision = Integer.parseInt(prec);
|
297
|
+
if(scal != null) {
|
298
|
+
scale = Integer.parseInt(scal);
|
299
|
+
}
|
300
|
+
}
|
301
|
+
String type = rs.getString(6);
|
302
|
+
if(prec != null && precision > 0) {
|
303
|
+
type += "(" + precision;
|
304
|
+
if(scal != null && scale > 0) {
|
305
|
+
type += "," + scale;
|
306
|
+
}
|
307
|
+
type += ")";
|
308
|
+
}
|
309
|
+
String def = rs.getString(13);
|
310
|
+
IRubyObject _def;
|
311
|
+
if(def == null) {
|
312
|
+
_def = runtime.getNil();
|
313
|
+
} else {
|
314
|
+
if(isDerby && def.length() > 0 && def.charAt(0) == '\'') {
|
315
|
+
def = def.substring(1, def.length()-1);
|
316
|
+
}
|
317
|
+
_def = runtime.newString(def);
|
318
|
+
}
|
319
|
+
|
320
|
+
IRubyObject c = jdbcCol.callMethod(ctx,"new", new IRubyObject[]{recv.getInstanceVariable("@config"), runtime.newString(column_name),
|
321
|
+
_def, runtime.newString(type),
|
322
|
+
runtime.newBoolean(!rs.getString(18).equals("NO"))});
|
323
|
+
columns.add(c);
|
324
|
+
|
325
|
+
IRubyObject tp = (IRubyObject)tps.fastARef(c.callMethod(ctx,"type"));
|
326
|
+
if(tp != null && !tp.isNil() && tp.callMethod(ctx,"[]",runtime.newSymbol("limit")).isNil()) {
|
327
|
+
c.callMethod(ctx,"limit=", runtime.getNil());
|
328
|
+
if(!c.callMethod(ctx,"type").equals(runtime.newSymbol("decimal"))) {
|
329
|
+
c.callMethod(ctx,"precision=", runtime.getNil());
|
330
|
+
}
|
331
|
+
}
|
332
|
+
}
|
333
|
+
return runtime.newArray(columns);
|
334
|
+
} finally {
|
335
|
+
try {
|
336
|
+
rs.close();
|
337
|
+
} catch(Exception e) {}
|
338
|
+
}
|
339
|
+
}
|
340
|
+
|
341
|
+
public static IRubyObject primary_keys(IRubyObject recv, IRubyObject _table_name) throws SQLException {
|
342
|
+
Connection c = (Connection)recv.dataGetStruct();
|
343
|
+
DatabaseMetaData metadata = c.getMetaData();
|
344
|
+
String table_name = _table_name.toString();
|
345
|
+
if(metadata.storesUpperCaseIdentifiers()) {
|
346
|
+
table_name = table_name.toUpperCase();
|
347
|
+
} else if(metadata.storesLowerCaseIdentifiers()) {
|
348
|
+
table_name = table_name.toLowerCase();
|
349
|
+
}
|
350
|
+
ResultSet result_set = metadata.getPrimaryKeys(null,null,table_name);
|
351
|
+
List keyNames = new ArrayList();
|
352
|
+
Ruby runtime = recv.getRuntime();
|
353
|
+
while(result_set.next()) {
|
354
|
+
String s1 = result_set.getString(4);
|
355
|
+
if(metadata.storesUpperCaseIdentifiers() && !HAS_SMALL.matcher(s1).find()) {
|
356
|
+
s1 = s1.toLowerCase();
|
357
|
+
}
|
358
|
+
keyNames.add(runtime.newString(s1));
|
359
|
+
}
|
360
|
+
|
361
|
+
try {
|
362
|
+
result_set.close();
|
363
|
+
} catch(Exception e) {}
|
364
|
+
|
365
|
+
return runtime.newArray(keyNames);
|
366
|
+
}
|
367
|
+
|
368
|
+
public static IRubyObject execute_id_insert(IRubyObject recv, IRubyObject sql, IRubyObject id) throws SQLException {
|
369
|
+
Connection c = (Connection)recv.dataGetStruct();
|
370
|
+
PreparedStatement ps = c.prepareStatement(sql.convertToString().getUnicodeValue());
|
371
|
+
try {
|
372
|
+
ps.setLong(1,RubyNumeric.fix2long(id));
|
373
|
+
ps.executeUpdate();
|
374
|
+
} finally {
|
375
|
+
ps.close();
|
376
|
+
}
|
377
|
+
return id;
|
378
|
+
}
|
379
|
+
|
380
|
+
public static IRubyObject execute_update(IRubyObject recv, IRubyObject sql) throws SQLException {
|
381
|
+
while(true) {
|
382
|
+
Connection c = (Connection)recv.dataGetStruct();
|
383
|
+
Statement stmt = null;
|
384
|
+
try {
|
385
|
+
stmt = c.createStatement();
|
386
|
+
return recv.getRuntime().newFixnum(stmt.executeUpdate(sql.convertToString().getUnicodeValue()));
|
387
|
+
} catch(SQLException e) {
|
388
|
+
if(c.isClosed()) {
|
389
|
+
recv = recv.callMethod(recv.getRuntime().getCurrentContext(),"reconnect!");
|
390
|
+
if(!((Connection)recv.dataGetStruct()).isClosed()) {
|
391
|
+
continue;
|
392
|
+
}
|
393
|
+
}
|
394
|
+
throw e;
|
395
|
+
} finally {
|
396
|
+
if(null != stmt) {
|
397
|
+
try {
|
398
|
+
stmt.close();
|
399
|
+
} catch(Exception e) {}
|
400
|
+
}
|
401
|
+
}
|
402
|
+
}
|
403
|
+
}
|
404
|
+
|
405
|
+
public static IRubyObject execute_query(IRubyObject recv, IRubyObject[] args) throws SQLException, IOException {
|
406
|
+
IRubyObject sql = args[0];
|
407
|
+
int maxrows = 0;
|
408
|
+
if(args.length > 1) {
|
409
|
+
maxrows = RubyNumeric.fix2int(args[1]);
|
410
|
+
}
|
411
|
+
while(true) {
|
412
|
+
Connection c = (Connection)recv.dataGetStruct();
|
413
|
+
Statement stmt = null;
|
414
|
+
try {
|
415
|
+
stmt = c.createStatement();
|
416
|
+
stmt.setMaxRows(maxrows);
|
417
|
+
return unmarshal_result(recv, stmt.executeQuery(sql.convertToString().getUnicodeValue()));
|
418
|
+
} catch(SQLException e) {
|
419
|
+
if(c.isClosed()) {
|
420
|
+
recv = recv.callMethod(recv.getRuntime().getCurrentContext(),"reconnect!");
|
421
|
+
if(!((Connection)recv.dataGetStruct()).isClosed()) {
|
422
|
+
continue;
|
423
|
+
}
|
424
|
+
}
|
425
|
+
throw e;
|
426
|
+
} finally {
|
427
|
+
if(null != stmt) {
|
428
|
+
try {
|
429
|
+
stmt.close();
|
430
|
+
} catch(Exception e) {}
|
431
|
+
}
|
432
|
+
}
|
433
|
+
}
|
434
|
+
}
|
435
|
+
|
436
|
+
public static IRubyObject execute_insert(IRubyObject recv, IRubyObject sql) throws SQLException {
|
437
|
+
while(true) {
|
438
|
+
Connection c = (Connection)recv.dataGetStruct();
|
439
|
+
Statement stmt = null;
|
440
|
+
try {
|
441
|
+
stmt = c.createStatement();
|
442
|
+
stmt.executeUpdate(sql.convertToString().getUnicodeValue(), Statement.RETURN_GENERATED_KEYS);
|
443
|
+
return unmarshal_id_result(recv.getRuntime(), stmt.getGeneratedKeys());
|
444
|
+
} catch(SQLException e) {
|
445
|
+
if(c.isClosed()) {
|
446
|
+
recv = recv.callMethod(recv.getRuntime().getCurrentContext(),"reconnect!");
|
447
|
+
if(!((Connection)recv.dataGetStruct()).isClosed()) {
|
448
|
+
continue;
|
449
|
+
}
|
450
|
+
}
|
451
|
+
throw e;
|
452
|
+
} finally {
|
453
|
+
if(null != stmt) {
|
454
|
+
try {
|
455
|
+
stmt.close();
|
456
|
+
} catch(Exception e) {}
|
457
|
+
}
|
458
|
+
}
|
459
|
+
}
|
460
|
+
}
|
461
|
+
|
462
|
+
public static IRubyObject unmarshal_result_downcase(IRubyObject recv, ResultSet rs) throws SQLException, IOException {
|
463
|
+
List results = new ArrayList();
|
464
|
+
Ruby runtime = recv.getRuntime();
|
465
|
+
try {
|
466
|
+
ResultSetMetaData metadata = rs.getMetaData();
|
467
|
+
int col_count = metadata.getColumnCount();
|
468
|
+
IRubyObject[] col_names = new IRubyObject[col_count];
|
469
|
+
int[] col_types = new int[col_count];
|
470
|
+
int[] col_scale = new int[col_count];
|
471
|
+
|
472
|
+
for(int i=0;i<col_count;i++) {
|
473
|
+
col_names[i] = runtime.newString(metadata.getColumnName(i+1).toLowerCase());
|
474
|
+
col_types[i] = metadata.getColumnType(i+1);
|
475
|
+
col_scale[i] = metadata.getScale(i+1);
|
476
|
+
}
|
477
|
+
|
478
|
+
while(rs.next()) {
|
479
|
+
RubyHash row = RubyHash.newHash(runtime);
|
480
|
+
for(int i=0;i<col_count;i++) {
|
481
|
+
row.aset(col_names[i], jdbc_to_ruby(runtime, i+1, col_types[i], col_scale[i], rs));
|
482
|
+
}
|
483
|
+
results.add(row);
|
484
|
+
}
|
485
|
+
} finally {
|
486
|
+
try {
|
487
|
+
rs.close();
|
488
|
+
} catch(Exception e) {}
|
489
|
+
}
|
490
|
+
|
491
|
+
return runtime.newArray(results);
|
492
|
+
}
|
493
|
+
|
494
|
+
public static IRubyObject unmarshal_result(IRubyObject recv, ResultSet rs) throws SQLException, IOException {
|
495
|
+
Ruby runtime = recv.getRuntime();
|
496
|
+
List results = new ArrayList();
|
497
|
+
try {
|
498
|
+
ResultSetMetaData metadata = rs.getMetaData();
|
499
|
+
boolean storesUpper = rs.getStatement().getConnection().getMetaData().storesUpperCaseIdentifiers();
|
500
|
+
int col_count = metadata.getColumnCount();
|
501
|
+
IRubyObject[] col_names = new IRubyObject[col_count];
|
502
|
+
int[] col_types = new int[col_count];
|
503
|
+
int[] col_scale = new int[col_count];
|
504
|
+
|
505
|
+
for(int i=0;i<col_count;i++) {
|
506
|
+
String s1 = metadata.getColumnName(i+1);
|
507
|
+
if(storesUpper && !HAS_SMALL.matcher(s1).find()) {
|
508
|
+
s1 = s1.toLowerCase();
|
509
|
+
}
|
510
|
+
col_names[i] = runtime.newString(s1);
|
511
|
+
col_types[i] = metadata.getColumnType(i+1);
|
512
|
+
col_scale[i] = metadata.getScale(i+1);
|
513
|
+
}
|
514
|
+
|
515
|
+
while(rs.next()) {
|
516
|
+
RubyHash row = RubyHash.newHash(runtime);
|
517
|
+
for(int i=0;i<col_count;i++) {
|
518
|
+
row.aset(col_names[i], jdbc_to_ruby(runtime, i+1, col_types[i], col_scale[i], rs));
|
519
|
+
}
|
520
|
+
results.add(row);
|
521
|
+
}
|
522
|
+
} finally {
|
523
|
+
try {
|
524
|
+
rs.close();
|
525
|
+
} catch(Exception e) {}
|
526
|
+
}
|
527
|
+
return runtime.newArray(results);
|
528
|
+
}
|
529
|
+
|
530
|
+
public static IRubyObject unmarshal_result(IRubyObject recv, IRubyObject resultset, Block row_filter) throws SQLException, IOException {
|
531
|
+
Ruby runtime = recv.getRuntime();
|
532
|
+
ResultSet rs = intoResultSet(resultset);
|
533
|
+
List results = new ArrayList();
|
534
|
+
try {
|
535
|
+
ResultSetMetaData metadata = rs.getMetaData();
|
536
|
+
int col_count = metadata.getColumnCount();
|
537
|
+
IRubyObject[] col_names = new IRubyObject[col_count];
|
538
|
+
int[] col_types = new int[col_count];
|
539
|
+
int[] col_scale = new int[col_count];
|
540
|
+
|
541
|
+
for(int i=0;i<col_count;i++) {
|
542
|
+
col_names[i] = runtime.newString(metadata.getColumnName(i+1));
|
543
|
+
col_types[i] = metadata.getColumnType(i+1);
|
544
|
+
col_scale[i] = metadata.getScale(i+1);
|
545
|
+
}
|
546
|
+
|
547
|
+
if(row_filter.isGiven()) {
|
548
|
+
while(rs.next()) {
|
549
|
+
if(row_filter.yield(runtime.getCurrentContext(),resultset).isTrue()) {
|
550
|
+
RubyHash row = RubyHash.newHash(runtime);
|
551
|
+
for(int i=0;i<col_count;i++) {
|
552
|
+
row.aset(col_names[i], jdbc_to_ruby(runtime, i+1, col_types[i], col_scale[i], rs));
|
553
|
+
}
|
554
|
+
results.add(row);
|
555
|
+
}
|
556
|
+
}
|
557
|
+
} else {
|
558
|
+
while(rs.next()) {
|
559
|
+
RubyHash row = RubyHash.newHash(runtime);
|
560
|
+
for(int i=0;i<col_count;i++) {
|
561
|
+
row.aset(col_names[i], jdbc_to_ruby(runtime, i+1, col_types[i], col_scale[i], rs));
|
562
|
+
}
|
563
|
+
results.add(row);
|
564
|
+
}
|
565
|
+
}
|
566
|
+
|
567
|
+
} finally {
|
568
|
+
try {
|
569
|
+
rs.close();
|
570
|
+
} catch(Exception e) {}
|
571
|
+
}
|
572
|
+
|
573
|
+
return runtime.newArray(results);
|
574
|
+
}
|
575
|
+
|
576
|
+
private static IRubyObject jdbc_to_ruby(Ruby runtime, int row, int type, int scale, ResultSet rs) throws SQLException, IOException {
|
577
|
+
int n;
|
578
|
+
switch(type) {
|
579
|
+
case Types.BINARY:
|
580
|
+
case Types.BLOB:
|
581
|
+
case Types.LONGVARBINARY:
|
582
|
+
case Types.VARBINARY:
|
583
|
+
InputStream is = rs.getBinaryStream(row);
|
584
|
+
if(is == null || rs.wasNull()) {
|
585
|
+
return runtime.getNil();
|
586
|
+
}
|
587
|
+
ByteList str = new ByteList(2048);
|
588
|
+
byte[] buf = new byte[2048];
|
589
|
+
while((n = is.read(buf)) != -1) {
|
590
|
+
str.append(buf, 0, n);
|
591
|
+
}
|
592
|
+
is.close();
|
593
|
+
return runtime.newString(str);
|
594
|
+
case Types.LONGVARCHAR:
|
595
|
+
case Types.CLOB:
|
596
|
+
Reader rss = rs.getCharacterStream(row);
|
597
|
+
if(rss == null || rs.wasNull()) {
|
598
|
+
return runtime.getNil();
|
599
|
+
}
|
600
|
+
StringBuffer str2 = new StringBuffer(2048);
|
601
|
+
char[] cuf = new char[2048];
|
602
|
+
while((n = rss.read(cuf)) != -1) {
|
603
|
+
str2.append(cuf, 0, n);
|
604
|
+
}
|
605
|
+
rss.close();
|
606
|
+
return RubyString.newUnicodeString(runtime, str2.toString());
|
607
|
+
case Types.TIMESTAMP:
|
608
|
+
Timestamp time = rs.getTimestamp(row);
|
609
|
+
if (time == null || rs.wasNull()) {
|
610
|
+
return runtime.getNil();
|
611
|
+
}
|
612
|
+
return RubyString.newUnicodeString(runtime, time.toString());
|
613
|
+
default:
|
614
|
+
String vs = rs.getString(row);
|
615
|
+
if(vs == null || rs.wasNull()) {
|
616
|
+
return runtime.getNil();
|
617
|
+
}
|
618
|
+
return RubyString.newUnicodeString(runtime, vs);
|
619
|
+
}
|
620
|
+
}
|
621
|
+
|
622
|
+
public static IRubyObject unmarshal_id_result(Ruby runtime, ResultSet rs) throws SQLException {
|
623
|
+
try {
|
624
|
+
if(rs.next()) {
|
625
|
+
if(rs.getMetaData().getColumnCount() > 0) {
|
626
|
+
return runtime.newFixnum(rs.getLong(1));
|
627
|
+
}
|
628
|
+
}
|
629
|
+
return runtime.getNil();
|
630
|
+
} finally {
|
631
|
+
try {
|
632
|
+
rs.close();
|
633
|
+
} catch(Exception e) {}
|
634
|
+
}
|
635
|
+
}
|
636
|
+
|
637
|
+
private static String convertToStringOrNull(IRubyObject obj) {
|
638
|
+
if (obj.isNil()) {
|
639
|
+
return null;
|
640
|
+
}
|
641
|
+
return obj.toString();
|
642
|
+
}
|
643
|
+
|
644
|
+
private static int getTypeValueFor(Ruby runtime, IRubyObject type) throws SQLException {
|
645
|
+
if(!(type instanceof RubySymbol)) {
|
646
|
+
type = type.callMethod(runtime.getCurrentContext(),"type");
|
647
|
+
}
|
648
|
+
if(type == runtime.newSymbol("string")) {
|
649
|
+
return Types.VARCHAR;
|
650
|
+
} else if(type == runtime.newSymbol("text")) {
|
651
|
+
return Types.CLOB;
|
652
|
+
} else if(type == runtime.newSymbol("integer")) {
|
653
|
+
return Types.INTEGER;
|
654
|
+
} else if(type == runtime.newSymbol("decimal")) {
|
655
|
+
return Types.DECIMAL;
|
656
|
+
} else if(type == runtime.newSymbol("float")) {
|
657
|
+
return Types.FLOAT;
|
658
|
+
} else if(type == runtime.newSymbol("datetime")) {
|
659
|
+
return Types.TIMESTAMP;
|
660
|
+
} else if(type == runtime.newSymbol("timestamp")) {
|
661
|
+
return Types.TIMESTAMP;
|
662
|
+
} else if(type == runtime.newSymbol("time")) {
|
663
|
+
return Types.TIME;
|
664
|
+
} else if(type == runtime.newSymbol("date")) {
|
665
|
+
return Types.DATE;
|
666
|
+
} else if(type == runtime.newSymbol("binary")) {
|
667
|
+
return Types.BLOB;
|
668
|
+
} else if(type == runtime.newSymbol("boolean")) {
|
669
|
+
return Types.BOOLEAN;
|
670
|
+
} else {
|
671
|
+
return -1;
|
672
|
+
}
|
673
|
+
}
|
674
|
+
|
675
|
+
private final static DateFormat FORMAT = new SimpleDateFormat("%y-%M-%d %H:%m:%s");
|
676
|
+
|
677
|
+
private static void setValue(PreparedStatement ps, int index, Ruby runtime, IRubyObject value, IRubyObject type) throws SQLException {
|
678
|
+
final int tp = getTypeValueFor(runtime, type);
|
679
|
+
if(value.isNil()) {
|
680
|
+
ps.setNull(index, tp);
|
681
|
+
return;
|
682
|
+
}
|
683
|
+
|
684
|
+
switch(tp) {
|
685
|
+
case Types.VARCHAR:
|
686
|
+
case Types.CLOB:
|
687
|
+
ps.setString(index, RubyString.objAsString(value).toString());
|
688
|
+
break;
|
689
|
+
case Types.INTEGER:
|
690
|
+
ps.setLong(index, RubyNumeric.fix2long(value));
|
691
|
+
break;
|
692
|
+
case Types.FLOAT:
|
693
|
+
ps.setDouble(index, ((RubyNumeric)value).getDoubleValue());
|
694
|
+
break;
|
695
|
+
case Types.TIMESTAMP:
|
696
|
+
case Types.TIME:
|
697
|
+
case Types.DATE:
|
698
|
+
if(!(value instanceof RubyTime)) {
|
699
|
+
try {
|
700
|
+
Date dd = FORMAT.parse(RubyString.objAsString(value).toString());
|
701
|
+
ps.setTimestamp(index, new java.sql.Timestamp(dd.getTime()), Calendar.getInstance());
|
702
|
+
} catch(Exception e) {
|
703
|
+
ps.setString(index, RubyString.objAsString(value).toString());
|
704
|
+
}
|
705
|
+
} else {
|
706
|
+
RubyTime rubyTime = (RubyTime) value;
|
707
|
+
java.util.Date date = rubyTime.getJavaDate();
|
708
|
+
long millis = date.getTime();
|
709
|
+
long micros = rubyTime.microseconds() - millis / 1000;
|
710
|
+
java.sql.Timestamp ts = new java.sql.Timestamp(millis);
|
711
|
+
java.util.Calendar cal = Calendar.getInstance();
|
712
|
+
cal.setTime(date);
|
713
|
+
ts.setNanos((int)(micros * 1000));
|
714
|
+
ps.setTimestamp(index, ts, cal);
|
715
|
+
}
|
716
|
+
break;
|
717
|
+
case Types.BOOLEAN:
|
718
|
+
ps.setBoolean(index, value.isTrue());
|
719
|
+
break;
|
720
|
+
default: throw new RuntimeException("type " + type + " not supported in _bind yet");
|
721
|
+
}
|
722
|
+
}
|
723
|
+
|
724
|
+
private static void setValuesOnPS(PreparedStatement ps, Ruby runtime, IRubyObject values, IRubyObject types) throws SQLException {
|
725
|
+
RubyArray vals = (RubyArray)values;
|
726
|
+
RubyArray tps = (RubyArray)types;
|
727
|
+
|
728
|
+
for(int i=0, j=vals.getLength(); i<j; i++) {
|
729
|
+
setValue(ps, i+1, runtime, vals.eltInternal(i), tps.eltInternal(i));
|
730
|
+
}
|
731
|
+
}
|
732
|
+
|
733
|
+
/*
|
734
|
+
* sql, values, types, name = nil, pk = nil, id_value = nil, sequence_name = nil
|
735
|
+
*/
|
736
|
+
public static IRubyObject insert_bind(IRubyObject recv, IRubyObject[] args) throws SQLException {
|
737
|
+
Ruby runtime = recv.getRuntime();
|
738
|
+
Arity.checkArgumentCount(runtime, args, 3, 7);
|
739
|
+
Connection c = (Connection)recv.dataGetStruct();
|
740
|
+
PreparedStatement ps = null;
|
741
|
+
try {
|
742
|
+
ps = c.prepareStatement(RubyString.objAsString(args[0]).toString(), Statement.RETURN_GENERATED_KEYS);
|
743
|
+
setValuesOnPS(ps, runtime, args[1], args[2]);
|
744
|
+
ps.executeUpdate();
|
745
|
+
return unmarshal_id_result(runtime, ps.getGeneratedKeys());
|
746
|
+
} finally {
|
747
|
+
try {
|
748
|
+
ps.close();
|
749
|
+
} catch(Exception e) {}
|
750
|
+
}
|
751
|
+
}
|
752
|
+
|
753
|
+
/*
|
754
|
+
* sql, values, types, name = nil
|
755
|
+
*/
|
756
|
+
public static IRubyObject update_bind(IRubyObject recv, IRubyObject[] args) throws SQLException {
|
757
|
+
Ruby runtime = recv.getRuntime();
|
758
|
+
Arity.checkArgumentCount(runtime, args, 3, 4);
|
759
|
+
Connection c = (Connection)recv.dataGetStruct();
|
760
|
+
PreparedStatement ps = null;
|
761
|
+
try {
|
762
|
+
ps = c.prepareStatement(RubyString.objAsString(args[0]).toString());
|
763
|
+
setValuesOnPS(ps, runtime, args[1], args[2]);
|
764
|
+
ps.executeUpdate();
|
765
|
+
} finally {
|
766
|
+
try {
|
767
|
+
ps.close();
|
768
|
+
} catch(Exception e) {}
|
769
|
+
}
|
770
|
+
return runtime.getNil();
|
771
|
+
}
|
772
|
+
|
773
|
+
|
774
|
+
private final static String LOB_UPDATE = "UPDATE ? WHERE ";
|
775
|
+
|
776
|
+
/*
|
777
|
+
* (is binary?, colname, tablename, primary key, id, value)
|
778
|
+
*/
|
779
|
+
public static IRubyObject write_large_object(IRubyObject recv, IRubyObject[] args) throws SQLException, IOException {
|
780
|
+
Ruby runtime = recv.getRuntime();
|
781
|
+
Arity.checkArgumentCount(runtime, args, 6, 6);
|
782
|
+
Connection c = (Connection)recv.dataGetStruct();
|
783
|
+
String sql = "UPDATE " + args[2].toString() + " SET " + args[1].toString() + " = ? WHERE " + args[3] + "=" + args[4];
|
784
|
+
PreparedStatement ps = null;
|
785
|
+
try {
|
786
|
+
ByteList outp = RubyString.objAsString(args[5]).getByteList();
|
787
|
+
ps = c.prepareStatement(sql);
|
788
|
+
if(args[0].isTrue()) { // binary
|
789
|
+
ps.setBinaryStream(1,new ByteArrayInputStream(outp.bytes, outp.begin, outp.realSize), outp.realSize);
|
790
|
+
} else { // clob
|
791
|
+
String ss = outp.toString();
|
792
|
+
ps.setCharacterStream(1,new StringReader(ss), ss.length());
|
793
|
+
}
|
794
|
+
ps.executeUpdate();
|
795
|
+
} finally {
|
796
|
+
try {
|
797
|
+
ps.close();
|
798
|
+
} catch(Exception e) {}
|
799
|
+
}
|
800
|
+
return runtime.getNil();
|
801
|
+
}
|
802
|
+
}
|