activerecord-jdbc-adapter 5.0.pre1 → 51.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -2
  3. data/.travis.yml +15 -416
  4. data/Gemfile +35 -37
  5. data/README.md +23 -118
  6. data/RUNNING_TESTS.md +31 -26
  7. data/Rakefile +2 -3
  8. data/activerecord-jdbc-adapter.gemspec +1 -2
  9. data/lib/arjdbc/abstract/connection_management.rb +21 -0
  10. data/lib/arjdbc/abstract/core.rb +62 -0
  11. data/lib/arjdbc/abstract/database_statements.rb +46 -0
  12. data/lib/arjdbc/abstract/statement_cache.rb +58 -0
  13. data/lib/arjdbc/abstract/transaction_support.rb +86 -0
  14. data/lib/arjdbc/derby/adapter.rb +6 -1
  15. data/lib/arjdbc/discover.rb +0 -7
  16. data/lib/arjdbc/firebird/adapter.rb +2 -2
  17. data/lib/arjdbc/jdbc/adapter.rb +10 -252
  18. data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
  19. data/lib/arjdbc/jdbc/connection.rb +6 -0
  20. data/lib/arjdbc/jdbc.rb +2 -2
  21. data/lib/arjdbc/mysql/adapter.rb +87 -944
  22. data/lib/arjdbc/mysql/connection_methods.rb +4 -2
  23. data/lib/arjdbc/postgresql/adapter.rb +288 -1023
  24. data/lib/arjdbc/postgresql/base/array_decoder.rb +26 -0
  25. data/lib/arjdbc/postgresql/base/array_encoder.rb +25 -0
  26. data/lib/arjdbc/postgresql/base/pgconn.rb +8 -5
  27. data/lib/arjdbc/postgresql/column.rb +10 -599
  28. data/lib/arjdbc/postgresql/connection_methods.rb +9 -0
  29. data/lib/arjdbc/postgresql/name.rb +24 -0
  30. data/lib/arjdbc/postgresql/oid_types.rb +25 -110
  31. data/lib/arjdbc/sqlite3/adapter.rb +171 -170
  32. data/lib/arjdbc/tasks/database_tasks.rb +1 -3
  33. data/lib/arjdbc/tasks/db2_database_tasks.rb +2 -2
  34. data/lib/arjdbc/version.rb +1 -1
  35. data/pom.xml +3 -3
  36. data/rakelib/02-test.rake +0 -12
  37. data/rakelib/compile.rake +1 -1
  38. data/rakelib/db.rake +7 -5
  39. data/rakelib/rails.rake +63 -64
  40. data/src/java/arjdbc/firebird/FirebirdRubyJdbcConnection.java +1 -17
  41. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +518 -1260
  42. data/src/java/arjdbc/mysql/MySQLModule.java +3 -3
  43. data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +53 -134
  44. data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +214 -240
  45. data/src/java/arjdbc/sqlite3/SQLite3Module.java +0 -20
  46. data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +85 -10
  47. metadata +20 -34
  48. data/Appraisals +0 -41
  49. data/lib/active_record/connection_adapters/oracle_adapter.rb +0 -1
  50. data/lib/arjdbc/common_jdbc_methods.rb +0 -89
  51. data/lib/arjdbc/mysql/bulk_change_table.rb +0 -150
  52. data/lib/arjdbc/mysql/column.rb +0 -162
  53. data/lib/arjdbc/mysql/explain_support.rb +0 -82
  54. data/lib/arjdbc/mysql/schema_creation.rb +0 -58
  55. data/lib/arjdbc/oracle/adapter.rb +0 -952
  56. data/lib/arjdbc/oracle/column.rb +0 -126
  57. data/lib/arjdbc/oracle/connection_methods.rb +0 -21
  58. data/lib/arjdbc/oracle.rb +0 -4
  59. data/lib/arjdbc/postgresql/_bc_time_cast_patch.rb +0 -21
  60. data/lib/arjdbc/postgresql/base/oid.rb +0 -412
  61. data/lib/arjdbc/postgresql/base/schema_definitions.rb +0 -131
  62. data/lib/arjdbc/postgresql/explain_support.rb +0 -53
  63. data/lib/arjdbc/postgresql/oid/bytea.rb +0 -2
  64. data/lib/arjdbc/postgresql/schema_creation.rb +0 -60
  65. data/lib/arjdbc/tasks/oracle/enhanced_structure_dump.rb +0 -297
  66. data/lib/arjdbc/tasks/oracle_database_tasks.rb +0 -65
  67. data/src/java/arjdbc/oracle/OracleModule.java +0 -75
  68. data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +0 -465
@@ -27,6 +27,7 @@ package arjdbc.postgresql;
27
27
 
28
28
  import java.io.ByteArrayInputStream;
29
29
  import java.io.InputStream;
30
+ import java.lang.StringBuilder;
30
31
  import java.sql.Array;
31
32
  import java.sql.Connection;
32
33
  import java.sql.PreparedStatement;
@@ -35,8 +36,10 @@ import java.sql.SQLException;
35
36
  import java.sql.Statement;
36
37
  import java.sql.Timestamp;
37
38
  import java.sql.Types;
39
+ import java.util.HashMap;
38
40
  import java.util.Map;
39
41
  import java.util.UUID;
42
+ import java.util.regex.Pattern;
40
43
 
41
44
  import org.jruby.Ruby;
42
45
  import org.jruby.RubyArray;
@@ -46,6 +49,7 @@ import org.jruby.RubyFixnum;
46
49
  import org.jruby.RubyFloat;
47
50
  import org.jruby.RubyHash;
48
51
  import org.jruby.RubyIO;
52
+ import org.jruby.RubyModule;
49
53
  import org.jruby.RubyString;
50
54
  import org.jruby.anno.JRubyMethod;
51
55
  import org.jruby.javasupport.JavaUtil;
@@ -57,7 +61,9 @@ import org.jruby.util.ByteList;
57
61
  import org.postgresql.PGConnection;
58
62
  import org.postgresql.PGStatement;
59
63
  import org.postgresql.core.BaseConnection;
60
- import org.postgresql.jdbc4.Jdbc4Array;
64
+ import org.postgresql.geometric.PGline;
65
+ import org.postgresql.geometric.PGlseg;
66
+ import org.postgresql.geometric.PGpoint;
61
67
  import org.postgresql.util.PGInterval;
62
68
  import org.postgresql.util.PGobject;
63
69
 
@@ -67,6 +73,52 @@ import org.postgresql.util.PGobject;
67
73
  */
68
74
  public class PostgreSQLRubyJdbcConnection extends arjdbc.jdbc.RubyJdbcConnection {
69
75
  private static final long serialVersionUID = 7235537759545717760L;
76
+ private static final int HSTORE_TYPE = 100000 + 1111;
77
+ private static final Pattern binaryStringPattern = Pattern.compile("^[01]+$");
78
+ private static final Pattern uuidPattern = Pattern.compile("^\\p{XDigit}{8}-(?:\\p{XDigit}{4}-){3}\\p{XDigit}{12}$");
79
+
80
+ private static final String[] binaryStrings = {
81
+ "0000",
82
+ "0001",
83
+ "0010",
84
+ "0011",
85
+ "0100",
86
+ "0101",
87
+ "0110",
88
+ "0111",
89
+ "1000",
90
+ "1001",
91
+ "1010",
92
+ "1011",
93
+ "1100",
94
+ "1101",
95
+ "1110",
96
+ "1111"
97
+ };
98
+
99
+ private static final Map<String, Integer> POSTGRES_JDBC_TYPE_FOR = new HashMap<String, Integer>(32, 1);
100
+ static {
101
+ POSTGRES_JDBC_TYPE_FOR.put("bit", Types.OTHER);
102
+ POSTGRES_JDBC_TYPE_FOR.put("bit_varying", Types.OTHER);
103
+ POSTGRES_JDBC_TYPE_FOR.put("citext", Types.OTHER);
104
+ POSTGRES_JDBC_TYPE_FOR.put("daterange", Types.OTHER);
105
+ POSTGRES_JDBC_TYPE_FOR.put("hstore", Types.OTHER);
106
+ POSTGRES_JDBC_TYPE_FOR.put("int4range", Types.OTHER);
107
+ POSTGRES_JDBC_TYPE_FOR.put("int8range", Types.OTHER);
108
+ POSTGRES_JDBC_TYPE_FOR.put("interval", Types.OTHER);
109
+ POSTGRES_JDBC_TYPE_FOR.put("json", Types.OTHER);
110
+ POSTGRES_JDBC_TYPE_FOR.put("jsonb", Types.OTHER);
111
+ POSTGRES_JDBC_TYPE_FOR.put("line", Types.OTHER);
112
+ POSTGRES_JDBC_TYPE_FOR.put("lseg", Types.OTHER);
113
+ POSTGRES_JDBC_TYPE_FOR.put("ltree", Types.OTHER);
114
+ POSTGRES_JDBC_TYPE_FOR.put("numrange", Types.OTHER);
115
+ POSTGRES_JDBC_TYPE_FOR.put("point", Types.OTHER);
116
+ POSTGRES_JDBC_TYPE_FOR.put("tsrange", Types.OTHER);
117
+ POSTGRES_JDBC_TYPE_FOR.put("tstzrange", Types.OTHER);
118
+ POSTGRES_JDBC_TYPE_FOR.put("tsvector", Types.OTHER);
119
+ POSTGRES_JDBC_TYPE_FOR.put("uuid", Types.OTHER);
120
+ }
121
+
70
122
 
71
123
  protected PostgreSQLRubyJdbcConnection(Ruby runtime, RubyClass metaClass) {
72
124
  super(runtime, metaClass);
@@ -128,6 +180,20 @@ public class PostgreSQLRubyJdbcConnection extends arjdbc.jdbc.RubyJdbcConnection
128
180
  return value;
129
181
  }
130
182
 
183
+ @Override
184
+ protected String internedTypeFor(final ThreadContext context, final IRubyObject attribute) throws SQLException {
185
+
186
+ final RubyModule postgreSQL = (RubyModule) getConnectionAdapters(context.runtime).getConstant("PostgreSQL");
187
+ final RubyModule oid = (RubyModule) postgreSQL.getConstant("OID");
188
+ final RubyClass arrayClass = oid.getClass("Array");
189
+
190
+ if ( arrayClass.isInstance(attributeType(context, attribute)) ) {
191
+ return "array";
192
+ }
193
+
194
+ return super.internedTypeFor(context, attribute);
195
+ }
196
+
131
197
  @Override
132
198
  protected Connection newConnection() throws SQLException {
133
199
  final Connection connection = getConnectionFactory().newConnection();
@@ -147,43 +213,27 @@ public class PostgreSQLRubyJdbcConnection extends arjdbc.jdbc.RubyJdbcConnection
147
213
  return connection;
148
214
  }
149
215
 
150
- @Override // due statement.setNull(index, Types.BLOB) not working :
151
- // org.postgresql.util.PSQLException: ERROR: column "sample_binary" is of type bytea but expression is of type oid
152
- protected void setBlobParameter(final ThreadContext context,
153
- final Connection connection, final PreparedStatement statement,
154
- final int index, final Object value,
155
- final IRubyObject column, final int type) throws SQLException {
156
- if ( value instanceof IRubyObject ) {
157
- setBlobParameter(context, connection, statement, index, (IRubyObject) value, column, type);
158
- }
159
- else {
160
- if ( value == null ) statement.setNull(index, Types.BINARY);
161
- else {
162
- statement.setBinaryStream(index, (InputStream) value);
163
- }
164
- }
165
- }
166
-
167
216
  @Override // due statement.setNull(index, Types.BLOB) not working :
168
217
  // org.postgresql.util.PSQLException: ERROR: column "sample_binary" is of type bytea but expression is of type oid
169
218
  protected void setBlobParameter(final ThreadContext context,
170
219
  final Connection connection, final PreparedStatement statement,
171
220
  final int index, final IRubyObject value,
172
- final IRubyObject column, final int type) throws SQLException {
221
+ final IRubyObject attribute, final int type) throws SQLException {
222
+
223
+ // TODO: Somewhere in the process of storing binary data, we lose about 50 bytes in one of the tests
224
+
173
225
  if ( value.isNil() ) {
174
226
  statement.setNull(index, Types.BINARY);
175
227
  }
176
- else {
177
- if ( value instanceof RubyIO ) { // IO/File
178
- statement.setBinaryStream(index, ((RubyIO) value).getInStream());
179
- }
180
- else { // should be a RubyString
181
- final ByteList blob = value.asString().getByteList();
182
- statement.setBinaryStream(index,
183
- new ByteArrayInputStream(blob.unsafeBytes(), blob.getBegin(), blob.getRealSize()),
184
- blob.getRealSize() // length
185
- );
186
- }
228
+ else if ( value instanceof RubyIO ) { // IO/File
229
+ statement.setBinaryStream(index, ((RubyIO) value).getInStream());
230
+ }
231
+ else { // should be a RubyString
232
+ final ByteList blob = value.asString().getByteList();
233
+ statement.setBinaryStream(index,
234
+ new ByteArrayInputStream(blob.unsafeBytes(), blob.getBegin(), blob.getRealSize()),
235
+ blob.getRealSize() // length
236
+ );
187
237
  }
188
238
  }
189
239
 
@@ -211,250 +261,178 @@ public class PostgreSQLRubyJdbcConnection extends arjdbc.jdbc.RubyJdbcConnection
211
261
  super.setTimestampParameter(context, connection, statement, index, value, column, type);
212
262
  }
213
263
 
214
- private static final ByteList INTERVAL =
215
- new ByteList( new byte[] { 'i','n','t','e','r','v','a','l' }, false );
216
-
217
- private static final ByteList ARRAY_END = new ByteList( new byte[] { '[',']' }, false );
218
-
219
264
  @Override
220
- protected void setStringParameter(final ThreadContext context,
265
+ protected void setObjectParameter(final ThreadContext context,
221
266
  final Connection connection, final PreparedStatement statement,
222
- final int index, final IRubyObject value,
223
- final IRubyObject column, final int type) throws SQLException {
224
- final RubyString sqlType;
225
- if ( column != null && ! column.isNil() ) {
226
- sqlType = (RubyString) column.callMethod(context, "sql_type");
227
- }
228
- else {
229
- sqlType = null;
230
- }
231
-
232
- if ( value.isNil() ) {
233
- if ( rawArrayType == Boolean.TRUE ) { // array's type is :string
234
- if ( sqlType != null && sqlType.getByteList().endsWith( ARRAY_END ) ) {
235
- statement.setNull(index, Types.ARRAY); return;
236
- }
237
- statement.setNull(index, type); return;
238
- }
239
- statement.setNull(index, Types.VARCHAR);
240
- }
241
- else {
242
- final String valueStr = value.asString().toString();
243
- if ( sqlType != null ) {
244
- if ( rawArrayType == Boolean.TRUE && sqlType.getByteList().endsWith( ARRAY_END ) ) {
245
- final int oid = oid(context, column);
246
- final Array valueArr = new Jdbc4Array(connection.unwrap(BaseConnection.class), oid, valueStr);
247
- statement.setArray(index, valueArr); return;
267
+ final int index, IRubyObject value,
268
+ final IRubyObject attribute, final int type) throws SQLException {
269
+
270
+ final String columnType = attributeSQLType(context, attribute).asJavaString();
271
+
272
+ switch ( columnType ) {
273
+ case "bit":
274
+ case "bit_varying":
275
+ setBitStringParameter(statement, index, value);
276
+ break;
277
+
278
+ case "cidr":
279
+ case "citext":
280
+ case "hstore":
281
+ case "inet":
282
+ case "ltree":
283
+ case "macaddr":
284
+ case "tsvector":
285
+ setPGobjectParameter(statement, index, value, columnType);
286
+ break;
287
+
288
+ case "interval":
289
+ statement.setObject(index, new PGInterval(value.toString()));
290
+ break;
291
+
292
+ case "json":
293
+ case "jsonb":
294
+ setJsonParameter(context, statement, index, value, columnType);
295
+ break;
296
+
297
+ case "line":
298
+ statement.setObject(index, new PGline(value.toString()));
299
+ break;
300
+
301
+ case "lseg":
302
+ statement.setObject(index, new PGlseg(value.toString()));
303
+ break;
304
+
305
+ case "point":
306
+ statement.setObject(index, new PGpoint(value.toString()));
307
+ break;
308
+
309
+ case "uuid":
310
+ setUUIDParameter(statement, index, value);
311
+ break;
312
+
313
+ default:
314
+ if ( columnType.endsWith("range") ) {
315
+ setRangeParameter(context, statement, index, value, columnType);
248
316
  }
249
- if ( sqlType.getByteList().startsWith( INTERVAL ) ) {
250
- statement.setObject( index, new PGInterval( valueStr ) ); return;
317
+ else {
318
+ super.setObjectParameter(context, connection, statement, index, value, attribute, type);
251
319
  }
252
- }
253
- statement.setString( index, valueStr );
254
320
  }
255
321
  }
256
322
 
257
- private static int oid(final ThreadContext context, final IRubyObject column) {
258
- // our column convention :
259
- IRubyObject oid = column.getInstanceVariables().getInstanceVariable("@oid");
260
- if ( oid == null || oid.isNil() ) { // only for user instantiated Column
261
- throw new IllegalStateException("missing @oid for column: " + column.inspect());
262
- }
263
- return RubyFixnum.fix2int(oid);
264
- }
265
-
266
- @Override
267
- protected void setObjectParameter(final ThreadContext context,
268
- final Connection connection, final PreparedStatement statement,
269
- final int index, Object value,
270
- final IRubyObject column, final int type) throws SQLException {
271
-
272
- final String columnType = column.callMethod(context, "type").asJavaString();
273
-
274
- if ( columnType == (Object) "uuid" ) {
275
- setUUIDParameter(statement, index, value);
276
- return;
277
- }
278
-
279
- if ( columnType == (Object) "json" ) {
280
- setJsonParameter(context, statement, index, value, column);
281
- return;
282
- }
283
-
284
- if ( columnType == (Object) "tsvector" ) {
285
- setTsVectorParameter(statement, index, value);
286
- return;
287
- }
288
-
289
- if ( columnType == (Object) "cidr" || columnType == (Object) "inet"
290
- || columnType == (Object) "macaddr" ) {
291
- setAddressParameter(context, statement, index, value, column, columnType);
292
- return;
293
- }
294
-
295
- if ( columnType != null && columnType.endsWith("range") ) {
296
- setRangeParameter(context, statement, index, value, column, columnType);
297
- return;
298
- }
323
+ // value should be a ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Bit::Data
324
+ private void setBitStringParameter(final PreparedStatement statement, final int index,
325
+ final IRubyObject value) throws SQLException {
299
326
 
300
- super.setObjectParameter(context, connection, statement, index, value, column, type);
301
- }
327
+ String valueForDB = value.toString();
328
+ int length = valueForDB.length();
302
329
 
303
- private void setUUIDParameter(
304
- final PreparedStatement statement, final int index,
305
- Object value) throws SQLException {
306
-
307
- if ( value instanceof IRubyObject ) {
308
- final IRubyObject rubyValue = (IRubyObject) value;
309
- if ( rubyValue.isNil() ) {
310
- statement.setNull(index, Types.OTHER); return;
330
+ /*
331
+ This means that if somebody sets their binary string to be "111" it
332
+ will always be assumed to be in binary. This matches the AR (5.0) functionality.
333
+ If it is meant to be a hex string they should use "0x111".
334
+ */
335
+ if (length > 0 && !binaryStringPattern.matcher(valueForDB).matches()) {
336
+ StringBuilder builder = new StringBuilder(length * 4);
337
+ for (int i = 0; i < length; i++) {
338
+ builder.append(binaryStrings[Character.digit(valueForDB.charAt(i), 16)]);
311
339
  }
312
- }
313
- else if ( value == null ) {
314
- statement.setNull(index, Types.OTHER); return;
340
+ valueForDB = builder.toString();
315
341
  }
316
342
 
317
- final Object uuid = UUID.fromString( value.toString() );
318
- statement.setObject(index, uuid);
343
+ setPGobjectParameter(statement, index, valueForDB, "bit");
319
344
  }
320
345
 
321
346
  private void setJsonParameter(final ThreadContext context,
322
347
  final PreparedStatement statement, final int index,
323
- Object value, final IRubyObject column) throws SQLException {
324
-
325
- if ( value instanceof IRubyObject ) {
326
- final IRubyObject rubyValue = (IRubyObject) value;
327
- if ( rubyValue.isNil() ) {
328
- statement.setNull(index, Types.OTHER); return;
329
- }
330
- if (!isAr42(column)) { // Value has already been cast for AR42
331
- value = column.getMetaClass().callMethod(context, "json_to_string", rubyValue);
332
- }
333
- }
334
- else if ( value == null ) {
335
- statement.setNull(index, Types.OTHER); return;
336
- }
348
+ final IRubyObject value, final String columnType) throws SQLException {
337
349
 
338
350
  final PGobject pgJson = new PGobject();
339
- pgJson.setType("json");
351
+ pgJson.setType(columnType);
340
352
  pgJson.setValue(value.toString());
341
353
  statement.setObject(index, pgJson);
342
354
  }
343
355
 
344
- private void setTsVectorParameter(
345
- final PreparedStatement statement, final int index,
346
- Object value) throws SQLException {
347
-
348
- if ( value instanceof IRubyObject ) {
349
- final IRubyObject rubyValue = (IRubyObject) value;
350
- if ( rubyValue.isNil() ) {
351
- statement.setNull(index, Types.OTHER); return;
352
- }
353
- }
354
- else if ( value == null ) {
355
- statement.setNull(index, Types.OTHER); return;
356
- }
357
-
358
- final PGobject pgTsVector = new PGobject();
359
- pgTsVector.setType("tsvector");
360
- pgTsVector.setValue(value.toString());
361
- statement.setObject(index, pgTsVector);
362
- }
363
-
364
- private void setAddressParameter(final ThreadContext context,
365
- final PreparedStatement statement, final int index,
366
- Object value, final IRubyObject column,
367
- final String columnType) throws SQLException {
368
-
369
- if ( value instanceof IRubyObject ) {
370
- final IRubyObject rubyValue = (IRubyObject) value;
371
- if ( rubyValue.isNil() ) {
372
- statement.setNull(index, Types.OTHER); return;
373
- }
374
- if (!isAr42(column)) { // Value has already been cast for AR42
375
- value = column.getMetaClass().callMethod(context, "cidr_to_string", rubyValue);
376
- }
377
- }
378
- else if ( value == null ) {
379
- statement.setNull(index, Types.OTHER); return;
380
- }
356
+ private void setPGobjectParameter(final PreparedStatement statement, final int index,
357
+ final Object value, final String columnType) throws SQLException {
381
358
 
382
- final PGobject pgAddress = new PGobject();
383
- pgAddress.setType(columnType);
384
- pgAddress.setValue(value.toString());
385
- statement.setObject(index, pgAddress);
359
+ final PGobject param = new PGobject();
360
+ param.setType(columnType);
361
+ param.setValue(value.toString());
362
+ statement.setObject(index, param);
386
363
  }
387
364
 
388
365
  private void setRangeParameter(final ThreadContext context,
389
366
  final PreparedStatement statement, final int index,
390
- final Object value, final IRubyObject column,
391
- final String columnType) throws SQLException {
367
+ final IRubyObject value, final String columnType) throws SQLException {
392
368
 
393
- final String rangeValue;
369
+ final String rangeValue = value.toString();
370
+ final Object pgRange;
394
371
 
395
- if ( value instanceof IRubyObject ) {
396
- final IRubyObject rubyValue = (IRubyObject) value;
397
- if ( rubyValue.isNil() ) {
398
- statement.setNull(index, Types.OTHER); return;
399
- }
400
- rangeValue = column.getMetaClass().callMethod(context, "range_to_string", rubyValue).toString();
401
- }
402
- else {
403
- if ( value == null ) {
404
- statement.setNull(index, Types.OTHER); return;
405
- }
406
- rangeValue = value.toString();
372
+ switch ( columnType ) {
373
+ case "daterange":
374
+ pgRange = new DateRangeType(rangeValue);
375
+ break;
376
+ case "tsrange":
377
+ pgRange = new TsRangeType(rangeValue);
378
+ break;
379
+ case "tstzrange":
380
+ pgRange = new TstzRangeType(rangeValue);
381
+ break;
382
+ case "int4range":
383
+ pgRange = new Int4RangeType(rangeValue);
384
+ break;
385
+ case "int8range":
386
+ pgRange = new Int8RangeType(rangeValue);
387
+ break;
388
+ default:
389
+ pgRange = new NumRangeType(rangeValue);
407
390
  }
408
391
 
409
- final Object pgRange;
410
- if ( columnType == (Object) "daterange" ) {
411
- pgRange = new DateRangeType(rangeValue);
412
- }
413
- else if ( columnType == (Object) "tsrange" ) {
414
- pgRange = new TsRangeType(rangeValue);
415
- }
416
- else if ( columnType == (Object) "tstzrange" ) {
417
- pgRange = new TstzRangeType(rangeValue);
418
- }
419
- else if ( columnType == (Object) "int4range" ) {
420
- pgRange = new Int4RangeType(rangeValue);
421
- }
422
- else if ( columnType == (Object) "int8range" ) {
423
- pgRange = new Int8RangeType(rangeValue);
424
- }
425
- else { // if ( columnType == (Object) "numrange" )
426
- pgRange = new NumRangeType(rangeValue);
427
- }
428
392
  statement.setObject(index, pgRange);
429
393
  }
430
394
 
431
395
  @Override
432
- protected String resolveArrayBaseTypeName(final ThreadContext context,
433
- final Object value, final IRubyObject column, final int type) {
434
- String sqlType = column.callMethod(context, "sql_type").toString();
435
- if ( sqlType.startsWith("character varying") ) return "text";
436
- final int index = sqlType.indexOf('('); // e.g. "character varying(255)"
437
- if ( index > 0 ) sqlType = sqlType.substring(0, index);
438
- return sqlType;
396
+ protected void setStringParameter(final ThreadContext context,
397
+ final Connection connection, final PreparedStatement statement,
398
+ final int index, final IRubyObject value,
399
+ final IRubyObject attribute, final int type) throws SQLException {
400
+
401
+ if ( attributeSQLType(context, attribute).isNil() ) {
402
+ /*
403
+ We have to check for a uuid here because in some cases
404
+ (for example, when doing "exists?" checks, or with legacy binds)
405
+ ActiveRecord doesn't send us the actual type of the attribute
406
+ and Postgres won't compare a uuid column with a string
407
+ */
408
+ final String uuid = value.toString();
409
+
410
+ // Checking the length so we don't have the overhead of the regex unless it "looks" like a UUID
411
+ if ( uuid.length() == 36 && uuidPattern.matcher(uuid).matches() ) {
412
+ setUUIDParameter(statement, index, value);
413
+ return;
414
+ }
415
+ }
416
+
417
+ super.setStringParameter(context, connection, statement, index, value, attribute, type);
439
418
  }
440
419
 
441
- private static final int HSTORE_TYPE = 100000 + 1111;
420
+ private void setUUIDParameter(final PreparedStatement statement,
421
+ final int index, final IRubyObject value) throws SQLException {
422
+
423
+ statement.setObject(index, UUID.fromString(value.toString()));
424
+ }
442
425
 
443
426
  @Override
444
- protected int jdbcTypeFor(final ThreadContext context, final Ruby runtime,
445
- final IRubyObject column, final Object value) throws SQLException {
446
- // NOTE: likely wrong but native adapters handles this thus we should
447
- // too - used from #table_exists? `binds << [ nil, schema ] if schema`
448
- if ( column == null || column.isNil() ) return Types.VARCHAR; // assume type == :string
449
- final int type = super.jdbcTypeFor(context, runtime, column, value);
450
- /*
451
- if ( type == Types.OTHER ) {
452
- final IRubyObject columnType = column.callMethod(context, "type");
453
- if ( "hstore" == (Object) columnType.asJavaString() ) {
454
- return HSTORE_TYPE;
455
- }
456
- } */
457
- return type;
427
+ protected Integer jdbcTypeFor(final String type) {
428
+
429
+ Integer typeValue = POSTGRES_JDBC_TYPE_FOR.get(type);
430
+
431
+ if ( typeValue != null ) {
432
+ return typeValue;
433
+ }
434
+
435
+ return super.jdbcTypeFor(type);
458
436
  }
459
437
 
460
438
  /**
@@ -498,12 +476,8 @@ public class PostgreSQLRubyJdbcConnection extends arjdbc.jdbc.RubyJdbcConnection
498
476
  if ( rawDateTime != null && rawDateTime.booleanValue() ) return strValue;
499
477
 
500
478
  final IRubyObject adapter = callMethod(context, "adapter"); // self.adapter
501
- if ( usesType(runtime) ) {
502
- return typeCastFromDatabase(context, adapter, runtime.newSymbol("timestamp"), strValue);
503
- }
504
479
 
505
- if ( adapter.isNil() ) return strValue; // NOTE: we warn on init_connection
506
- return adapter.callMethod(context, "_string_to_timestamp", strValue);
480
+ return typeCastFromDatabase(context, adapter, runtime.newSymbol("timestamp"), strValue);
507
481
  }
508
482
 
509
483
  @Override
@@ -30,7 +30,6 @@ import org.jruby.RubyString;
30
30
  import org.jruby.anno.JRubyMethod;
31
31
  import org.jruby.runtime.ThreadContext;
32
32
  import org.jruby.runtime.builtin.IRubyObject;
33
- import org.jruby.util.ByteList;
34
33
 
35
34
  /**
36
35
  * ArJdbc::SQLite3
@@ -56,23 +55,4 @@ public class SQLite3Module {
56
55
  );
57
56
  return quoted;
58
57
  }
59
-
60
- private static final ByteList Q_TRUE = new ByteList(new byte[] { '\'', 't', '\'' }, false);
61
-
62
- @JRubyMethod(name = "quoted_true", required = 0, frame = false)
63
- public static IRubyObject quoted_true(
64
- final ThreadContext context,
65
- final IRubyObject self) {
66
- return RubyString.newString(context.getRuntime(), Q_TRUE);
67
- }
68
-
69
- private static final ByteList Q_FALSE = new ByteList(new byte[] { '\'', 'f', '\'' }, false);
70
-
71
- @JRubyMethod(name = "quoted_false", required = 0, frame = false)
72
- public static IRubyObject quoted_false(
73
- final ThreadContext context,
74
- final IRubyObject self) {
75
- return RubyString.newString(context.getRuntime(), Q_FALSE);
76
- }
77
-
78
58
  }