8
8
import java .sql .*;
9
9
import java .text .DecimalFormat ;
10
10
import java .text .DecimalFormatSymbols ;
11
+ import java .time .DateTimeException ;
11
12
import java .time .LocalDateTime ;
12
13
import java .time .ZonedDateTime ;
13
14
import java .time .format .DateTimeFormatter ;
@@ -144,24 +145,30 @@ public String decodeStringText(
144
145
final Context context )
145
146
throws SQLDataException {
146
147
if (length .get () == 0 ) return buildZeroDate ();
148
+ int initialPos = buf .pos ();
147
149
int initialLength = length .get ();
148
- LocalDateTime ldt = parseText (buf , length );
149
- if (ldt == null ) {
150
- if (initialLength > 0 ) return buildZeroDate ();
151
- return null ;
152
- }
153
- LocalDateTime modifiedLdt =
154
- localDateTimeToZoneDateTime (ldt , providedCal , context ).toLocalDateTime ();
155
- String timestampWithoutMicro = dateTimeFormatter .format (modifiedLdt );
156
- if (context .getConf ().oldModeNoPrecisionTimestamp ()) {
157
- // for compatibility with 2.2.0 and before, micro precision use .0##### format
150
+ try {
151
+ LocalDateTime ldt = parseText (buf , length );
152
+ if (ldt == null ) {
153
+ if (initialLength > 0 ) return buildZeroDate ();
154
+ return null ;
155
+ }
156
+ LocalDateTime modifiedLdt =
157
+ localDateTimeToZoneDateTime (ldt , providedCal , context ).toLocalDateTime ();
158
+ String timestampWithoutMicro = dateTimeFormatter .format (modifiedLdt );
159
+ if (context .getConf ().oldModeNoPrecisionTimestamp ()) {
160
+ // for compatibility with 2.2.0 and before, micro precision use .0##### format
161
+ return timestampWithoutMicro
162
+ + oldDecimalFormat .format (((double ) modifiedLdt .getNano ()) / 1000000000 );
163
+ }
164
+ if (this .decimals == 0 ) return timestampWithoutMicro ;
158
165
return timestampWithoutMicro
159
- + oldDecimalFormat .format (((double ) modifiedLdt .getNano ()) / 1000000000 );
166
+ + "."
167
+ + String .format (Locale .US , "%0" + this .decimals + "d" , modifiedLdt .getNano () / 1000 );
168
+ } catch (DateTimeException e ) {
169
+ buf .pos (initialPos );
170
+ return buf .readString (length .get ());
160
171
}
161
- if (this .decimals == 0 ) return timestampWithoutMicro ;
162
- return timestampWithoutMicro
163
- + "."
164
- + String .format (Locale .US , "%0" + this .decimals + "d" , modifiedLdt .getNano () / 1000 );
165
172
}
166
173
167
174
private String buildZeroDate () {
@@ -181,24 +188,72 @@ public String decodeStringBinary(
181
188
final Context context )
182
189
throws SQLDataException {
183
190
if (length .get () == 0 ) return buildZeroDate ();
191
+ int initialPos = buf .pos ();
184
192
int initialLength = length .get ();
185
- LocalDateTime ldt = parseBinary (buf , length );
186
- if (ldt == null ) {
187
- if (initialLength > 0 ) return buildZeroDate ();
188
- return null ;
189
- }
190
- LocalDateTime modifiedLdt =
191
- localDateTimeToZoneDateTime (ldt , providedCal , context ).toLocalDateTime ();
192
- String timestampWithoutMicro = dateTimeFormatter .format (modifiedLdt );
193
- if (context .getConf ().oldModeNoPrecisionTimestamp ()) {
194
- // for compatibility with 2.2.0 and before, micro precision use .0##### format
193
+ try {
194
+ LocalDateTime ldt = parseBinary (buf , length );
195
+ if (ldt == null ) {
196
+ if (initialLength > 0 ) return buildZeroDate ();
197
+ return null ;
198
+ }
199
+ LocalDateTime modifiedLdt =
200
+ localDateTimeToZoneDateTime (ldt , providedCal , context ).toLocalDateTime ();
201
+ String timestampWithoutMicro = dateTimeFormatter .format (modifiedLdt );
202
+ if (context .getConf ().oldModeNoPrecisionTimestamp ()) {
203
+ // for compatibility with 2.2.0 and before, micro precision use .0##### format
204
+ return timestampWithoutMicro
205
+ + oldDecimalFormat .format (((double ) modifiedLdt .getNano ()) / 1000000000 );
206
+ }
207
+ if (this .decimals == 0 ) return timestampWithoutMicro ;
195
208
return timestampWithoutMicro
196
- + oldDecimalFormat .format (((double ) modifiedLdt .getNano ()) / 1000000000 );
209
+ + "."
210
+ + String .format (Locale .US , "%0" + this .decimals + "d" , modifiedLdt .getNano () / 1000 );
211
+ } catch (DateTimeException e ) {
212
+ buf .pos (initialPos );
213
+ int year = buf .readUnsignedShort ();
214
+ int month = buf .readByte ();
215
+ int dayOfMonth = buf .readByte ();
216
+ int hour = 0 ;
217
+ int minutes = 0 ;
218
+ int seconds = 0 ;
219
+ long microseconds = 0 ;
220
+
221
+ if (length .get () > 4 ) {
222
+ hour = buf .readByte ();
223
+ minutes = buf .readByte ();
224
+ seconds = buf .readByte ();
225
+
226
+ if (length .get () > 7 ) {
227
+ microseconds = buf .readUnsignedInt ();
228
+ }
229
+ }
230
+ StringBuilder sb = new StringBuilder ();
231
+ fill (year , 4 , sb );
232
+ sb .append ("-" );
233
+ fill (month , 2 , sb );
234
+ sb .append ("-" );
235
+ fill (dayOfMonth , 2 , sb );
236
+ sb .append (" " );
237
+ fill (hour , 2 , sb );
238
+ sb .append (":" );
239
+ fill (minutes , 2 , sb );
240
+ sb .append (":" );
241
+ fill (seconds , 2 , sb );
242
+
243
+ if (getDecimals () == 0 ) return sb .toString ();
244
+ sb .append ("." );
245
+ fill ((int ) (microseconds / Math .pow (10 , 6 - getDecimals ())), getDecimals (), sb );
246
+ return sb .toString ();
247
+ }
248
+ }
249
+
250
+ private void fill (int val , int size , StringBuilder sb ) {
251
+ String valSt = String .valueOf (val );
252
+ long zeroToAdd = size - valSt .length ();
253
+ while (zeroToAdd -- > 0 ) {
254
+ sb .append ("0" );
197
255
}
198
- if (this .decimals == 0 ) return timestampWithoutMicro ;
199
- return timestampWithoutMicro
200
- + "."
201
- + String .format (Locale .US , "%0" + this .decimals + "d" , modifiedLdt .getNano () / 1000 );
256
+ sb .append (valSt );
202
257
}
203
258
204
259
@ Override
@@ -320,22 +375,90 @@ public Time decodeTimeBinary(
320
375
public Timestamp decodeTimestampText (
321
376
final ReadableByteBuf buf , final MutableInt length , Calendar calParam , final Context context )
322
377
throws SQLDataException {
323
- LocalDateTime ldt = parseText (buf , length );
324
- if (ldt == null ) return null ;
325
- Timestamp res = new Timestamp (localDateTimeToInstant (ldt , calParam , context ));
326
- res .setNanos (ldt .getNano ());
327
- return res ;
378
+ int [] parts = LocalDateTimeCodec .parseTextTimestamp (buf , length );
379
+ if (LocalDateTimeCodec .isZeroTimestamp (parts )) {
380
+ length .set (NULL_LENGTH );
381
+ return null ;
382
+ }
383
+
384
+ try {
385
+ LocalDateTime ldt = LocalDateTime .of (parts [0 ], parts [1 ], parts [2 ], parts [3 ], parts [4 ], parts [5 ])
386
+ .plusNanos (parts [6 ]);
387
+ Timestamp res = new Timestamp (localDateTimeToInstant (ldt , calParam , context ));
388
+ res .setNanos (ldt .getNano ());
389
+ return res ;
390
+ } catch (DateTimeException e ) {
391
+ Timestamp timestamp ;
392
+ Calendar cal = calParam == null ? Calendar .getInstance () : calParam ;
393
+ synchronized (cal ) {
394
+ cal .setLenient (true );
395
+ cal .clear ();
396
+ cal .set (Calendar .YEAR , parts [0 ]);
397
+ cal .set (Calendar .MONTH , parts [1 ] - 1 );
398
+ cal .set (Calendar .DAY_OF_MONTH , parts [2 ]);
399
+ cal .set (Calendar .HOUR_OF_DAY , parts [3 ]);
400
+ cal .set (Calendar .MINUTE , parts [4 ]);
401
+ cal .set (Calendar .SECOND , parts [5 ]);
402
+ cal .set (Calendar .MILLISECOND , parts [6 ] / 1000000 );
403
+ timestamp = new Timestamp (cal .getTime ().getTime ());
404
+ }
405
+ timestamp .setNanos (parts [6 ]);
406
+ return timestamp ;
407
+ }
408
+
328
409
}
329
410
330
411
@ Override
331
412
public Timestamp decodeTimestampBinary (
332
413
final ReadableByteBuf buf , final MutableInt length , Calendar calParam , final Context context )
333
414
throws SQLDataException {
334
- LocalDateTime ldt = parseBinary (buf , length );
335
- if (ldt == null ) return null ;
336
- Timestamp res = new Timestamp (localDateTimeToInstant (ldt , calParam , context ));
337
- res .setNanos (ldt .getNano ());
338
- return res ;
415
+ if (length .get () == 0 ) {
416
+ length .set (NULL_LENGTH );
417
+ return null ;
418
+ }
419
+
420
+ int year = buf .readUnsignedShort ();
421
+ int month = buf .readByte ();
422
+ int dayOfMonth = buf .readByte ();
423
+ int hour = 0 ;
424
+ int minutes = 0 ;
425
+ int seconds = 0 ;
426
+ long microseconds = 0 ;
427
+
428
+ if (length .get () > 4 ) {
429
+ hour = buf .readByte ();
430
+ minutes = buf .readByte ();
431
+ seconds = buf .readByte ();
432
+
433
+ if (length .get () > 7 ) {
434
+ microseconds = buf .readUnsignedInt ();
435
+ }
436
+ }
437
+ try {
438
+ LocalDateTime ldt = LocalDateTime .of (year , month , dayOfMonth , hour , minutes , seconds )
439
+ .plusNanos (microseconds * 1000 );
440
+ if (ldt == null ) return null ;
441
+ Timestamp res = new Timestamp (localDateTimeToInstant (ldt , calParam , context ));
442
+ res .setNanos (ldt .getNano ());
443
+ return res ;
444
+ } catch (DateTimeException e ) {
445
+ Timestamp timestamp ;
446
+ Calendar cal = calParam == null ? Calendar .getInstance () : calParam ;
447
+ synchronized (cal ) {
448
+ cal .setLenient (true );
449
+ cal .clear ();
450
+ cal .set (Calendar .YEAR , year );
451
+ cal .set (Calendar .MONTH , month - 1 );
452
+ cal .set (Calendar .DAY_OF_MONTH , dayOfMonth );
453
+ cal .set (Calendar .HOUR_OF_DAY , hour );
454
+ cal .set (Calendar .MINUTE , minutes );
455
+ cal .set (Calendar .SECOND , seconds );
456
+ cal .set (Calendar .MILLISECOND , (int ) (microseconds / 1000000 ));
457
+ timestamp = new Timestamp (cal .getTime ().getTime ());
458
+ }
459
+ timestamp .setNanos ((int ) (microseconds * 1000 ));
460
+ return timestamp ;
461
+ }
339
462
}
340
463
341
464
private LocalDateTime parseText (final ReadableByteBuf buf , final MutableInt length ) {
@@ -371,18 +494,6 @@ private LocalDateTime parseBinary(final ReadableByteBuf buf, final MutableInt le
371
494
microseconds = buf .readUnsignedInt ();
372
495
}
373
496
}
374
-
375
- // xpand workaround https://jira.mariadb.org/browse/XPT-274
376
- if (year == 0
377
- && month == 0
378
- && dayOfMonth == 0
379
- && hour == 0
380
- && minutes == 0
381
- && seconds == 0
382
- && microseconds == 0 ) {
383
- length .set (NULL_LENGTH );
384
- return null ;
385
- }
386
497
return LocalDateTime .of (year , month , dayOfMonth , hour , minutes , seconds )
387
498
.plusNanos (microseconds * 1000 );
388
499
}
0 commit comments