5
5
*/
6
6
package org .elasticsearch .xpack .sql .jdbc .jdbc ;
7
7
8
+ import org .elasticsearch .xpack .sql .type .DataType ;
9
+
8
10
import java .io .InputStream ;
9
11
import java .io .Reader ;
10
12
import java .math .BigDecimal ;
21
23
import java .sql .ResultSet ;
22
24
import java .sql .ResultSetMetaData ;
23
25
import java .sql .RowId ;
26
+ import java .sql .SQLDataException ;
24
27
import java .sql .SQLException ;
25
28
import java .sql .SQLFeatureNotSupportedException ;
26
29
import java .sql .SQLXML ;
30
+ import java .sql .Struct ;
27
31
import java .sql .Time ;
28
32
import java .sql .Timestamp ;
29
33
import java .sql .Types ;
34
+ import java .time .LocalDate ;
35
+ import java .time .LocalDateTime ;
36
+ import java .time .LocalTime ;
37
+ import java .time .OffsetDateTime ;
38
+ import java .time .OffsetTime ;
39
+ import java .util .ArrayList ;
40
+ import java .util .Arrays ;
30
41
import java .util .Calendar ;
42
+ import java .util .List ;
43
+ import java .util .Locale ;
31
44
32
45
class JdbcPreparedStatement extends JdbcStatement implements PreparedStatement {
33
46
final PreparedQuery query ;
@@ -74,67 +87,67 @@ public void setNull(int parameterIndex, int sqlType) throws SQLException {
74
87
75
88
@ Override
76
89
public void setBoolean (int parameterIndex , boolean x ) throws SQLException {
77
- setParam (parameterIndex , x , Types .BOOLEAN );
90
+ setObject (parameterIndex , x , Types .BOOLEAN );
78
91
}
79
92
80
93
@ Override
81
94
public void setByte (int parameterIndex , byte x ) throws SQLException {
82
- setParam (parameterIndex , x , Types .TINYINT );
95
+ setObject (parameterIndex , x , Types .TINYINT );
83
96
}
84
97
85
98
@ Override
86
99
public void setShort (int parameterIndex , short x ) throws SQLException {
87
- setParam (parameterIndex , x , Types .SMALLINT );
100
+ setObject (parameterIndex , x , Types .SMALLINT );
88
101
}
89
102
90
103
@ Override
91
104
public void setInt (int parameterIndex , int x ) throws SQLException {
92
- setParam (parameterIndex , x , Types .INTEGER );
105
+ setObject (parameterIndex , x , Types .INTEGER );
93
106
}
94
107
95
108
@ Override
96
109
public void setLong (int parameterIndex , long x ) throws SQLException {
97
- setParam (parameterIndex , x , Types .BIGINT );
110
+ setObject (parameterIndex , x , Types .BIGINT );
98
111
}
99
112
100
113
@ Override
101
114
public void setFloat (int parameterIndex , float x ) throws SQLException {
102
- setParam (parameterIndex , x , Types .REAL );
115
+ setObject (parameterIndex , x , Types .REAL );
103
116
}
104
117
105
118
@ Override
106
119
public void setDouble (int parameterIndex , double x ) throws SQLException {
107
- setParam (parameterIndex , x , Types .DOUBLE );
120
+ setObject (parameterIndex , x , Types .DOUBLE );
108
121
}
109
122
110
123
@ Override
111
124
public void setBigDecimal (int parameterIndex , BigDecimal x ) throws SQLException {
112
- throw new SQLFeatureNotSupportedException ( "BigDecimal not supported" );
125
+ setObject ( parameterIndex , x , Types . BIGINT );
113
126
}
114
127
115
128
@ Override
116
129
public void setString (int parameterIndex , String x ) throws SQLException {
117
- setParam (parameterIndex , x , Types .VARCHAR );
130
+ setObject (parameterIndex , x , Types .VARCHAR );
118
131
}
119
132
120
133
@ Override
121
134
public void setBytes (int parameterIndex , byte [] x ) throws SQLException {
122
- throw new UnsupportedOperationException ( "Bytes not implemented yet" );
135
+ setObject ( parameterIndex , x , Types . VARBINARY );
123
136
}
124
137
125
138
@ Override
126
139
public void setDate (int parameterIndex , Date x ) throws SQLException {
127
- throw new UnsupportedOperationException ( "Date/Time not implemented yet" );
140
+ setObject ( parameterIndex , x , Types . TIMESTAMP );
128
141
}
129
142
130
143
@ Override
131
144
public void setTime (int parameterIndex , Time x ) throws SQLException {
132
- throw new UnsupportedOperationException ( "Date/Time not implemented yet" );
145
+ setObject ( parameterIndex , x , Types . TIMESTAMP );
133
146
}
134
147
135
148
@ Override
136
149
public void setTimestamp (int parameterIndex , Timestamp x ) throws SQLException {
137
- throw new UnsupportedOperationException ( "Date/Time not implemented yet" );
150
+ setObject ( parameterIndex , x , Types . TIMESTAMP );
138
151
}
139
152
140
153
@ Override
@@ -161,12 +174,22 @@ public void clearParameters() throws SQLException {
161
174
162
175
@ Override
163
176
public void setObject (int parameterIndex , Object x , int targetSqlType ) throws SQLException {
164
- throw new UnsupportedOperationException ("Object not implemented yet" );
177
+ // the value of scaleOrLength parameter doesn't matter, as it's not used in the called method below
178
+ setObject (parameterIndex , x , targetSqlType , 0 );
165
179
}
166
180
167
181
@ Override
168
182
public void setObject (int parameterIndex , Object x ) throws SQLException {
169
- throw new SQLFeatureNotSupportedException ("CharacterStream not supported" );
183
+ if (x == null ) {
184
+ setParam (parameterIndex , null , Types .NULL );
185
+ return ;
186
+ }
187
+
188
+ // check also here the unsupported types so that any unsupported interfaces ({@code java.sql.Struct},
189
+ // {@code java.sql.Array} etc) will generate the correct exception message. Otherwise, the method call
190
+ // {@code TypeConverter.fromJavaToJDBC(x.getClass())} will report the implementing class as not being supported.
191
+ checkKnownUnsupportedTypes (x );
192
+ setObject (parameterIndex , x , TypeConverter .fromJavaToJDBC (x .getClass ()).getVendorTypeNumber (), 0 );
170
193
}
171
194
172
195
@ Override
@@ -181,22 +204,22 @@ public void setCharacterStream(int parameterIndex, Reader reader, int length) th
181
204
182
205
@ Override
183
206
public void setRef (int parameterIndex , Ref x ) throws SQLException {
184
- throw new SQLFeatureNotSupportedException ( "Ref not supported" );
207
+ setObject ( parameterIndex , x );
185
208
}
186
209
187
210
@ Override
188
211
public void setBlob (int parameterIndex , Blob x ) throws SQLException {
189
- throw new SQLFeatureNotSupportedException ( "Blob not supported" );
212
+ setObject ( parameterIndex , x );
190
213
}
191
214
192
215
@ Override
193
216
public void setClob (int parameterIndex , Clob x ) throws SQLException {
194
- throw new SQLFeatureNotSupportedException ( "Clob not supported" );
217
+ setObject ( parameterIndex , x );
195
218
}
196
219
197
220
@ Override
198
221
public void setArray (int parameterIndex , Array x ) throws SQLException {
199
- throw new SQLFeatureNotSupportedException ( "Array not supported" );
222
+ setObject ( parameterIndex , x );
200
223
}
201
224
202
225
@ Override
@@ -206,17 +229,44 @@ public ResultSetMetaData getMetaData() throws SQLException {
206
229
207
230
@ Override
208
231
public void setDate (int parameterIndex , Date x , Calendar cal ) throws SQLException {
209
- throw new UnsupportedOperationException ("Dates not implemented yet" );
232
+ if (cal == null ) {
233
+ setObject (parameterIndex , x , Types .TIMESTAMP );
234
+ return ;
235
+ }
236
+ if (x == null ) {
237
+ setNull (parameterIndex , Types .TIMESTAMP );
238
+ return ;
239
+ }
240
+ // converting to UTC since this is what ES is storing internally
241
+ setObject (parameterIndex , new Date (TypeConverter .convertFromCalendarToUTC (x .getTime (), cal )), Types .TIMESTAMP );
210
242
}
211
243
212
244
@ Override
213
245
public void setTime (int parameterIndex , Time x , Calendar cal ) throws SQLException {
214
- throw new UnsupportedOperationException ("Dates not implemented yet" );
246
+ if (cal == null ) {
247
+ setObject (parameterIndex , x , Types .TIMESTAMP );
248
+ return ;
249
+ }
250
+ if (x == null ) {
251
+ setNull (parameterIndex , Types .TIMESTAMP );
252
+ return ;
253
+ }
254
+ // converting to UTC since this is what ES is storing internally
255
+ setObject (parameterIndex , new Time (TypeConverter .convertFromCalendarToUTC (x .getTime (), cal )), Types .TIMESTAMP );
215
256
}
216
257
217
258
@ Override
218
259
public void setTimestamp (int parameterIndex , Timestamp x , Calendar cal ) throws SQLException {
219
- throw new UnsupportedOperationException ("Dates not implemented yet" );
260
+ if (cal == null ) {
261
+ setObject (parameterIndex , x , Types .TIMESTAMP );
262
+ return ;
263
+ }
264
+ if (x == null ) {
265
+ setNull (parameterIndex , Types .TIMESTAMP );
266
+ return ;
267
+ }
268
+ // converting to UTC since this is what ES is storing internally
269
+ setObject (parameterIndex , new Timestamp (TypeConverter .convertFromCalendarToUTC (x .getTime (), cal )), Types .TIMESTAMP );
220
270
}
221
271
222
272
@ Override
@@ -226,7 +276,7 @@ public void setNull(int parameterIndex, int sqlType, String typeName) throws SQL
226
276
227
277
@ Override
228
278
public void setURL (int parameterIndex , URL x ) throws SQLException {
229
- throw new SQLFeatureNotSupportedException ( "Datalink not supported" );
279
+ setObject ( parameterIndex , x );
230
280
}
231
281
232
282
@ Override
@@ -236,7 +286,7 @@ public ParameterMetaData getParameterMetaData() throws SQLException {
236
286
237
287
@ Override
238
288
public void setRowId (int parameterIndex , RowId x ) throws SQLException {
239
- throw new SQLFeatureNotSupportedException ( "RowId not supported" );
289
+ setObject ( parameterIndex , x );
240
290
}
241
291
242
292
@ Override
@@ -251,7 +301,7 @@ public void setNCharacterStream(int parameterIndex, Reader value, long length) t
251
301
252
302
@ Override
253
303
public void setNClob (int parameterIndex , NClob value ) throws SQLException {
254
- throw new SQLFeatureNotSupportedException ( "NClob not supported" );
304
+ setObject ( parameterIndex , value );
255
305
}
256
306
257
307
@ Override
@@ -271,12 +321,108 @@ public void setNClob(int parameterIndex, Reader reader, long length) throws SQLE
271
321
272
322
@ Override
273
323
public void setSQLXML (int parameterIndex , SQLXML xmlObject ) throws SQLException {
274
- throw new SQLFeatureNotSupportedException ( "SQLXML not supported" );
324
+ setObject ( parameterIndex , xmlObject );
275
325
}
276
-
326
+
277
327
@ Override
278
328
public void setObject (int parameterIndex , Object x , int targetSqlType , int scaleOrLength ) throws SQLException {
279
- throw new UnsupportedOperationException ("Object not implemented yet" );
329
+ checkOpen ();
330
+
331
+ JDBCType targetJDBCType ;
332
+ try {
333
+ // this is also a way to check early for the validity of the desired sql type
334
+ targetJDBCType = JDBCType .valueOf (targetSqlType );
335
+ } catch (IllegalArgumentException e ) {
336
+ throw new SQLDataException (e .getMessage ());
337
+ }
338
+
339
+ // set the null value on the type and exit
340
+ if (x == null ) {
341
+ setParam (parameterIndex , null , targetSqlType );
342
+ return ;
343
+ }
344
+
345
+ checkKnownUnsupportedTypes (x );
346
+ if (x instanceof byte []) {
347
+ if (targetJDBCType != JDBCType .VARBINARY ) {
348
+ throw new SQLFeatureNotSupportedException (
349
+ "Conversion from type byte[] to " + targetJDBCType + " not supported" );
350
+ }
351
+ setParam (parameterIndex , x , Types .VARBINARY );
352
+ return ;
353
+ }
354
+
355
+ if (x instanceof Timestamp
356
+ || x instanceof Calendar
357
+ || x instanceof Date
358
+ || x instanceof LocalDateTime
359
+ || x instanceof Time
360
+ || x instanceof java .util .Date )
361
+ {
362
+ if (targetJDBCType == JDBCType .TIMESTAMP ) {
363
+ // converting to {@code java.util.Date} because this is the type supported by {@code XContentBuilder} for serialization
364
+ java .util .Date dateToSet ;
365
+ if (x instanceof Timestamp ) {
366
+ dateToSet = new java .util .Date (((Timestamp ) x ).getTime ());
367
+ } else if (x instanceof Calendar ) {
368
+ dateToSet = ((Calendar ) x ).getTime ();
369
+ } else if (x instanceof Date ) {
370
+ dateToSet = new java .util .Date (((Date ) x ).getTime ());
371
+ } else if (x instanceof LocalDateTime ){
372
+ LocalDateTime ldt = (LocalDateTime ) x ;
373
+ Calendar cal = getDefaultCalendar ();
374
+ cal .set (ldt .getYear (), ldt .getMonthValue () - 1 , ldt .getDayOfMonth (), ldt .getHour (), ldt .getMinute (), ldt .getSecond ());
375
+
376
+ dateToSet = cal .getTime ();
377
+ } else if (x instanceof Time ) {
378
+ dateToSet = new java .util .Date (((Time ) x ).getTime ());
379
+ } else {
380
+ dateToSet = (java .util .Date ) x ;
381
+ }
382
+
383
+ setParam (parameterIndex , dateToSet , Types .TIMESTAMP );
384
+ return ;
385
+ } else if (targetJDBCType == JDBCType .VARCHAR ) {
386
+ setParam (parameterIndex , String .valueOf (x ), Types .VARCHAR );
387
+ return ;
388
+ }
389
+ // anything else other than VARCHAR and TIMESTAMP is not supported in this JDBC driver
390
+ throw new SQLFeatureNotSupportedException (
391
+ "Conversion from type " + x .getClass ().getName () + " to " + targetJDBCType + " not supported" );
392
+ }
393
+
394
+ if (x instanceof Boolean
395
+ || x instanceof Byte
396
+ || x instanceof Short
397
+ || x instanceof Integer
398
+ || x instanceof Long
399
+ || x instanceof Float
400
+ || x instanceof Double
401
+ || x instanceof String ) {
402
+ setParam (parameterIndex ,
403
+ TypeConverter .convert (x , TypeConverter .fromJavaToJDBC (x .getClass ()), DataType .fromJdbcTypeToJava (targetJDBCType )),
404
+ targetSqlType );
405
+ return ;
406
+ }
407
+
408
+ throw new SQLFeatureNotSupportedException (
409
+ "Conversion from type " + x .getClass ().getName () + " to " + targetJDBCType + " not supported" );
410
+ }
411
+
412
+ private void checkKnownUnsupportedTypes (Object x ) throws SQLFeatureNotSupportedException {
413
+ List <Class <?>> unsupportedTypes = new ArrayList <Class <?>>(Arrays .asList (Struct .class , Array .class , SQLXML .class ,
414
+ RowId .class , Ref .class , Blob .class , NClob .class , Clob .class , LocalDate .class , LocalTime .class ,
415
+ OffsetTime .class , OffsetDateTime .class , URL .class , BigDecimal .class ));
416
+
417
+ for (Class <?> clazz :unsupportedTypes ) {
418
+ if (clazz .isAssignableFrom (x .getClass ())) {
419
+ throw new SQLFeatureNotSupportedException ("Objects of type " + clazz .getName () + " are not supported" );
420
+ }
421
+ }
422
+ }
423
+
424
+ private Calendar getDefaultCalendar () {
425
+ return Calendar .getInstance (cfg .timeZone (), Locale .ROOT );
280
426
}
281
427
282
428
@ Override
0 commit comments