1
1
package org .tarantool .jdbc ;
2
2
3
+ import org .tarantool .CommunicationException ;
4
+ import org .tarantool .JDBCBridge ;
5
+ import org .tarantool .TarantoolConnection ;
6
+ import org .tarantool .util .SQLStates ;
7
+
3
8
import java .io .IOException ;
4
9
import java .net .InetSocketAddress ;
5
10
import java .net .Socket ;
16
21
import java .sql .SQLClientInfoException ;
17
22
import java .sql .SQLException ;
18
23
import java .sql .SQLFeatureNotSupportedException ;
24
+ import java .sql .SQLNonTransientConnectionException ;
25
+ import java .sql .SQLNonTransientException ;
19
26
import java .sql .SQLWarning ;
20
27
import java .sql .SQLXML ;
21
28
import java .sql .Savepoint ;
27
34
import java .util .Properties ;
28
35
import java .util .concurrent .Executor ;
29
36
30
- import org .tarantool .CommunicationException ;
31
- import org .tarantool .JDBCBridge ;
32
- import org .tarantool .TarantoolConnection ;
33
-
34
37
import static org .tarantool .jdbc .SQLDriver .PROP_HOST ;
35
38
import static org .tarantool .jdbc .SQLDriver .PROP_PASSWORD ;
36
39
import static org .tarantool .jdbc .SQLDriver .PROP_PORT ;
39
42
40
43
@ SuppressWarnings ("Since15" )
41
44
public class SQLConnection implements Connection {
45
+
46
+ private static final int UNSET_HOLDABILITY = 0 ;
47
+
42
48
private final TarantoolConnection connection ;
43
- final String url ;
44
- final Properties properties ;
49
+
50
+ private final String url ;
51
+ private final Properties properties ;
52
+
53
+ private DatabaseMetaData cachedMetadata ;
54
+
55
+ private int resultSetHoldability = UNSET_HOLDABILITY ;
45
56
46
57
SQLConnection (String url , Properties properties ) throws SQLException {
47
58
this .url = url ;
@@ -62,20 +73,20 @@ public class SQLConnection implements Connection {
62
73
}
63
74
}
64
75
if (e instanceof SQLException )
65
- throw (SQLException )e ;
76
+ throw (SQLException ) e ;
66
77
throw new SQLException ("Couldn't initiate connection using " + SQLDriver .diagProperties (properties ), e );
67
78
}
68
79
}
69
80
70
81
/**
71
82
* Provides a connected socket to be used to initialize a native tarantool
72
83
* connection.
73
- *
84
+ * <p>
74
85
* The implementation assumes that {@link #properties} contains all the
75
86
* necessary info extracted from both the URI and connection properties
76
87
* provided by the user. However, the overrides are free to also use the
77
88
* {@link #url} if required.
78
- *
89
+ * <p>
79
90
* A connect is guarded with user provided timeout. Socket is configured
80
91
* to honor this timeout for the following read/write operations as well.
81
92
*
@@ -111,7 +122,7 @@ protected Socket getConnectedSocket() throws SQLException {
111
122
/**
112
123
* Provides a newly connected socket instance. The method is intended to be
113
124
* overridden to enable unit testing of the class.
114
- *
125
+ * <p>
115
126
* Not supposed to contain any logic other than a call to constructor.
116
127
*
117
128
* @return socket.
@@ -123,11 +134,11 @@ protected Socket makeSocket() {
123
134
/**
124
135
* Provides a native tarantool connection instance. The method is intended
125
136
* to be overridden to enable unit testing of the class.
126
- *
137
+ * <p>
127
138
* Not supposed to contain any logic other than a call to constructor.
128
139
*
129
- * @param user User name.
130
- * @param pass Password.
140
+ * @param user User name.
141
+ * @param pass Password.
131
142
* @param socket Connected socket.
132
143
* @return Native tarantool connection.
133
144
* @throws IOException if failed.
@@ -140,14 +151,12 @@ protected TarantoolConnection makeConnection(String user, String pass, Socket so
140
151
141
152
@ Override
142
153
public Statement createStatement () throws SQLException {
143
- checkNotClosed ();
144
- return new SQLStatement (this );
154
+ return createStatement (ResultSet .TYPE_FORWARD_ONLY , ResultSet .CONCUR_READ_ONLY );
145
155
}
146
156
147
157
@ Override
148
158
public PreparedStatement prepareStatement (String sql ) throws SQLException {
149
- checkNotClosed ();
150
- return new SQLPreparedStatement (this , sql );
159
+ return prepareStatement (sql , ResultSet .TYPE_FORWARD_ONLY , ResultSet .CONCUR_READ_ONLY );
151
160
}
152
161
153
162
@ Override
@@ -196,7 +205,10 @@ public boolean isClosed() throws SQLException {
196
205
@ Override
197
206
public DatabaseMetaData getMetaData () throws SQLException {
198
207
checkNotClosed ();
199
- return new SQLDatabaseMetadata (this );
208
+ if (cachedMetadata == null ) {
209
+ cachedMetadata = new SQLDatabaseMetadata (this );
210
+ }
211
+ return cachedMetadata ;
200
212
}
201
213
202
214
@ Override
@@ -242,13 +254,13 @@ public void clearWarnings() throws SQLException {
242
254
243
255
@ Override
244
256
public Statement createStatement (int resultSetType , int resultSetConcurrency ) throws SQLException {
245
- throw new SQLFeatureNotSupportedException ( );
257
+ return createStatement ( resultSetType , resultSetConcurrency , getHoldability () );
246
258
}
247
259
248
260
@ Override
249
261
public PreparedStatement prepareStatement (String sql , int resultSetType , int resultSetConcurrency )
250
262
throws SQLException {
251
- throw new SQLFeatureNotSupportedException ( );
263
+ return prepareStatement ( sql , resultSetType , resultSetConcurrency , getHoldability () );
252
264
}
253
265
254
266
@ Override
@@ -268,12 +280,18 @@ public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
268
280
269
281
@ Override
270
282
public void setHoldability (int holdability ) throws SQLException {
271
- throw new SQLFeatureNotSupportedException ();
283
+ checkNotClosed ();
284
+ checkHoldabilitySupport (holdability );
285
+ resultSetHoldability = holdability ;
272
286
}
273
287
274
288
@ Override
275
289
public int getHoldability () throws SQLException {
276
- throw new SQLFeatureNotSupportedException ();
290
+ checkNotClosed ();
291
+ if (resultSetHoldability == UNSET_HOLDABILITY ) {
292
+ resultSetHoldability = getMetaData ().getResultSetHoldability ();
293
+ }
294
+ return resultSetHoldability ;
277
295
}
278
296
279
297
@ Override
@@ -297,15 +315,22 @@ public void releaseSavepoint(Savepoint savepoint) throws SQLException {
297
315
}
298
316
299
317
@ Override
300
- public Statement createStatement (int resultSetType , int resultSetConcurrency , int resultSetHoldability )
301
- throws SQLException {
302
- throw new SQLFeatureNotSupportedException ();
318
+ public Statement createStatement (int resultSetType ,
319
+ int resultSetConcurrency ,
320
+ int resultSetHoldability ) throws SQLException {
321
+ checkNotClosed ();
322
+ checkHoldabilitySupport (resultSetHoldability );
323
+ return new SQLStatement (this , resultSetType , resultSetConcurrency , resultSetHoldability );
303
324
}
304
325
305
326
@ Override
306
- public PreparedStatement prepareStatement (String sql , int resultSetType , int resultSetConcurrency , int resultSetHoldability )
307
- throws SQLException {
308
- throw new SQLFeatureNotSupportedException ();
327
+ public PreparedStatement prepareStatement (String sql ,
328
+ int resultSetType ,
329
+ int resultSetConcurrency ,
330
+ int resultSetHoldability ) throws SQLException {
331
+ checkNotClosed ();
332
+ checkHoldabilitySupport (resultSetHoldability );
333
+ return new SQLPreparedStatement (this , sql , resultSetType , resultSetConcurrency , resultSetHoldability );
309
334
}
310
335
311
336
@ Override
@@ -423,16 +448,19 @@ public int getNetworkTimeout() throws SQLException {
423
448
}
424
449
425
450
@ Override
426
- public <T > T unwrap (Class <T > iface ) throws SQLException {
427
- throw new SQLFeatureNotSupportedException ();
451
+ public <T > T unwrap (Class <T > type ) throws SQLException {
452
+ if (isWrapperFor (type )) {
453
+ return type .cast (this );
454
+ }
455
+ throw new SQLNonTransientException ("Connection does not wrap " + type .getName ());
428
456
}
429
457
430
458
@ Override
431
- public boolean isWrapperFor (Class <?> iface ) throws SQLException {
432
- throw new SQLFeatureNotSupportedException ( );
459
+ public boolean isWrapperFor (Class <?> type ) throws SQLException {
460
+ return type . isAssignableFrom ( this . getClass () );
433
461
}
434
462
435
- protected Object execute (String sql , Object ... args ) throws SQLException {
463
+ protected Object execute (String sql , Object ... args ) throws SQLException {
436
464
checkNotClosed ();
437
465
try {
438
466
return JDBCBridge .execute (connection , sql , args );
@@ -442,17 +470,17 @@ protected Object execute(String sql, Object ... args) throws SQLException {
442
470
}
443
471
}
444
472
445
- protected ResultSet executeQuery (String sql , Object ... args ) throws SQLException {
473
+ protected JDBCBridge executeQuery (String sql , Object ... args ) throws SQLException {
446
474
checkNotClosed ();
447
475
try {
448
- return new SQLResultSet ( JDBCBridge .query (connection , sql , args ) );
476
+ return JDBCBridge .query (connection , sql , args );
449
477
} catch (Exception e ) {
450
478
handleException (e );
451
479
throw new SQLException (formatError (sql , args ), e );
452
480
}
453
481
}
454
482
455
- protected int executeUpdate (String sql , Object ... args ) throws SQLException {
483
+ protected int executeUpdate (String sql , Object ... args ) throws SQLException {
456
484
checkNotClosed ();
457
485
try {
458
486
return JDBCBridge .update (connection , sql , args );
@@ -463,7 +491,7 @@ protected int executeUpdate(String sql, Object ... args) throws SQLException {
463
491
}
464
492
465
493
protected List <?> nativeSelect (Integer space , Integer index , List <?> key , int offset , int limit , int iterator )
466
- throws SQLException {
494
+ throws SQLException {
467
495
checkNotClosed ();
468
496
try {
469
497
return connection .select (space , index , key , offset , limit , iterator );
@@ -482,7 +510,18 @@ protected String getServerVersion() {
482
510
*/
483
511
protected void checkNotClosed () throws SQLException {
484
512
if (isClosed ())
485
- throw new SQLException ("Connection is closed." );
513
+ throw new SQLNonTransientConnectionException (
514
+ "Connection is closed." ,
515
+ SQLStates .CONNECTION_DOES_NOT_EXIST .getSqlState ()
516
+ );
517
+ }
518
+
519
+ String getUrl () {
520
+ return url ;
521
+ }
522
+
523
+ Properties getProperties () {
524
+ return properties ;
486
525
}
487
526
488
527
/**
@@ -492,7 +531,7 @@ protected void checkNotClosed() throws SQLException {
492
531
*/
493
532
private void handleException (Exception e ) {
494
533
if (CommunicationException .class .isAssignableFrom (e .getClass ()) ||
495
- IOException .class .isAssignableFrom (e .getClass ())) {
534
+ IOException .class .isAssignableFrom (e .getClass ())) {
496
535
try {
497
536
close ();
498
537
} catch (SQLException ignored ) {
@@ -501,14 +540,31 @@ private void handleException(Exception e) {
501
540
}
502
541
}
503
542
543
+ /**
544
+ * Checks whether <code>holdability</code> is supported
545
+ *
546
+ * @param holdability param to be checked
547
+ * @throws SQLFeatureNotSupportedException param is not supported
548
+ * @throws SQLNonTransientException param has invalid value
549
+ */
550
+ private void checkHoldabilitySupport (int holdability ) throws SQLException {
551
+ if (holdability != ResultSet .CLOSE_CURSORS_AT_COMMIT
552
+ && holdability != ResultSet .HOLD_CURSORS_OVER_COMMIT ) {
553
+ throw new SQLNonTransientException ("" , SQLStates .INVALID_PARAMETER_VALUE .getSqlState ());
554
+ }
555
+ if (!getMetaData ().supportsResultSetHoldability (holdability )) {
556
+ throw new SQLFeatureNotSupportedException ();
557
+ }
558
+ }
559
+
504
560
/**
505
561
* Provides error message that contains parameters of failed SQL statement.
506
562
*
507
- * @param sql SQL Text.
563
+ * @param sql SQL Text.
508
564
* @param params Parameters of the SQL statement.
509
565
* @return Formatted error message.
510
566
*/
511
- private static String formatError (String sql , Object ... params ) {
567
+ private static String formatError (String sql , Object ... params ) {
512
568
return "Failed to execute SQL: " + sql + ", params: " + Arrays .deepToString (params );
513
569
}
514
570
}
0 commit comments